/* @generated-fonts:start - written by tools/font-subset.py; do not edit by hand.
 *
 * Three faces, all subsets. 'Noto' is split in two by unicode-range so a page
 * that draws no kanji never fetches the CJK slice; the Latin slice is
 * font-display: optional because it only dresses chips and rank grades, and a
 * late swap there is a reflow nobody asked for. The CJK slice stays swap: the
 * piece characters must end up in this face, and a system fallback is only a
 * placeholder until they do. Anything outside both ranges - user-typed kanji -
 * falls through the --font-kanji stack to the device's own CJK font. */
@font-face {
    font-family: 'Junge';
    src: url('/fonts/junge.woff2') format('woff2'), url('/fonts/junge.woff') format('woff');
    font-display: swap;
    unicode-range: U+0020-007E, U+00A0-00FF, U+2000-206F, U+21B6, U+25B2-25B3, U+25B6, U+25C0, U+2715;
}
@font-face {
    font-family: 'Noto';
    src: url('/fonts/noto-latin.woff2') format('woff2'), url('/fonts/noto-latin.woff') format('woff');
    font-display: optional;
    unicode-range: U+0020-007E, U+00A0-00FF, U+2000-206F, U+21B6, U+25B2-25B3, U+25B6, U+25C0, U+2715;
}
@font-face {
    font-family: 'Noto';
    src: url('/fonts/noto-cjk.woff2') format('woff2'), url('/fonts/noto-cjk.woff') format('woff');
    font-display: swap;
    unicode-range: U+3001-3002, U+3007, U+3042, U+3044, U+3046, U+3048, U+304A-304F, U+3051, U+3053-305D, U+305F-3061, U+3063-3064, U+3066-306B, U+306E-3070, U+3072, U+3075-3076, U+3078-3079, U+307E-307F, U+3082-3083, U+3087-308D, U+3092-3093, U+30A2, U+30A7, U+30AF, U+30B2-30B4, U+30B9, U+30C1, U+30CB, U+30CE, U+30D4, U+30D9, U+30DE, U+30E0-30E1, U+30EA-30EB, U+30F3, U+30FB-30FC, U+4E00, U+4E03, U+4E09-4E0B, U+4E0D, U+4E2D, U+4E5D, U+4E86, U+4E8B-4E8C, U+4E94, U+4EBA, U+4ED6, U+4EFB, U+4F4D, U+5009, U+50CD, U+5148, U+5165, U+5168, U+516B, U+516D, U+5175, U+5206-5207, U+521D, U+5247, U+5272, U+5275, U+52D5, U+52DD, U+5316, U+5341, U+5343, U+53BB, U+53C2, U+53CB, U+53CD, U+53D6, U+5408, U+540C-540D, U+5411, U+56DB, U+56F2-56F3, U+56FA, U+572D, U+57CE, U+5834, U+5897, U+5909, U+591C, U+5927, U+597D, U+5B57, U+5B66, U+5B87, U+5B89, U+5B8C, U+5B99-5B9A, U+5BFE, U+5C01, U+5C06, U+5C40, U+5C45, U+5E73-5E74, U+5F15, U+5F62, U+5F85, U+5F8C, U+5FC3, U+611A, U+6210, U+6226, U+6240, U+624B, U+6253, U+6280, U+6295, U+62BC, U+6301, U+6307, U+6311, U+632F, U+633F, U+6557, U+6570, U+6587, U+65AD, U+65B0, U+65E5, U+6642, U+66F4, U+6708, U+674F, U+6821, U+6842, U+68CB, U+6975, U+6A5F, U+6B20, U+6B66, U+6B69, U+6BB5, U+6D88, U+6E08, U+6F2B, U+6F84, U+6FC3, U+7121, U+7247, U+72D9, U+7384, U+7389, U+738B, U+751F, U+7531, U+753B, U+756A, U+75BE, U+75F4, U+767E, U+7686, U+76E4, U+77E2, U+7881, U+7985, U+79D1, U+7A3D, U+7A76, U+7ADC, U+7B46, U+7B4B, U+7B54, U+7D1A, U+7D42, U+7D9A, U+7F8E, U+8056, U+81EA, U+884C, U+8853, U+8987, U+89D2, U+89E3, U+8A13, U+8A18, U+8A70-8A71, U+8AAD, U+8AD6, U+8B5C, U+8CA0, U+8CBC, U+8DE1, U+8ECA, U+9003, U+9031, U+9053, U+9078, U+91D1, U+9280, U+932C, U+935B, U+9593, U+9759, U+9762, U+9858, U+98DB, U+9999, U+99AC, U+99D2, U+9F8D, U+FF10-FF1A, U+FF1F, U+FF56;
}
/* @generated-fonts:end */

/* --- Design tokens ---------------------------------------------------
 * Light values live on :root, dark swaps them on html.dark-mode (the theme
 * toggle sets that class on <html> and <body>). Dark is the default: the
 * inline script in head.ejs only *removes* it when the reader picked light. */
:root,
.theme-swatch[data-theme="light"] {
    --font-ui: 'Google Sans', 'Google Sans Text', Roboto, 'Noto Sans',
               system-ui, -apple-system, 'Segoe UI', 'Helvetica Neue', Arial,
               sans-serif;
    --font-kanji: 'Noto', 'Yu Mincho', 'Hiragino Mincho ProN', 'Noto Serif JP', serif;
    --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
                 'Liberation Mono', monospace;

    /* Material surfaces + Google blue. */
    --c-page: #f0f4f9;
    --c-box: #ffffff;
    --c-box-alt: #f1f3f4;
    --c-border: #dadce0;
    --c-border-soft: rgba(0, 0, 0, 0.07);
    --c-font: #444746;
    --c-font-strong: #1f1f1f;
    --c-font-dim: #5f6368;
    /* The logo grey. Sampled from logo.png, where #272424 is 86% of the
       opaque pixels and #ffffff the rest. */
    --c-accent: #272424;
    --c-accent-hover: #3d3939;
    --c-accent-soft: #e6e3e3;
    --c-accent-on-soft: #272424;
    --c-on-accent: #ffffff;
    --c-hover: rgba(39, 36, 36, 0.07);
    --c-good: #188038;
    --c-bad: #d93025;
    /* The board keeps its own warm surface in both themes. */
    --c-board: #e8c88f;

    /* Category + difficulty tones. */
    --tone-pieces-bg: #e3e9fb;   --tone-pieces-fg: #1a3a8f;
    --tone-castles-bg: #dff2e3;  --tone-castles-fg: #14612f;
    --tone-openings-bg: #fbeeda; --tone-openings-fg: #8a5300;
    --tone-culture-bg: #f0e6f7;  --tone-culture-fg: #5b2a80;

    /* Badge families. One hue each, close in lightness to the category tones
       above so badges sit in the same palette the rest of the site chips
       things with. */
    --badge-course-bg: #dbe7fb;  --badge-course-fg: #14418f;
    --badge-time-bg: #f6e4c9;    --badge-time-fg: #7a4a05;
    --badge-play-bg: #d8f0de;    --badge-play-fg: #10592b;
    --badge-streak-bg: #fbdcd8;  --badge-streak-fg: #8c2016;
    /* Magenta: the one gap left between the streak red and the wiki purple,
       and far enough from both that a row of coins still separates. */
    --badge-tsume-bg: #f7d9ec;   --badge-tsume-fg: #8c1f66;
    --badge-wiki-bg: #ece0f7;    --badge-wiki-fg: #55257d;
    --badge-social-bg: #d7eef2;  --badge-social-fg: #0f5560;
    --c-streak: #e8590c;
    --tone-easy-bg: #dff2e3;     --tone-easy-fg: #14612f;
    --tone-medium-bg: #fbeeda;   --tone-medium-fg: #8a5300;
    --tone-hard-bg: #fadedb;     --tone-hard-fg: #8c2016;

    /* The bottom system inset, from whichever side actually knows it.
       env() where the browser reports one (a PWA, a notch); the Android
       app's WebView reports env() as 0 and injects --app-inset-bottom
       instead (MainActivity.applyBottomInsetToPage). max() picks the one
       that is real, so it can never be counted twice. Every bottom-bar
       offset reads this, never env() directly. */
    --inset-b: max(env(safe-area-inset-bottom, 0px), var(--app-inset-bottom, 0px));

    --rail-w: 240px;
    --rail-gap: 16px;
    --shell-max: 800px;
    /* (rail + gap + content) / 2 */
    --shell-half: 528px;
    --shell-inset: 8px;
    /* Where the rail starts once the viewport is too narrow to centre. */
    --shell-x: max(var(--shell-inset), calc(50% - var(--shell-half)));

    /* One reading measure for the article. In `ch` it would differ per
       element, because ch is relative to that element's own font size - which
       is why the headings ran ~300px wider than the paragraphs and the column
       looked ragged. */
    --prose: 550px;

    --radius: 12px;
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 20px;
    --radius-pill: 999px;
    --elev-1: 0 1px 2px rgba(60, 64, 67, 0.16), 0 1px 3px 1px rgba(60, 64, 67, 0.10);
    --elev-2: 0 1px 3px rgba(60, 64, 67, 0.18), 0 4px 8px 3px rgba(60, 64, 67, 0.10);
}

html.dark-mode,
.theme-swatch[data-theme="dark"] {
    /* Material 3 dark: tonal surfaces, light-blue primary on a dark ground. */
    --c-page: #131314;
    --c-box: #1e1f20;
    --c-box-alt: #282a2c;
    --c-border: #444746;
    --c-border-soft: rgba(255, 255, 255, 0.08);
    --c-font: #c4c7c5;
    --c-font-strong: #e3e3e3;
    --c-font-dim: #9aa0a6;
    /* Inverted for dark, using the light grey that is also in the logo. */
    --c-accent: #e4e3e3;
    --c-accent-hover: #ffffff;
    --c-accent-soft: #3a3635;
    --c-accent-on-soft: #e4e3e3;
    --c-on-accent: #272424;
    --c-hover: rgba(255, 255, 255, 0.07);
    --c-good: #6dd58c;
    --c-bad: #f2b8b5;
    --c-board: #d9b47a;

    --tone-pieces-bg: #26314a;   --tone-pieces-fg: #b8caf7;
    --tone-castles-bg: #1f3a29;  --tone-castles-fg: #96d8a8;
    --tone-openings-bg: #3d3220; --tone-openings-fg: #e8c48a;
    --tone-culture-bg: #322740;  --tone-culture-fg: #d8bdf0;

    --badge-course-bg: #21304d;  --badge-course-fg: #a9c6f8;
    --badge-time-bg: #3f3117;    --badge-time-fg: #efc689;
    --badge-play-bg: #1c3a27;    --badge-play-fg: #8ed6a4;
    --badge-streak-bg: #452321;  --badge-streak-fg: #f3a99f;
    --badge-tsume-bg: #452139;   --badge-tsume-fg: #f0a8d6;
    --badge-wiki-bg: #33244a;    --badge-wiki-fg: #cfb0ee;
    --badge-social-bg: #17383d;  --badge-social-fg: #8ed2dd;
    --c-streak: #ff922b;
    --tone-easy-bg: #1f3a29;     --tone-easy-fg: #96d8a8;
    --tone-medium-bg: #3d3220;   --tone-medium-fg: #e8c48a;
    --tone-hard-bg: #43241f;     --tone-hard-fg: #f2b0a6;

    --elev-1: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 3px 1px rgba(0, 0, 0, 0.25);
    --elev-2: 0 2px 6px rgba(0, 0, 0, 0.45), 0 6px 12px 4px rgba(0, 0, 0, 0.25);
}

/* --- Appearance themes beyond light and dark -------------------------
 * Each is light- or dark-BASED: the base is the .dark-mode class (present or
 * absent), which the hundreds of component rules key on, and the theme is a
 * data-theme attribute on <html> that swaps the surface and accent tokens
 * over that base. The category tones and badge families are left to the
 * base. Written AFTER html.dark-mode on purpose - same specificity, so file
 * order is what lets a dark-based theme override the dark tokens.
 *
 * The second selector in each pair is the preview swatch on the preferences
 * page, which carries the attribute on a plain span and reads the same
 * tokens; :root and html.dark-mode above pair with the light and dark
 * swatches the same way. */
html[data-theme="sepia"],
.theme-swatch[data-theme="sepia"] {
    /* Warm paper: brown ink, brown accent. */
    --c-page: #f2e9d8;
    --c-box: #fbf6ec;
    --c-box-alt: #efe5d1;
    --c-border: #d8cbb0;
    --c-border-soft: rgba(70, 50, 20, 0.09);
    --c-font: #4b4033;
    --c-font-strong: #2a2218;
    --c-font-dim: #7b6b54;
    --c-accent: #6f4b2a;
    --c-accent-hover: #85603b;
    --c-accent-soft: #eadbc3;
    --c-accent-on-soft: #5a3a1c;
    --c-on-accent: #fff8ee;
    --c-hover: rgba(111, 75, 42, 0.08);
    --c-good: #2f7a3a;
    --c-bad: #b63a2b;
    --elev-1: 0 1px 2px rgba(80, 60, 30, 0.16), 0 1px 3px 1px rgba(80, 60, 30, 0.10);
    --elev-2: 0 1px 3px rgba(80, 60, 30, 0.18), 0 4px 8px 3px rgba(80, 60, 30, 0.10);
}
html[data-theme="sakura"],
.theme-swatch[data-theme="sakura"] {
    /* Cherry: blush surfaces, a deep pink accent. */
    --c-page: #fbf0f4;
    --c-box: #ffffff;
    --c-box-alt: #f9e6ee;
    --c-border: #ebd1dc;
    --c-border-soft: rgba(120, 40, 70, 0.08);
    --c-font: #4c3b44;
    --c-font-strong: #2b1f26;
    --c-font-dim: #836b76;
    --c-accent: #b8446e;
    --c-accent-hover: #cb5c84;
    --c-accent-soft: #f7dbe6;
    --c-accent-on-soft: #8f2f52;
    --c-on-accent: #ffffff;
    --c-hover: rgba(184, 68, 110, 0.08);
    --c-good: #2e7d32;
    --c-bad: #c62828;
    --elev-1: 0 1px 2px rgba(120, 60, 90, 0.16), 0 1px 3px 1px rgba(120, 60, 90, 0.10);
    --elev-2: 0 1px 3px rgba(120, 60, 90, 0.18), 0 4px 8px 3px rgba(120, 60, 90, 0.10);
}
html[data-theme="midnight"],
.theme-swatch[data-theme="midnight"] {
    /* Navy: the dark base with blue surfaces and a sky-blue accent. */
    --c-page: #0e1320;
    --c-box: #161d2e;
    --c-box-alt: #1e2739;
    --c-border: #34405c;
    --c-border-soft: rgba(160, 180, 255, 0.10);
    --c-font: #c2cbe3;
    --c-font-strong: #eaf0ff;
    --c-font-dim: #8e9ab8;
    --c-accent: #8ab4f8;
    --c-accent-hover: #adc8fb;
    --c-accent-soft: #223457;
    --c-accent-on-soft: #b9d1ff;
    --c-on-accent: #0b1220;
    --c-hover: rgba(138, 180, 248, 0.10);
    --c-good: #7ddc95;
    --c-bad: #f6a9a3;
    --elev-1: 0 1px 2px rgba(0, 0, 20, 0.5), 0 1px 3px 1px rgba(0, 0, 20, 0.3);
    --elev-2: 0 2px 6px rgba(0, 0, 20, 0.55), 0 6px 12px 4px rgba(0, 0, 20, 0.3);
}
html[data-theme="matcha"],
.theme-swatch[data-theme="matcha"] {
    /* Deep green: the dark base steeped in tea. */
    --c-page: #0f1a14;
    --c-box: #172620;
    --c-box-alt: #1e3129;
    --c-border: #2f4b3d;
    --c-border-soft: rgba(150, 220, 180, 0.10);
    --c-font: #c3d7ca;
    --c-font-strong: #e9f4ec;
    --c-font-dim: #8fae9b;
    --c-accent: #9fd9b4;
    --c-accent-hover: #bfe8cc;
    --c-accent-soft: #25402f;
    --c-accent-on-soft: #bfe8cc;
    --c-on-accent: #0b1a11;
    --c-hover: rgba(159, 217, 180, 0.10);
    --c-good: #8ce0a3;
    --c-bad: #f2b8b5;
    --elev-1: 0 1px 2px rgba(0, 10, 5, 0.5), 0 1px 3px 1px rgba(0, 10, 5, 0.3);
    --elev-2: 0 2px 6px rgba(0, 10, 5, 0.55), 0 6px 12px 4px rgba(0, 10, 5, 0.3);
}
html[data-theme="sumi"],
.theme-swatch[data-theme="sumi"] {
    /* Ink black: true black for OLED screens, grey surfaces barely lifted. */
    --c-page: #000000;
    --c-box: #0d0d0d;
    --c-box-alt: #171717;
    --c-border: #303030;
    --c-border-soft: rgba(255, 255, 255, 0.08);
    --c-font: #c8c8c8;
    --c-font-strong: #f2f2f2;
    --c-font-dim: #8d8d8d;
    --c-accent: #e6e6e6;
    --c-accent-hover: #ffffff;
    --c-accent-soft: #262626;
    --c-accent-on-soft: #e6e6e6;
    --c-on-accent: #111111;
    --c-hover: rgba(255, 255, 255, 0.07);
    --c-good: #6dd58c;
    --c-bad: #f2b8b5;
    --elev-1: 0 1px 2px rgba(0, 0, 0, 0.7), 0 1px 3px 1px rgba(0, 0, 0, 0.5);
    --elev-2: 0 2px 6px rgba(0, 0, 0, 0.75), 0 6px 12px 4px rgba(0, 0, 0, 0.5);
}

/* The preview beside each appearance option: the page with a box on it, an
   accent bar and a line of text, in that theme's own tokens. */
.theme-swatch {
    position: relative;
    display: block;
    box-sizing: border-box;
    width: 44px;
    height: 32px;
    flex: 0 0 auto;
    border: 1px solid var(--c-border);
    border-radius: 6px;
    background: var(--c-page);
    overflow: hidden;
}
.theme-swatch::before {
    content: '';
    position: absolute;
    left: 6px; top: 6px; right: 6px; bottom: 6px;
    border: 1px solid var(--c-border);
    border-radius: 3px;
    background: var(--c-box);
}
.theme-swatch::after {
    content: '';
    position: absolute;
    left: 11px; top: 11px;
    width: 14px; height: 4px;
    border-radius: 2px;
    background: var(--c-accent);
    box-shadow: 0 7px 0 -1px var(--c-font-dim);
}

* {
    font-family: var(--font-ui);
}

html {
    background-color: var(--c-page);
    color: var(--c-font);
}

body {
    /* No reset in this stylesheet, so the UA's 8px was still there. On most
       pages it collapsed with the content card's own margin and hid; on the
       full-bleed play column there was nothing to collapse with and it pushed
       the page 16px past the viewport. It also made `50%` inside .content
       resolve against a 16px-narrower box than the fixed rail's. */
    margin: 0;
    transition: background-color 0.2s ease, color 0.2s ease;
    user-select: none;
    background-color: var(--c-page);
    color: var(--c-font);
    font-size: 15px;
    line-height: 1.45;
}

/* The toggle stamps the class on both elements; the tokens above do the work,
 * so these only have to keep the surfaces in sync. */
body.dark-mode,
html.dark-mode,
html.dark-mode body {
    background-color: var(--c-page);
    color: var(--c-font);
}

.theme-toggle {
    position: fixed;
    top: 20px;
    right: 20px;
    padding: 10px 15px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    background-color: #f0f0f0;
    color: #000000;
    font-family: var(--font-ui);
}

body.dark-mode .theme-toggle {
    background-color: #272424;
    color: #ffffff;
}

.leftdiv {
    position: fixed;
    top: 0;
    left: var(--shell-x);
    height: 100vh;
    width: 275px;
    display: flex;
    flex-direction: column;
    justify-content: safe center;
    align-items: flex-start;
    gap: 15px;
    padding: 20px;
    overflow-y: auto;
    scrollbar-width: none;          /* Firefox */
    -ms-overflow-style: none;       /* IE / old Edge */
}

.leftdiv::-webkit-scrollbar {       /* Chrome / Safari */
    display: none;
}

body.dark-mode .leftdiv {
    background-color: transparent;
}

.leftdiv a {
    color: inherit;
    text-decoration: none;
    padding: 8px;
    border-radius: 5px;
    position: relative;
    transition: color 0.2s ease;
}

.leftdiv a::after,
.dropbutton-arrow::after {
    content: '';
    position: absolute;
    left: -3px;
    right: 16px;
    bottom: 4px;
    height: 1px;
    background-color: currentColor;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.25s ease;
    pointer-events: none;
}

.leftdiv a:hover::after,
.leftdiv a:focus-visible::after,
.dropbutton-arrow:hover::after,
.dropbutton-arrow:focus-visible::after {
    transform: scaleX(0.9);
}

.dropbutton {
    display: flex;
    flex-direction: column;
    width: 100%;
}

.dropbutton-row {
    display: flex;
    align-items: center;
    width: 100%;
}

.dropbutton-link {
    display: block;
    flex: 1;
}

.dropbutton-arrow {
    background: none;
    border: none;
    cursor: pointer;
    color: inherit;
    font-size: 0.75em;
    padding: 4px;
    border-radius: 5px;
    position: relative;
    transition: transform 0.25s ease, color 0.2s ease;
    transform: rotate(0deg);
}

.dropbutton-arrow:hover {
    background-color: transparent;
}

.dropbutton.expanded .dropbutton-arrow {
    transform: rotate(90deg);
}

.subitems {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    max-height: 0;
    transition: max-height 0.25s ease;
}

.dropbutton.expanded .subitems {
    max-height: 500px;
    margin-left: -3px;
}

.subitems a {
    font-size: 0.9em;
    opacity: 0.85;
}
/* The drawer entries carry a glyph for the phone sheets; the rail's
   drawers stay words, as they always were. The phone block turns them on. */
.leftdiv .subitems .nav-icon { display: none; }

.content {
    /* Always clears the rail, at every width above the mobile breakpoint. */
    margin-left: calc(var(--shell-x) + var(--rail-w) + var(--rail-gap));
    width: min(
        calc(100% - var(--rail-w) - var(--rail-gap) - var(--shell-inset) * 2),
        var(--shell-max)
    );
    max-width: var(--shell-max);
    min-height: 100vh;
    background-color: var(--c-box);
    border-left: 1px solid var(--c-border);
    border-right: 1px solid var(--c-border);
}

.tweet-composer {
    display: flex;
    gap: 12px;
    padding: 16px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    top: 0;
    background-color: rgba(255, 255, 255, 0.8);
    backdrop-filter: blur(10px);
    z-index: 10;
}

body.dark-mode .tweet-composer {
    background-color: rgba(39, 36, 36, 0.8);
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.avatar-small {
    width: 48px;
    height: 48px;
    border-radius: 100% !important;
    object-fit: cover;
    flex-shrink: 0;
}

.composer-input-container {
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: 4px;
}

.composer-name {
    background-color: transparent;
    color: inherit;
    border: none;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    font-family: var(--font-ui);
    font-size: 1em;
    font-weight: bold;
    outline: none;
    padding: 4px 0;
    margin-top: 8px;
}

body.dark-mode .composer-name {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.composer-name::placeholder,
.composer-input::placeholder {
    color: rgba(0, 0, 0, 0.5);
}

body.dark-mode .composer-name::placeholder,
body.dark-mode .composer-input::placeholder {
    color: rgba(255, 255, 255, 0.5);
}

.composer-input {
    width: 100%;
    background-color: transparent;
    color: inherit;
    border: none;
    font-size: 1.25em;
    font-family: var(--font-ui);
    resize: none;
    outline: none;
    min-height: 48px;
    line-height: 1.5;
}

.composer-attachments {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.composer-attachments:empty {
    display: none;
}

.attachment {
    position: relative;
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 12px;
    overflow: hidden;
}

body.dark-mode .attachment {
    border-color: rgba(255, 255, 255, 0.1);
}

.attachment img {
    display: block;
    max-width: 100%;
    max-height: 360px;
    object-fit: cover;
}

.attachment audio {
    display: block;
    width: 100%;
}

.attachment-audio {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border: none;
}

body.dark-mode .attachment-audio {
    border: none;
}

.attachment-audio audio {
    flex: 1;
    min-width: 0;
}

.attachment-audio .attachment-remove {
    position: static;
    flex-shrink: 0;
}

.attachment iframe {
    display: block;
    width: 100%;
    height: 420px;
    border: none;
}

.attachment-remove {
    position: absolute;
    top: 6px;
    right: 6px;
    background-color: rgba(0, 0, 0, 0.6);
    color: white;
    border: none;
    border-radius: 50%;
    width: 24px;
    height: 24px;
    cursor: pointer;
    font-family: var(--font-ui);
    font-size: 0.9em;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

.composer-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.composer-actions {
    display: flex;
    gap: 4px;
}

.composer-action {
    background: none;
    border: none;
    cursor: pointer;
    color: inherit;
    padding: 6px;
    border-radius: 50%;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.2s ease;
}

.composer-action svg {
    display: block;
}

.composer-action:hover {
    background-color: rgba(0, 0, 0, 0.06);
}

body.dark-mode .composer-action:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.composer-action.active {
    background-color: rgba(0, 0, 0, 0.1);
}

body.dark-mode .composer-action.active {
    background-color: rgba(255, 255, 255, 0.14);
}

.compose-button {
    background-color: #272424;
    color: white;
    border: none;
    border-radius: 20px;
    padding: 10px 24px;
    font-weight: bold;
    font-size: 0.875em;
    cursor: pointer;
    font-family: var(--font-ui);
    transition: background-color 0.2s ease;
}

.compose-button:hover {
    background-color: #272424;
}

.compose-button:active {
    background-color: #272424;
}

.feed {
    display: flex;
    flex-direction: column;
}

.feed-item {
    display: flex;
    gap: 10px;
    padding: 10px 14px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    font-size: 0.875em;
}

body.dark-mode .feed-item {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.feed-item-body {
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: 4px;
    min-width: 0;
}

.feed-item-name {
    font-weight: bold;
    display: flex;
    align-items: center;
    gap: 6px;
    padding-top: 5px;
}

.feed-item-handle,
.feed-comment-handle {
    font-size: 0.8em;
    opacity: 0.55;
    margin-top: -2px;
    margin-bottom: 7px;
    word-break: break-all;
}

.feed-item-flag {
    font-family: 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif;
    font-weight: normal;
    font-size: 1em;
    line-height: 1;
}

.composer-name-row {
    display: flex;
    align-items: center;
    gap: 8px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    margin: -16px -16px 8px;
    padding: 8px 0;
}

body.is-logged-in .composer-name,
body.is-logged-in .composer-name-row {
    display: none !important;
}

body.dark-mode .composer-name-row {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.composer-name-row .composer-name {
    flex: 1;
    border-bottom: none;
    margin-top: 0;
}

.composer-flag {
    font-family: 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif;
    font-size: 1em;
    padding-right: 15px;
    line-height: 1;
}

.feed-item-text {
    white-space: pre-wrap;
    word-wrap: break-word;
}

.feed-item img,
.feed-item audio,
.feed-item iframe {
    max-width: 100%;
}

.feed-item iframe {
    width: calc(100% + 60px);
    max-width: none;
    height: 420px;
    border: none;
    border-radius: 12px;
    margin-left: -60px;
}

.feed-item img {
    border-radius: 12px;
    max-height: 360px;
}

.feed-item-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 4px;
    margin-top: 4px;
    max-width: 425px;
}

.feed-action {
    background: none;
    border: none;
    cursor: pointer;
    color: inherit;
    opacity: 0.65;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 1px;
    border-radius: 999px;
    font-family: var(--font-ui);
    font-size: 0.85em;
    transition: background-color 0.2s ease, color 0.2s ease, opacity 0.2s ease;
}

.feed-action[hidden] {
    display: none;
}

.feed-action:hover {
    opacity: 1;
}

body.dark-mode .feed-action:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.feed-action-upvotes:hover {
    color: #2ecc71;
}

.feed-action-bookmarks:hover {
    color: #f1c40f;
}

.feed-action-comments:hover {
    color: #3498db;
}

.feed-action svg {
    display: block;
}

.feed-action .action-glyph {
    display: inline-block;
    font-size: 18px;
    line-height: 1;
    font-family: var(--font-kanji);
}

.feed-action-count {
    line-height: 1;
}

.feed-action-bookmarks .feed-action-count {
    opacity: 0;
    transition: opacity 0.2s ease;
}

.feed-action-bookmarks:hover .feed-action-count,
.feed-action-bookmarks:focus-visible .feed-action-count {
    opacity: 1;
}

.feed-item-image {
    max-width: 100%;
    max-height: 420px;
    border-radius: 8px;
    display: block;
    margin-top: 6px;
}

.feed-item-comments[hidden] {
    display: none;
}

.feed-item-comments {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}

body.dark-mode .feed-item-comments {
    border-top-color: rgba(255, 255, 255, 0.08);
}

.feed-item-comments-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.feed-comment {
    display: flex;
    gap: 10px;
    margin-top: 4px;
    padding-bottom: 4px;
    padding-top: 10px;
    background-color: transparent;
    border-radius: 0;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
    font-size: 0.875em;
}

body.dark-mode .feed-comment {
    background-color: transparent;
    border-top-color: rgba(255, 255, 255, 0.08);
}

.feed-comment-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.feed-comment-name {
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 6px;
    padding-top: 5px;
}

.feed-comment-text {
    white-space: pre-wrap;
    word-wrap: break-word;
}

.feed-comment-form {
    margin-top: 10px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.feed-comment-form input,
.feed-comment-form textarea {
    font-family: inherit;
    font-size: 0.9em;
    padding: 6px 8px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 6px;
    background: transparent;
    color: inherit;
    resize: vertical;
}

.feed-comment-form textarea {
    min-height: 60px;
}

body.dark-mode .feed-comment-form input,
body.dark-mode .feed-comment-form textarea {
    border-color: rgba(255, 255, 255, 0.18);
}

.feed-comment-form .compose-button {
    align-self: flex-end;
}

.feed-item-comments-loading {
    font-size: 0.85em;
    opacity: 0.7;
}

.feed-item-clickable {
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.feed-item-clickable:hover {
    background-color: rgba(0, 0, 0, 0.025);
}

body.dark-mode .feed-item-clickable:hover {
    background-color: rgba(255, 255, 255, 0.03);
}

.feed-action.active {
    opacity: 1;
}

.feed-action-upvotes.active { color: #2ecc71; }
.feed-action-bookmarks.active { color: #f1c40f; }
.feed-action-bookmarks.active .feed-action-count { opacity: 1; }

body .mod-only { display: none; }
body.is-mod .mod-only { display: inline-flex; }

body .admin-only { display: none; }
body.is-admin .admin-only { display: inline-flex; }
/* The rail's admin entry is a whole nav item, not an inline control, so it
   keeps the item's own display when it shows. */
body .admin-nav { display: none; }
body.is-admin .admin-nav { display: flex; }

.feed-action-delete:hover { color: #e74c3c; }
.feed-action-ban:hover { color: #c0392b; }

.ban-dialog {
    width: min(380px, 100%);
    padding: 32px 28px 24px;
    text-align: center;
    gap: 0;
}

.ban-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background-color: rgba(192, 57, 43, 0.12);
    color: #c0392b;
    margin: 0 auto 16px;
}

.ban-title {
    margin: 0 0 6px;
    font-size: 1.4em;
    font-weight: 600;
    color: #c0392b;
}

.ban-subtitle {
    margin: 0 0 18px;
    opacity: 0.7;
    font-size: 0.92em;
}

.ban-reason-block {
    background-color: rgba(0, 0, 0, 0.04);
    border-radius: 12px;
    padding: 12px 14px;
    margin-bottom: 20px;
    text-align: left;
}

body.dark-mode .ban-reason-block {
    background-color: rgba(255, 255, 255, 0.05);
}

.ban-reason-label {
    font-size: 0.75em;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    opacity: 0.6;
    margin-bottom: 4px;
}

.ban-reason {
    margin: 0;
    font-size: 0.95em;
    white-space: pre-wrap;
    word-wrap: break-word;
}

.ban-ok {
    width: 100%;
    background-color: #272424;
    color: #ffffff;
    border: none;
    border-radius: 999px;
    padding: 12px 20px;
    font-family: inherit;
    font-size: 0.95em;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.15s ease;
}

.ban-ok:hover { opacity: 0.9; }

body.dark-mode .ban-ok {
    background-color: #ffffff;
    color: #272424;
}

.comment-ban {
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    padding: 2px 4px;
    opacity: 0.6;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.comment-ban:hover { opacity: 1; color: #c0392b; }
.comment-ban svg { width: 14px; height: 14px; }

.feed-action-pin:hover { color: #f39c12; }
.feed-action-pin.active { color: #f39c12; }

.feed-item-pinned {
    background-color: rgba(243, 156, 18, 0.05);
    border-left: 3px solid #f39c12;
    position: relative;
}

body.dark-mode .feed-item-pinned {
    background-color: rgba(243, 156, 18, 0.08);
}

.feed-item-pin-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.75em;
    color: #f39c12;
    opacity: 0.9;
    margin-left: auto;
    padding-right: 24px;
}

.feed-item-pin-label svg {
    width: 12px;
    height: 12px;
}

.feed-item-pin-hide {
    position: absolute;
    top: 6px;
    right: 6px;
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    opacity: 0.45;
    padding: 4px;
    border-radius: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.feed-item-pin-hide:hover { opacity: 1; background: rgba(0, 0, 0, 0.06); }
body.dark-mode .feed-item-pin-hide:hover { background: rgba(255, 255, 255, 0.08); }

.feed-item-pin-collapsed {
    display: none !important;
}

.role-badge {
    display: inline-flex;
    align-items: center;
    margin-left: 4px;
    color: #8b8b8b;
    line-height: 0;
    vertical-align: middle;
}

.role-badge svg {
    display: block;
    width: 16px;
    height: 16px;
}

body.dark-mode .role-badge {
    color: #b5b5b5;
}

/* The pass title beside a subscriber's name: a small seal with the title's
   first character - 王 King, 竜 Ryuuou, 名 Meijin - drawn wherever the staff
   mark is drawn (comments, posts, the seat in a room, the profile header).
   Three metals for three ranks: gold, the dragon's red, and black lacquer
   with gold for the top. */
.title-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    margin-left: 4px;
    width: 18px;
    height: 18px;
    border-radius: 5px;
    font-family: var(--font-kanji);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    vertical-align: middle;
    letter-spacing: 0;
    text-transform: none;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12) inset, 0 1px 1px rgba(0, 0, 0, 0.15);
    cursor: default;
}
.title-badge-king { background: linear-gradient(160deg, #f3d478 0%, #c9961a 60%, #a8770a 100%); color: #2a1e05; }
.title-badge-ryuuou { background: linear-gradient(160deg, #d43f48 0%, #a01f2a 60%, #6f0f18 100%); color: #ffe6a6; }
.title-badge-meijin {
    background: linear-gradient(160deg, #3d3538 0%, #1a1618 60%, #060505 100%);
    color: #f0c65e;
    box-shadow: 0 0 0 1px #c9a340 inset, 0 1px 1px rgba(0, 0, 0, 0.3);
}
.profile-name-row .title-badge { width: 22px; height: 22px; font-size: 13px; border-radius: 6px; margin-left: 0; }
.profile-role { display: inline-flex; align-items: center; gap: 6px; }
.play-player-name .title-badge { margin-left: 5px; }
.shop-pass-tier-name .title-badge { margin-left: 8px; width: 20px; height: 20px; font-size: 12px; }

.comment-delete {
    margin-left: auto;
    background: none;
    border: none;
    color: inherit;
    opacity: 0.5;
    cursor: pointer;
    font-size: 1em;
    line-height: 1;
    padding: 0 4px;
}

.comment-delete:hover { opacity: 1; color: #e74c3c; }

.feed-comment-reply-info {
    font-size: 0.85em;
    opacity: 0.65;
    margin-top: -4px;
}

.feed-comment-reply-info .mention-link {
    opacity: 1;
}

.feed-comment-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-top: 8px;
    margin-left: -8px;
    padding-bottom: 12px;
}

.feed-action.feed-comment-action {
    padding: 3px 8px;
    font-size: 0.8em;
}

.feed-action .feed-action-label {
    line-height: 1;
}

.mention {
    color: #3498db;
    opacity: 0.9;
}

.mention-link {
    color: #3498db;
    text-decoration: none;
    cursor: pointer;
}

.mention-link:hover {
    text-decoration: underline;
}

body.dark-mode .mention,
body.dark-mode .mention-link {
    color: #5dade2;
}

.comment-highlight {
    animation: commentHighlight 1.6s ease;
}

@keyframes commentHighlight {
    0% { background-color: rgba(52, 152, 219, 0.18); }
    100% { background-color: transparent; }
}

.composer-reply-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    align-self: flex-start;
    padding: 3px 8px;
    border-radius: 999px;
    background-color: rgba(52, 152, 219, 0.12);
    color: #3498db;
    font-size: 0.85em;
}

.composer-reply-chip[hidden] { display: none; }

body.dark-mode .composer-reply-chip {
    background-color: rgba(93, 173, 226, 0.18);
    color: #5dade2;
}

.composer-reply-chip-clear {
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    font-size: 1em;
    line-height: 1;
    padding: 0 2px;
    opacity: 0.7;
}

.composer-reply-chip-clear:hover { opacity: 1; }

.sidebar-shortcuts {
    /* Negative margin cancels most of the .leftdiv gap (15px) so the
       buttons sit close under the avatar/name instead of far below. */
    margin-top: -6px;
    padding: 0 8px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.sidebar-shortcut {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    box-sizing: border-box;
    flex: 0 0 36px;
    border-radius: 50%;
    color: inherit;
    text-decoration: none;
    transition: background-color 0.15s ease;
}

.sidebar-shortcut:hover {
    background-color: rgba(0, 0, 0, 0.06);
}

body.dark-mode .sidebar-shortcut:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.sidebar-shortcut-avatar {
    padding: 0;
    overflow: hidden;
    display: none;
}

.sidebar-shortcut-lang {
    background: none;
    border: 1px solid rgba(0, 0, 0, 0.15);
    font-family: inherit;
    font-size: 0.75em;
    font-weight: 600;
    letter-spacing: 0.05em;
    cursor: pointer;
    padding: 0;
}

body.dark-mode .sidebar-shortcut-lang {
    border-color: rgba(255, 255, 255, 0.18);
}

.sidebar-shortcut-lang:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.sidebar-shortcut-logout {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: #e74c3c;
}

.sidebar-shortcut-logout:hover {
    background-color: rgba(231, 76, 60, 0.12);
}

body.dark-mode .sidebar-shortcut-logout {
    color: #f87171;
}

body.dark-mode .sidebar-shortcut-logout:hover {
    background-color: rgba(248, 113, 113, 0.16);
}

.sidebar-avatar {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}

.sidebar-shortcut-badge {
    position: absolute;
    top: 0;
    right: 0;
    background-color: #e74c3c;
    color: #fff;
    border-radius: 999px;
    padding: 0 5px;
    font-size: 0.7em;
    line-height: 1.4;
    min-width: 16px;
    text-align: center;
}

.board-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

body.dark-mode .board-header {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.board-title {
    margin: 0;
    font-size: 1.2em;
    font-weight: bold;
}

.board-show-pinned {
    display: none;
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    opacity: 0.55;
    padding: 6px;
    border-radius: 6px;
    align-items: center;
    justify-content: center;
}
.board-show-pinned.is-active { display: inline-flex; }
.board-show-pinned:hover { opacity: 1; background: rgba(0, 0, 0, 0.06); }
body.dark-mode .board-show-pinned:hover { background: rgba(255, 255, 255, 0.08); }
.board-show-pinned svg { width: 20px; height: 20px; }

.page-header {
    display: flex;
    align-items: center;
    padding: 16px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

body.dark-mode .page-header {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.page-title {
    margin: 0;
    font-size: 1.2em;
    font-weight: bold;
}

.page-list {
    display: flex;
    flex-direction: column;
}

.page-loading,
.page-empty {
    padding: 24px;
    text-align: center;
    opacity: 0.6;
    font-size: 0.95em;
}

.notification-item {
    display: block;
    padding: 12px 14px;
    color: inherit;
    text-decoration: none;
    transition: background-color 0.15s ease;
    border: 1px solid transparent;
}

.notification-item:hover {
    background-color: rgba(0, 0, 0, 0.04);
}

body.dark-mode .notification-item:hover {
    background-color: rgba(255, 255, 255, 0.05);
}

.notification-item.unread {
    border-color: rgba(52, 152, 219, 0.25);
    background-color: rgba(52, 152, 219, 0.06);
}

body.dark-mode .notification-item.unread {
    border-color: rgba(93, 173, 226, 0.3);
    background-color: rgba(93, 173, 226, 0.08);
}

.notification-text {
    font-size: 0.95em;
}

.notification-preview {
    margin-top: 2px;
    font-size: 0.85em;
    opacity: 0.7;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.profile-header {
    display: flex;
    /* Top-aligned, not centred: the meta block is three or four rows tall
       and centring the avatar on it left the name floating above the
       picture. The name row is centred on the avatar by the meta block's
       own top padding instead - see .profile-meta. */
    align-items: flex-start;
    gap: 16px;
    padding: 20px 16px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

body.dark-mode .profile-header {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.profile-avatar-wrap {
    position: relative;
    display: inline-block;
    width: 72px;
    height: 72px;
    flex-shrink: 0;
}

.profile-avatar-wrap.editable {
    cursor: pointer;
}

.profile-avatar {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}

.profile-avatar-edit {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    background-color: rgba(0, 0, 0, 0.4);
    opacity: 0;
    transition: opacity 0.15s ease;
    pointer-events: none;
}

.profile-avatar-edit[hidden] { display: none; }

.profile-avatar-wrap.editable:hover .profile-avatar-edit {
    opacity: 1;
}

.profile-stats {
    display: flex;
    gap: 14px;
    margin-top: 6px;
    font-size: 0.9em;
    opacity: 0.8;
}

.profile-stat strong {
    font-weight: 600;
}

.profile-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1 1 auto;
    min-width: 0;
    /* (72px avatar - ~30px name row) / 2: the name sits level with the
       middle of the picture, the handle just under that middle. */
    padding-top: 21px;
}

.profile-description {
    margin: 6px 0 0;
    font-size: 0.92em;
    opacity: 0.8;
    white-space: pre-wrap;
    word-wrap: break-word;
}

.profile-matches { padding: 0; }
.profile-matches[hidden] { display: none; }
.profile-posts[hidden] { display: none; }
.profile-section-title { margin: 0 0 10px; font-size: 1.1em; font-weight: 600; }
/* Profile matches grid - no extra outer padding (the feed area already
 * provides it). Cards stack flush like the lobby/wiki listings. */
.profile-matches-list { padding: 0; }
/* Inside a profile match card, the players row must not wrap mid-name -
 * truncate with ellipsis instead so the card height stays predictable. */
.profile-match-card .play-recent-players {
    flex-wrap: nowrap;
    min-width: 0;
    /* Not clipped: the names ellipsize on their own, and a frame ring
     * round a 24px face sits just outside it. */
    overflow: visible;
    padding: 3px 0;
}
.profile-match-card .play-recent-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1 1 auto;
}
.profile-match-card .play-recent-vs { flex-shrink: 0; }
.profile-match-card .play-recent-avatar { flex-shrink: 0; }
.profile-match-card .play-recent-meta { flex-shrink: 0; }

/* Twitter-style profile tabs: full-width row of equal buttons with an
 * underline on the active one. Sits flush below the profile header. */
.profile-tabs {
    display: flex;
    align-items: stretch;
    border-bottom: 1px solid rgba(0, 0, 0, 0.10);
    margin: 0;
    padding: 0;
}
body.dark-mode .profile-tabs { border-bottom-color: rgba(255, 255, 255, 0.10); }
.profile-tab {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 14px 12px;
    border: none;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 0.95rem;
    cursor: pointer;
    opacity: 0.6;
    border-bottom: 2px solid transparent;
    transition: background-color 0.12s ease, opacity 0.12s ease, border-color 0.12s ease;
    text-decoration: none;
}
.profile-tab:hover { background: rgba(0, 0, 0, 0.04); opacity: 0.9; }
body.dark-mode .profile-tab:hover { background: rgba(255, 255, 255, 0.05); }
.profile-tab-active {
    opacity: 1;
    font-weight: 700;
    border-bottom-color: currentColor;
}
.profile-tab-label { white-space: nowrap; }
.profile-tab-count {
    font-size: 0.78rem;
    opacity: 0.55;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}
.profile-tab-active .profile-tab-count { opacity: 0.75; }
/* Result chip on profile match cards: same pill as .play-public-chip but
 * coloured per outcome (win / loss / active / draw). */
.profile-match-result-chip {
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.profile-match-result-win {
    background: rgba(26, 127, 58, 0.15);
    color: #1a7f3a;
}
.profile-match-result-loss {
    background: rgba(185, 28, 28, 0.13);
    color: #b91c1c;
}
.profile-match-result-active {
    background: rgba(194, 65, 12, 0.13);
    color: #c2410c;
}
.profile-match-result-draw {
    background: rgba(0, 0, 0, 0.10);
    color: rgba(0, 0, 0, 0.65);
}
.profile-match-result-unrated {
    background: transparent;
    color: rgba(0, 0, 0, 0.4);
    border: 1px dashed rgba(0, 0, 0, 0.25);
}
body.dark-mode .profile-match-result-unrated {
    color: rgba(255, 255, 255, 0.45);
    border-color: rgba(255, 255, 255, 0.30);
}
body.dark-mode .profile-match-result-win {
    background: rgba(74, 222, 128, 0.15);
    color: #4ade80;
}
body.dark-mode .profile-match-result-loss {
    background: rgba(248, 113, 113, 0.15);
    color: #f87171;
}
body.dark-mode .profile-match-result-active {
    background: rgba(251, 146, 60, 0.15);
    color: #fb923c;
}
body.dark-mode .profile-match-result-draw {
    background: rgba(255, 255, 255, 0.10);
    color: rgba(255, 255, 255, 0.65);
}

.profile-name {
    margin: 0;
    font-size: 1.4em;
    font-weight: bold;
}

.profile-handle {
    font-size: 0.9em;
    opacity: 0.6;
}
/* The handle and the badge collection share a line: the name row says who
   this is (name, staff mark, grade, the one badge they chose to show), the
   handle row what they have collected. */
.profile-handle-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 10px;
    font-size: 0.9em;
    color: var(--c-font-dim);
}
.profile-handle-row .profile-handle { font-size: 1em; opacity: 1; }
/* A middle dot between the words on the handle line. Not before the coins:
   they are visibly a group of their own, and on a phone they are what wraps
   to the next line, where a dot would lead it. */
.profile-handle-row > * + *::before {
    content: '·';
    margin-right: 10px;
    opacity: 0.55;
}
.profile-handle-row > .profile-coins::before { content: none; }
/* The grades read as words on this line, not as pills: a pill beside the
   name was a claim, a word after the handle is a fact. */
.profile-handle-row .profile-rank,
.profile-handle-row .profile-rank-tsume,
.profile-handle-row .profile-rank-provisional {
    padding: 0;
    border: none;
    background: none;
    color: var(--c-font-dim);
    font-size: 1em;
    font-weight: 600;
    letter-spacing: 0;
}
.profile-coins { display: inline-flex; align-items: center; }

/* ---- The banner ----------------------------------------------------------
   A 3:1 strip above the header, clipped to the content's own radius. With
   nothing set it takes no room; on your own profile it becomes a quiet
   strip that offers to add one, in the tone of a placeholder rather than a
   box. */
.profile-banner {
    position: relative;
    display: block;
    /* 24px at the sides so its edges line up with the avatar and the tabs
       below, which sit inside the header's 24px padding; more room above
       so it does not press against the top of the card. */
    margin: 20px 24px 0;
    border-radius: var(--radius-lg, 14px);
    overflow: hidden;
    aspect-ratio: 3 / 1;
    max-height: 260px;
}
.profile-banner[hidden] { display: none; }
.profile-banner.editable { cursor: pointer; }
.profile-banner-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.profile-banner-img[hidden] { display: none; }
.profile-banner-edit {
    position: absolute;
    right: 10px;
    bottom: 10px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    border-radius: var(--radius-pill, 999px);
    background-color: rgba(0, 0, 0, 0.55);
    color: #ffffff;
    font-size: 0.8em;
    opacity: 0;
    transition: opacity 0.15s ease;
}
.profile-banner-edit[hidden] { display: none; }
.profile-banner.editable:hover .profile-banner-edit,
.profile-banner.editable:focus-within .profile-banner-edit { opacity: 1; }
.profile-banner-remove {
    position: absolute;
    left: 10px;
    bottom: 10px;
    padding: 5px 10px;
    border: none;
    border-radius: var(--radius-pill, 999px);
    background-color: rgba(0, 0, 0, 0.55);
    color: #ffffff;
    font: inherit;
    font-size: 0.8em;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s ease;
}
.profile-banner-remove[hidden] { display: none; }
.profile-banner.editable:hover .profile-banner-remove,
.profile-banner.editable:focus-within .profile-banner-remove { opacity: 1; }
/* Clubs carry the same two pictures in the same components. The face is
   squarer than a person's, so a club and a member never read as the same
   kind of thing on one page. */
.club-banner.has-banner + .home-hero { padding-top: 16px; }
.club-avatar-wrap { flex: 0 0 auto; align-self: flex-start; }
.club-avatar-wrap .profile-avatar,
.club-avatar-wrap .profile-avatar-edit { border-radius: 18px; }
.club-card-face {
    width: 24px;
    height: 24px;
    border-radius: 7px;
    object-fit: cover;
    vertical-align: middle;
    margin-right: 8px;
}
/* Under a banner the avatar grows and rides up over the picture's bottom
   edge, ringed in the page colour so it reads as sitting on top of it. Only
   the avatar moves up - the header itself stays put, so the name row starts
   below the banner and is centred on the avatar: the picture's centre is
   48 - 28 = 20px into the header, the name row's is 6 + 15. The avatar's
   bottom then lands where the stats begin. */
.profile-banner.has-banner + .profile-header { padding-top: 0; }
.profile-banner.has-banner + .profile-header .profile-avatar-wrap {
    width: 96px;
    height: 96px;
    margin-top: -28px;
}
.profile-banner.has-banner + .profile-header .profile-avatar {
    width: 96px;
    height: 96px;
    box-shadow: 0 0 0 4px var(--c-box);
}
.profile-banner.has-banner + .profile-header .profile-meta { padding-top: 6px; }

.feed-item-edit-btn {
    margin-left: auto;
    background: none;
    border: none;
    color: inherit;
    opacity: 0.5;
    cursor: pointer;
    padding: 2px 6px;
    border-radius: 4px;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.feed-item-edit-btn:hover {
    opacity: 1;
    background-color: rgba(0, 0, 0, 0.06);
}

body.dark-mode .feed-item-edit-btn:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.feed-item-edit-textarea {
    width: 100%;
    min-height: 80px;
    background: transparent;
    color: inherit;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 8px;
    padding: 8px 10px;
    font-family: inherit;
    font-size: 1em;
    resize: vertical;
    outline: none;
}

body.dark-mode .feed-item-edit-textarea {
    border-color: rgba(255, 255, 255, 0.18);
}

.feed-item-edit-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

.sidebar-auth {
    margin-top: 16px;
    padding: 0 16px;
    font-size: 0.9em;
    opacity: 0.85;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}

.sidebar-auth-user {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    max-width: 100%;
}

.sidebar-auth-avatar-link {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    /* Not clipped: the frame ring sits just outside this box. */
    overflow: visible;
    margin-left: -11px;
    border: 2px solid transparent;
    transition: border-color 0.15s ease;
}

.sidebar-auth-avatar-link:hover {
    border-color: #000;
    border: 2px solid #000;
    border-radius: 100%;
}

body.dark-mode .sidebar-auth-avatar-link:hover {
    border-color: #f5f5f5;
}

/* The .leftdiv a::after hover underline must not show under the
   avatar or username link in the auth block. */
.sidebar-auth-avatar-link::after,
.sidebar-auth-name::after {
    display: none;
}

.sidebar-auth-avatar {
    border-radius: 50%;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    border-radius: 50%;
}

.sidebar-auth-name {
    font-weight: 600;
    color: inherit;
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-left: -13px;
    white-space: nowrap;
}

.sidebar-auth-name:hover {
    text-decoration: underline;
}

.sidebar-auth-login {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    font: inherit;
    font-size: 1em;
    padding: 0;
    opacity: 0.75;
    transition: opacity 0.15s ease;
}

.sidebar-auth-login:hover {
    opacity: 1;
}

.auth-dialog {
    width: min(400px, 100%);
    padding: 28px 28px 24px;
    gap: 0;
}

.auth-close {
    position: absolute;
    top: 14px;
    right: 14px;
    background: none;
    border: none;
    color: inherit;
    opacity: 0.55;
    cursor: pointer;
    padding: 6px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.auth-close:hover {
    opacity: 1;
    background-color: rgba(0, 0, 0, 0.06);
}

body.dark-mode .auth-close:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.auth-hero {
    text-align: center;
    margin-bottom: 18px;
}

.auth-title {
    margin: 0 0 4px;
    font-size: 1.5em;
    font-weight: 600;
}

.auth-subtitle {
    margin: 0;
    opacity: 0.6;
    font-size: 0.92em;
}

.auth-tabs {
    position: relative;
    display: flex;
    background-color: rgba(0, 0, 0, 0.05);
    border-radius: 999px;
    padding: 4px;
    margin-bottom: 18px;
}

body.dark-mode .auth-tabs {
    background-color: rgba(255, 255, 255, 0.06);
}

.auth-tab {
    flex: 1;
    position: relative;
    z-index: 1;
    background: transparent;
    border: none;
    color: inherit;
    padding: 8px 12px;
    border-radius: 999px;
    cursor: pointer;
    font-family: inherit;
    font-size: 0.9em;
    opacity: 0.6;
    transition: opacity 0.2s ease;
}

.auth-tab.active {
    opacity: 1;
    font-weight: 600;
}

.auth-tab-indicator {
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 4px;
    width: calc(50% - 4px);
    background-color: #ffffff;
    border-radius: 999px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    transition: transform 0.25s ease;
    z-index: 0;
}

body.dark-mode .auth-tab-indicator {
    background-color: #3a3636;
}

.auth-modal[data-mode="register"] .auth-tab-indicator {
    transform: translateX(100%);
}

.auth-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.auth-avatar-uploader {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border: 1px dashed rgba(0, 0, 0, 0.2);
    border-radius: 12px;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.auth-avatar-uploader[hidden],
.auth-field[hidden] { display: none; }

.auth-avatar-uploader:hover {
    border-color: rgba(0, 0, 0, 0.4);
    background-color: rgba(0, 0, 0, 0.02);
}

body.dark-mode .auth-avatar-uploader {
    border-color: rgba(255, 255, 255, 0.2);
}

body.dark-mode .auth-avatar-uploader:hover {
    border-color: rgba(255, 255, 255, 0.4);
    background-color: rgba(255, 255, 255, 0.03);
}

.auth-avatar-preview {
    width: 52px;
    height: 52px;
    border-radius: 50%;
    background-color: rgba(0, 0, 0, 0.05);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    flex-shrink: 0;
    opacity: 0.7;
}

body.dark-mode .auth-avatar-preview {
    background-color: rgba(255, 255, 255, 0.06);
}

.auth-avatar-preview.has-image {
    opacity: 1;
}

.auth-avatar-preview img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.auth-avatar-text {
    flex: 1;
    font-size: 0.92em;
    opacity: 0.75;
}

.auth-avatar-clear {
    background: none;
    border: none;
    color: inherit;
    opacity: 0.5;
    cursor: pointer;
    font-size: 1.2em;
    line-height: 1;
    padding: 4px 8px;
    border-radius: 50%;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.auth-avatar-clear:hover {
    opacity: 1;
    background-color: rgba(0, 0, 0, 0.06);
}

body.dark-mode .auth-avatar-clear:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.auth-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.auth-label {
    font-size: 0.8em;
    opacity: 0.7;
    padding-left: 2px;
}

.auth-input {
    font-family: inherit;
    font-size: 0.95em;
    padding: 10px 12px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 10px;
    background: transparent;
    color: inherit;
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.auth-input:focus {
    border-color: rgba(0, 0, 0, 0.5);
    box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
}

body.dark-mode .auth-input {
    border-color: rgba(255, 255, 255, 0.18);
}

body.dark-mode .auth-input:focus {
    border-color: rgba(255, 255, 255, 0.5);
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.06);
}

.auth-error {
    margin: 0;
    color: #e74c3c;
    font-size: 0.88em;
    text-align: center;
}

.auth-submit {
    margin-top: 4px;
    background-color: #272424;
    color: #ffffff;
    border: none;
    border-radius: 999px;
    padding: 12px 20px;
    font-family: inherit;
    font-size: 0.95em;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.1s ease, opacity 0.15s ease;
}

.auth-submit:hover:not(:disabled) {
    opacity: 0.9;
}

.auth-submit:active:not(:disabled) {
    transform: translateY(1px);
}

.auth-submit:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

body.dark-mode .auth-submit {
    background-color: #ffffff;
    color: #272424;
}

.thread-header {
    padding: 8px 16px 0;
    margin-bottom: 4px;
}

.thread-back {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    color: inherit;
    text-decoration: none;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    font: inherit;
    transition: background-color 0.15s ease;
}

.thread-back svg {
    display: block;
}

.thread-back:hover {
    background-color: rgba(0, 0, 0, 0.06);
}

body.dark-mode .thread-back:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.thread-post .feed-item {
    cursor: default;
}

.thread-comments-section {
    margin-top: 4px;
}

.thread-comments-list {
    display: flex;
    flex-direction: column;
    padding: 0 16px;
}

.thread-comments-empty {
    font-size: 0.9em;
    opacity: 0.6;
    padding: 16px 0;
    text-align: center;
}

.thread-comment-form {
    padding: 0 16px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

body.dark-mode .thread-comment-form {
    border-top-color: rgba(255, 255, 255, 0.08);
    border-bottom-color: rgba(255, 255, 255, 0.08);
}

.thread-comment-form .comment-composer {
    padding: 12px 0;
}

.thread-comments-list .feed-comment:first-child {
    border-top: none;
}

.thread-loading,
.thread-error {
    padding: 12px;
    opacity: 0.7;
    font-size: 0.95em;
}

.modal-feed-item {
    cursor: default;
    padding: 0;
    background: transparent !important;
}

.modal-feed-item:hover {
    background: transparent;
}

.comment-modal .modal-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    /* Room for a frame ring on the quoted post's picture. */
    padding-top: 10px;
}

.comment-modal-post {
    padding-bottom: 4px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

body.dark-mode .comment-modal-post {
    border-bottom-color: rgba(255, 255, 255, 0.08);
}

.comment-composer {
    margin: 0;
    padding: 8px 0 0;
    background: transparent !important;
    backdrop-filter: none;
    border-bottom: none;
}

.modal[hidden] {
    display: none;
}

.modal {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}

.modal-backdrop {
    position: absolute;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.5);
}

.modal-dialog {
    position: relative;
    background-color: #ffffff;
    color: #000000;
    width: min(560px, 100%);
    max-height: calc(100vh - 40px);
    border-radius: 16px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

body.dark-mode .modal-dialog {
    background-color: #272424;
    color: #ffffff;
}

.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

body.dark-mode .modal-header {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.modal-title {
    margin: 0;
    font-size: 1.1em;
}

.modal-close {
    background: none;
    border: none;
    cursor: pointer;
    color: inherit;
    padding: 6px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.2s ease;
}

.modal-close:hover {
    background-color: rgba(0, 0, 0, 0.06);
}

body.dark-mode .modal-close:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.modal-body {
    padding: 16px 20px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    overflow-y: auto;
}

.modal-lishogi-input {
    background-color: transparent;
    color: inherit;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 8px;
    font-family: var(--font-ui);
    font-size: 0.95em;
    outline: none;
    padding: 10px 12px;
}

body.dark-mode .modal-lishogi-input {
    border-color: rgba(255, 255, 255, 0.15);
}

.modal-preview {
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 12px;
    min-height: 360px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

body.dark-mode .modal-preview {
    border-color: rgba(255, 255, 255, 0.1);
}

.modal-preview iframe {
    display: block;
    width: 100%;
    height: 420px;
    border: none;
}

.modal-preview-hint {
    margin: 0;
    padding: 24px;
    text-align: center;
    opacity: 0.65;
}

.modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 12px 20px 16px;
    border-top: 1px solid rgba(0, 0, 0, 0.1);
}

body.dark-mode .modal-footer {
    border-top-color: rgba(255, 255, 255, 0.1);
}

.modal-cancel {
    background: none;
    border: 1px solid rgba(0, 0, 0, 0.15);
    color: inherit;
    border-radius: 20px;
    padding: 10px 20px;
    cursor: pointer;
    font-family: var(--font-ui);
    font-size: 1em;
}

body.dark-mode .modal-cancel {
    border-color: rgba(255, 255, 255, 0.2);
}

.modal-confirm:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

@media (max-width: 900px) {
    .leftdiv {
        position: fixed;
        top: auto;
        bottom: 0;
        left: 0;
        right: 0;
        width: 100%;
        height: auto;
        flex-direction: row;
        justify-content: space-around;
        align-items: center;
        padding: 10px 10px calc(10px + var(--inset-b));
        gap: 6px;
        background-color: rgba(255, 255, 255, 0.95);
        backdrop-filter: blur(10px);
        border-top: 1px solid rgba(0, 0, 0, 0.1);
        z-index: 50;
        /* Bottom bar: must NOT inherit the desktop scroll container,
           otherwise backdrop-filter makes it clip the fixed submenu. */
        overflow: visible;
    }

    body.dark-mode .leftdiv {
        background-color: var(--c-box);
        border-top-color: var(--c-border);
    }

    .leftdiv > img,
    .leftdiv > .sidebar-logo,
    .leftdiv .sidebar-header {
        display: none;
    }

    .leftdiv .dropbutton {
        width: auto;
        flex: 0 0 auto;
        min-width: 0;
        position: relative;
    }

    .leftdiv .dropbutton-row {
        display: flex;
        align-items: center;
        justify-content: center;
        width: auto;
    }

    .leftdiv .dropbutton-arrow {
        display: none;
    }

    .leftdiv .dropbutton-link {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        padding: 0;
        width: 44px;
        height: 44px;
        border-radius: 50%;
        font-size: 0;
        flex: 0 0 auto;
        transition: background-color 0.15s ease;
    }

    .leftdiv .dropbutton-link::after {
        display: none;
    }

    .leftdiv .dropbutton-link:hover,
    .leftdiv .dropbutton-link:active,
    .leftdiv .dropbutton.expanded .dropbutton-link {
        background-color: rgba(0, 0, 0, 0.08);
    }

    body.dark-mode .leftdiv .dropbutton-link:hover,
    body.dark-mode .leftdiv .dropbutton-link:active,
    body.dark-mode .leftdiv .dropbutton.expanded .dropbutton-link {
        background-color: rgba(255, 255, 255, 0.1);
    }

    .leftdiv .dropbutton-link::before {
        content: "";
        display: block;
        width: 24px;
        height: 24px;
        background-color: currentColor;
        -webkit-mask-size: 24px 24px;
        mask-size: 24px 24px;
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-position: center;
        mask-position: center;
    }

    .leftdiv .dropbutton[data-key="boards"] .dropbutton-link::before {
        -webkit-mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z'/%3E%3C/svg%3E");
    }

    .leftdiv .dropbutton[data-key="studies"] .dropbutton-link::before {
        -webkit-mask-image: url("/images/study-pieces.svg");
        mask-image: url("/images/study-pieces.svg");
    }

    .leftdiv .dropbutton[data-key="play"] .dropbutton-link::before {
        -webkit-mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M8 5v14l11-7z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M8 5v14l11-7z'/%3E%3C/svg%3E");
    }

    .leftdiv .dropbutton[data-key="preferences"] .dropbutton-link::before {
        -webkit-mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' fill-rule='evenodd' d='M19.14 12.94a7.07 7.07 0 0 0 0-1.88l2.03-1.58a.5.5 0 0 0 .12-.64l-1.92-3.32a.5.5 0 0 0-.61-.22l-2.39.96a7 7 0 0 0-1.62-.94l-.36-2.54a.5.5 0 0 0-.5-.42h-3.84a.5.5 0 0 0-.5.42l-.36 2.54a7 7 0 0 0-1.62.94l-2.39-.96a.5.5 0 0 0-.61.22L2.6 8.84a.5.5 0 0 0 .12.64l2.03 1.58a7.07 7.07 0 0 0 0 1.88L2.72 14.5a.5.5 0 0 0-.12.64l1.92 3.32a.5.5 0 0 0 .61.22l2.39-.96a7 7 0 0 0 1.62.94l.36 2.54a.5.5 0 0 0 .5.42h3.84a.5.5 0 0 0 .5-.42l.36-2.54a7 7 0 0 0 1.62-.94l2.39.96a.5.5 0 0 0 .61-.22l1.92-3.32a.5.5 0 0 0-.12-.64zM12 15.5A3.5 3.5 0 1 1 12 8.5a3.5 3.5 0 0 1 0 7z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' fill-rule='evenodd' d='M19.14 12.94a7.07 7.07 0 0 0 0-1.88l2.03-1.58a.5.5 0 0 0 .12-.64l-1.92-3.32a.5.5 0 0 0-.61-.22l-2.39.96a7 7 0 0 0-1.62-.94l-.36-2.54a.5.5 0 0 0-.5-.42h-3.84a.5.5 0 0 0-.5.42l-.36 2.54a7 7 0 0 0-1.62.94l-2.39-.96a.5.5 0 0 0-.61.22L2.6 8.84a.5.5 0 0 0 .12.64l2.03 1.58a7.07 7.07 0 0 0 0 1.88L2.72 14.5a.5.5 0 0 0-.12.64l1.92 3.32a.5.5 0 0 0 .61.22l2.39-.96a7 7 0 0 0 1.62.94l.36 2.54a.5.5 0 0 0 .5.42h3.84a.5.5 0 0 0 .5-.42l.36-2.54a7 7 0 0 0 1.62-.94l2.39.96a.5.5 0 0 0 .61-.22l1.92-3.32a.5.5 0 0 0-.12-.64zM12 15.5A3.5 3.5 0 1 1 12 8.5a3.5 3.5 0 0 1 0 7z'/%3E%3C/svg%3E");
    }

    .leftdiv .dropbutton[data-key="support"] .dropbutton-link::before {
        -webkit-mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M16 11c1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3 1.34 3 3 3zm-8 0c1.66 0 3-1.34 3-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M16 11c1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3 1.34 3 3 3zm-8 0c1.66 0 3-1.34 3-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z'/%3E%3C/svg%3E");
    }

    .leftdiv .dropbutton[data-key="donate"] .dropbutton-link::before {
        -webkit-mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z'/%3E%3C/svg%3E");
    }

    .leftdiv .subitems {
        display: none;
        position: fixed;
        bottom: calc(58px + var(--inset-b));
        left: 12px;
        right: 12px;
        flex-direction: column;
        gap: 2px;
        padding: 8px;
        min-width: 0;
        max-width: none;
        max-height: none;
        overflow: visible;
        background-color: rgba(255, 255, 255, 0.98);
        color: #000;
        border: 1px solid rgba(0, 0, 0, 0.1);
        border-radius: 14px;
        box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
        z-index: 60;
        animation: dropbuttonPopIn 0.15s ease;
    }

    body.dark-mode .leftdiv .subitems {
        background-color: rgba(46, 43, 43, 0.98);
        color: #fff;
        border-color: rgba(255, 255, 255, 0.12);
        box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
    }

    .leftdiv .dropbutton.expanded .subitems {
        display: flex;
    }

    @keyframes dropbuttonPopIn {
        from { opacity: 0; transform: translateY(6px); }
        to { opacity: 1; transform: translateY(0); }
    }

    .leftdiv .subitems a {
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 10px 14px;
        width: 100%;
        font-size: 0.95em;
        opacity: 1;
        border-radius: 8px;
        white-space: nowrap;
        text-align: left;
        transition: background-color 0.15s ease;
    }

    .leftdiv .subitems a::after {
        display: none;
    }

    .leftdiv .subitems a:hover,
    .leftdiv .subitems a:active {
        background-color: rgba(0, 0, 0, 0.06);
    }

    body.dark-mode .leftdiv .subitems a:hover,
    body.dark-mode .leftdiv .subitems a:active {
        background-color: rgba(255, 255, 255, 0.08);
    }

    .leftdiv .subitems a::before {
        content: "";
        flex: 0 0 auto;
        display: block;
        width: 22px;
        height: 22px;
        background-color: currentColor;
        -webkit-mask-size: 22px 22px;
        mask-size: 22px 22px;
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-position: center;
        mask-position: center;
    }

    .leftdiv .subitems a[href="/b/shogi"]::before {
        -webkit-mask-image: url("/images/board-shogi.svg");
        mask-image: url("/images/board-shogi.svg");
    }

    .leftdiv .subitems a[href="/b/anime"]::before {
        -webkit-mask-image: url("/images/board-anime.svg");
        mask-image: url("/images/board-anime.svg");
    }

    .leftdiv .subitems a[href="/b/tech"]::before {
        -webkit-mask-image: url("/images/board-tech.svg");
        mask-image: url("/images/board-tech.svg");
    }

    .leftdiv .subitems a[href="/b/venting"]::before {
        -webkit-mask-image: url("/images/board-venting.svg");
        mask-image: url("/images/board-venting.svg");
    }

    .leftdiv .subitems a[href="/b/life"]::before {
        -webkit-mask-image: url("/images/board-life.svg");
        mask-image: url("/images/board-life.svg");
    }

    .leftdiv .subitems a[href="/pieces"]::before {
        -webkit-mask-image: url("/images/study-pieces.svg");
        mask-image: url("/images/study-pieces.svg");
    }

    .leftdiv .subitems a[href="/castles"]::before {
        -webkit-mask-image: url("/images/study-castles.svg");
        mask-image: url("/images/study-castles.svg");
    }

    .leftdiv .subitems a[href="/openings"]::before {
        -webkit-mask-image: url("/images/study-openings.svg");
        mask-image: url("/images/study-openings.svg");
    }

    .sidebar-auth {
        display: none;
    }

    .sidebar-shortcuts {
        margin-top: 0;
        padding: 0;
        gap: 6px;
        flex: 0 0 auto;
    }

    .sidebar-shortcut {
        width: 44px;
        height: 44px;
    }

    /* .sidebar-auth is hidden on mobile, so the avatar shortcut is the
       only profile/login entry point here - bring it back. */
    .sidebar-shortcut-avatar {
        display: inline-flex;
    }

    .sidebar-shortcut svg {
        width: 22px;
        height: 22px;
    }

    .sidebar-shortcut-bookmarks {
        display: none !important;
    }

    .sidebar-shortcut-lang,
    .sidebar-shortcut-logout {
        display: none !important;
    }

    .content {
        margin-left: 0;
        width: 100%;
        max-width: 100%;
        min-height: calc(100vh - 72px);
        border-left: none;
        border-right: none;
        padding-bottom: calc(88px + var(--inset-b));
    }

    .feed-item iframe {
        width: 100%;
        margin-left: 0;
    }

    .attachment iframe,
    .modal-preview iframe {
        height: 320px;
    }

    .theme-toggle {
        top: auto;
        bottom: calc(88px + var(--inset-b));
    }

    .modal {
        padding: 12px;
    }

    .modal-dialog {
        max-height: calc(100vh - 80px);
    }
}

.piece-link,
.wiki-link {
    color: #2c2c2c;
    text-decoration: none;
    border-bottom: 1px dotted currentColor;
    cursor: pointer;
    transition: color 0.15s ease, border-bottom-color 0.15s ease;
}

.piece-link:hover,
.piece-link:focus,
.wiki-link:hover,
.wiki-link:focus {
    color: #000;
    border-bottom-style: dashed;
    outline: none;
}

body.dark-mode .piece-link,
body.dark-mode .wiki-link {
    color: #c8c8c8;
}

body.dark-mode .piece-link:hover,
body.dark-mode .piece-link:focus,
body.dark-mode .wiki-link:hover,
body.dark-mode .wiki-link:focus {
    color: #fff;
}

.piece-tooltip {
    position: absolute;
    z-index: 10000;
    max-width: 320px;
    min-width: 180px;
    padding: 10px 12px;
    background: #1f1d1d;
    color: #f4f4f4;
    border-radius: 8px;
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.25);
    font-size: 0.88em;
    line-height: 1.45;
    pointer-events: auto;
}

body.dark-mode .piece-tooltip {
    background: #f5f3f3;
    color: #1f1d1d;
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.45);
}

.piece-tooltip[hidden] {
    display: none;
}

.piece-tooltip-head {
    display: flex;
    flex-direction: column;
    margin-bottom: 6px;
}

.piece-tooltip-kanji {
    font-size: 1.1em;
    opacity: 0.85;
}

.piece-tooltip-title {
    font-weight: bold;
}

.piece-tooltip-move {
    margin-bottom: 4px;
}

.piece-tooltip-move-label {
    font-weight: bold;
    opacity: 0.85;
}

.piece-tooltip-desc {
    opacity: 0.95;
}

.piece-name-chip {
    display: inline-block;
}

.wiki-picker-menu {
    position: absolute;
    z-index: 10001;
    min-width: 260px;
    max-width: 320px;
    max-height: 280px;
    overflow-y: auto;
    background: #fff;
    color: #1f1d1d;
    border: 1px solid #d8d8d8;
    border-radius: 10px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
    padding: 4px;
    font-size: 0.92em;
}

.wiki-picker-menu[hidden] {
    display: none;
}

body.dark-mode .wiki-picker-menu {
    background: #1f1d1d;
    color: #f4f4f4;
    border-color: #3a3a3a;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
}

.wiki-picker-empty {
    padding: 10px 12px;
    opacity: 0.6;
    font-style: italic;
}

.wiki-picker-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 7px;
    cursor: pointer;
    transition: background-color 0.1s ease;
}

.wiki-picker-item:hover,
.wiki-picker-item.active {
    background: #f0f0f0;
}

body.dark-mode .wiki-picker-item:hover,
body.dark-mode .wiki-picker-item.active {
    background: #2e2c2c;
}

.wiki-picker-badge {
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #ece9e3;
    color: #2c2c2c;
    border-radius: 6px;
    font-weight: bold;
    font-size: 0.95em;
    line-height: 1;
}

body.dark-mode .wiki-picker-badge {
    background: #36302a;
    color: #f0e8da;
}

.wiki-picker-badge-castles {
    background: #d8e4d6;
    color: #2c4429;
}

body.dark-mode .wiki-picker-badge-castles {
    background: #2f3f2c;
    color: #c2dabf;
}

.wiki-picker-badge-openings {
    background: #e0dcef;
    color: #382c5e;
}

body.dark-mode .wiki-picker-badge-openings {
    background: #322c4a;
    color: #c8c0e0;
}

.wiki-picker-main {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
}

.wiki-picker-title {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.wiki-picker-slug {
    font-size: 0.78em;
    opacity: 0.6;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.wiki-article {
    padding: 24px 28px;
    max-width: 880px;
    margin: 0 auto;
    position: relative;
}

.wiki-toolbar-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 24px;
}

.wiki-back {
    color: inherit;
    text-decoration: none;
    opacity: 0.7;
    font-size: 0.92em;
}

.wiki-back:hover { opacity: 1; }

.wiki-kanji {
    text-align: center;
    font-size: 5em;
    line-height: 1.1;
    margin: 8px 0 4px 0;
    letter-spacing: 0.04em;
}

.wiki-title {
    text-align: center;
    margin: 0 0 14px 0;
    font-size: 2em;
    font-weight: bold;
    line-height: 1.2;
}

.wiki-movement {
    text-align: center;
    margin: 0 auto 24px auto;
    max-width: 640px;
    line-height: 1.55;
    opacity: 0.85;
}

.wiki-movement-label {
    font-weight: bold;
    opacity: 0.7;
    margin-right: 4px;
}

.wiki-divider {
    border: none;
    border-top: 1px solid rgba(0, 0, 0, 0.12);
    margin: 0 0 24px 0;
}

body.dark-mode .wiki-divider {
    border-top-color: rgba(255, 255, 255, 0.15);
}

.wiki-toolbar-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.wiki-icon-btn {
    background: transparent;
    border: 1px solid rgba(0, 0, 0, 0.2);
    color: inherit;
    cursor: pointer;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.wiki-icon-btn svg {
    display: block;
}

body.dark-mode .wiki-icon-btn {
    border-color: rgba(255, 255, 255, 0.22);
}

.wiki-icon-btn:hover {
    background-color: rgba(0, 0, 0, 0.05);
    border-color: currentColor;
}

body.dark-mode .wiki-icon-btn:hover {
    background-color: rgba(255, 255, 255, 0.06);
}

.wiki-body-rendered {
    line-height: 1.65;
    font-size: 1em;
}

.wiki-body-rendered h1,
.wiki-body-rendered h2,
.wiki-body-rendered h3,
.wiki-body-rendered h4 {
    margin-top: 1.4em;
    margin-bottom: 0.5em;
    line-height: 1.25;
}

.wiki-body-rendered h2 {
    font-size: 1.45em;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    padding-bottom: 4px;
}

body.dark-mode .wiki-body-rendered h2 {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.wiki-body-rendered h3 { font-size: 1.2em; }

.wiki-body-rendered p { margin: 0 0 1em 0; }

.wiki-body-rendered ul,
.wiki-body-rendered ol {
    margin: 0 0 1em 1.4em;
    padding: 0;
}

.wiki-body-rendered blockquote {
    margin: 1em 0;
    padding: 8px 14px;
    border-left: 3px solid rgba(0, 0, 0, 0.2);
    opacity: 0.85;
    font-style: italic;
}

body.dark-mode .wiki-body-rendered blockquote {
    border-left-color: rgba(255, 255, 255, 0.25);
}

.wiki-body-rendered .wiki-cite {
    font-size: 0.78em;
    line-height: 0;
    vertical-align: super;
    margin-left: 1px;
}

.wiki-body-rendered .wiki-cite a {
    color: #1a4ea8;
    text-decoration: none;
    padding: 0 1px;
}

.wiki-body-rendered .wiki-cite a:hover {
    text-decoration: underline;
}

body.dark-mode .wiki-body-rendered .wiki-cite a {
    color: #7aaaff;
}

.wiki-body-rendered .wiki-cite a:target,
.wiki-body-rendered .wiki-references li:target {
    background: rgba(255, 230, 120, 0.45);
    border-radius: 3px;
}

body.dark-mode .wiki-body-rendered .wiki-cite a:target,
body.dark-mode .wiki-body-rendered .wiki-references li:target {
    background: rgba(120, 100, 0, 0.55);
}

.wiki-body-rendered .wiki-references {
    margin-top: 2em;
    padding-top: 0.6em;
    border-top: 1px solid rgba(0, 0, 0, 0.1);
    font-size: 0.92em;
}

body.dark-mode .wiki-body-rendered .wiki-references {
    border-top-color: rgba(255, 255, 255, 0.12);
}

.wiki-body-rendered .wiki-references h2 {
    font-size: 1.1em;
    margin: 0 0 0.5em 0;
    border-bottom: none;
    padding-bottom: 0;
}

.wiki-body-rendered .wiki-references ol {
    margin: 0 0 0 1.6em;
    padding: 0;
}

.wiki-body-rendered .wiki-references li {
    margin: 0.25em 0;
    padding: 1px 4px;
}

.wiki-body-rendered .wiki-ref-back {
    color: inherit;
    text-decoration: none;
    opacity: 0.7;
    margin-right: 4px;
}

.wiki-body-rendered .wiki-ref-back:hover {
    text-decoration: underline;
    opacity: 1;
}

.wiki-body-rendered .wiki-ref-backs {
    font-size: 0.85em;
}

.wiki-body-rendered .wiki-ref-backs .wiki-ref-back {
    margin-right: 3px;
}

.wiki-body-rendered code {
    font-family: monospace;
    background: rgba(0, 0, 0, 0.06);
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 0.92em;
}

body.dark-mode .wiki-body-rendered code {
    background: rgba(255, 255, 255, 0.08);
}

.wiki-body-rendered hr {
    border: none;
    border-top: 1px solid rgba(0, 0, 0, 0.12);
    margin: 1.5em 0;
}

body.dark-mode .wiki-body-rendered hr {
    border-top-color: rgba(255, 255, 255, 0.15);
}

.wiki-image {
    max-width: 100%;
    border-radius: 6px;
    vertical-align: middle;
}

.wiki-figure {
    margin: 1.2em 0;
    text-align: center;
}

.wiki-figure img {
    max-width: 100%;
    border-radius: 8px;
}

.wiki-figure figcaption {
    font-size: 0.88em;
    opacity: 0.7;
    margin-top: 6px;
}

.wiki-lishogi {
    margin: 1.2em 0;
}

.wiki-lishogi iframe {
    width: 100%;
    height: 480px;
    border: 0;
    border-radius: 8px;
    background: #000;
}

.wiki-empty {
    opacity: 0.55;
    font-style: italic;
}

.wiki-footer {
    margin-top: 28px;
    padding-top: 12px;
    border-top: 1px solid rgba(0, 0, 0, 0.1);
    font-size: 0.85em;
    opacity: 0.7;
    clear: both;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.wiki-footer > span[hidden] {
    display: none;
}

body.dark-mode .wiki-footer {
    border-top-color: rgba(255, 255, 255, 0.12);
}

/* Editor */

.wiki-editor {
    margin-top: 12px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 10px;
    overflow: hidden;
    background: rgba(0, 0, 0, 0.015);
}

body.dark-mode .wiki-editor {
    border-color: rgba(255, 255, 255, 0.15);
    background: rgba(255, 255, 255, 0.025);
}

.wiki-editor-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 8px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    background: rgba(0, 0, 0, 0.025);
}

body.dark-mode .wiki-editor-toolbar {
    border-bottom-color: rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.03);
}

.wiki-tool-btn {
    background: transparent;
    border: 1px solid transparent;
    border-radius: 5px;
    padding: 5px 10px;
    cursor: pointer;
    color: inherit;
    font-family: inherit;
    font-size: 0.95em;
    line-height: 1;
    min-width: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.wiki-tool-btn:hover {
    background: rgba(0, 0, 0, 0.06);
    border-color: rgba(0, 0, 0, 0.15);
}

body.dark-mode .wiki-tool-btn:hover {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.18);
}

.wiki-editor-textarea {
    width: 100%;
    border: 0;
    padding: 14px;
    resize: vertical;
    background: transparent;
    color: inherit;
    font-family: monospace;
    font-size: 0.95em;
    line-height: 1.5;
    outline: none;
    min-height: 420px;
}

.wiki-editor-title {
    width: 100%;
    border: 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    padding: 12px 14px;
    background: transparent;
    color: inherit;
    font-family: var(--font-ui);
    font-size: 1.2em;
    font-weight: bold;
    outline: none;
}

body.dark-mode .wiki-editor-title {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}

.wiki-editor-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    padding: 10px 12px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}

body.dark-mode .wiki-editor-actions {
    border-top-color: rgba(255, 255, 255, 0.1);
}

.wiki-editor-status {
    margin-right: auto;
    font-size: 0.88em;
    opacity: 0.75;
}

@media (max-width: 720px) {
    .wiki-infobox {
        float: none;
        width: auto;
        margin: 0 0 18px 0;
    }
}

.pages-header {
    justify-content: space-between;
    gap: 12px;
}

.pages-empty {
    grid-column: 1 / -1;
    text-align: center;
    padding: 40px 20px;
    opacity: 0.6;
    font-size: 0.95em;
}

.page-form-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.page-form-label {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-weight: bold;
    font-size: 0.95em;
}

.page-form-hint {
    font-size: 0.82em;
    opacity: 0.65;
    line-height: 1.4;
}

.pieces-index {
    display: column;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

.pieces-index-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 14px 16px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
    background: transparent;
}

body.dark-mode .pieces-index-card {
    border-color: rgba(255, 255, 255, 0.15);
}

.pieces-index-card:hover {
    border-color: rgba(0, 0, 0, 0.4);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}

body.dark-mode .pieces-index-card:hover {
    border-color: rgba(255, 255, 255, 0.5);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

.pieces-index-kanji {
    font-size: 1.8em;
    line-height: 1;
    opacity: 0.9;
}

.pieces-index-label {
    font-weight: bold;
    font-size: 1em;
}

.pieces-index-kanji.promoted {
    color: #cc0000;
}

body.dark-mode .pieces-index-kanji.promoted,
body.dark-mode .wiki-kanji.promoted,
body.dark-mode .piece-tooltip-kanji.promoted {
    color: #ff5252;
}

.wiki-kanji.promoted,
.piece-tooltip-kanji.promoted {
    color: #cc0000;
}

.pieces-index-move {
    font-size: 0.85em;
    opacity: 0.7;
    line-height: 1.4;
}

.support-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.support-card {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    text-decoration: none;
    color: inherit;
    background: transparent;
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

body.dark-mode .support-card {
    border-color: rgba(255, 255, 255, 0.15);
}

a.support-card:hover {
    border-color: rgba(0, 0, 0, 0.4);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}

body.dark-mode a.support-card:hover {
    border-color: rgba(255, 255, 255, 0.5);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

.support-card-icon {
    width: 56px;
    height: 56px;
    object-fit: contain;
    flex: 0 0 auto;
    border-radius: 6px;
}

.support-card-info {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.support-card-name {
    font-weight: bold;
    font-size: 1em;
}

.support-card-desc {
    font-size: 0.85em;
    opacity: 0.7;
    line-height: 1.4;
}

.support-card-link {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 8px;
    color: inherit;
    opacity: 0.65;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.support-card-link:hover {
    opacity: 1;
    background-color: rgba(0, 0, 0, 0.06);
}

body.dark-mode .support-card-link:hover {
    background-color: rgba(255, 255, 255, 0.08);
}

.settings-page {
    padding: 24px 28px 60px;
    max-width: 880px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 28px;
}

.settings-page-title {
    text-align: center;
    margin: 0;
    font-size: 2em;
    font-weight: bold;
    line-height: 1.2;
}

.settings-page-title::after {
    content: '';
    display: block;
    border-top: 1px solid rgba(0, 0, 0, 0.12);
    margin: 18px 0 0;
}

body.dark-mode .settings-page-title::after {
    border-top-color: rgba(255, 255, 255, 0.15);
}

.settings-section {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 0;
    border: none;
    border-radius: 0;
}

body.dark-mode .settings-section {
    border: none;
}

.settings-section + .settings-section {
    padding-top: 24px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}

body.dark-mode .settings-section + .settings-section {
    border-top-color: rgba(255, 255, 255, 0.1);
}

.settings-section-title {
    margin: 0;
    font-size: 1.25em;
    font-weight: bold;
    letter-spacing: 0.01em;
}

.settings-section-hint {
    margin: 0;
    font-size: 0.92em;
    opacity: 0.75;
    line-height: 1.55;
    max-width: 640px;
}

/* --- The welcome screen ----------------------------------------------
   A page, not a modal: the same groups as preferences, numbered, under a
   board that wears each choice as it is made. */
.welcome-intro {
    margin: 0;
    max-width: 640px;
    font-size: 1.02em;
    line-height: 1.55;
    opacity: 0.85;
}
.welcome-preview { margin: 0; }
.welcome-board-wrap { max-width: 300px; margin: 0 auto; }
.welcome-step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    margin-right: 10px;
    border-radius: 50%;
    background: var(--c-accent);
    color: var(--c-on-accent);
    font-size: 0.72em;
    font-weight: 700;
    vertical-align: middle;
}
.welcome-actions {
    display: flex;
    justify-content: flex-end;
    padding-top: 8px;
}
.welcome-finish {
    border: 1px solid var(--c-accent);
    background: var(--c-accent);
    color: var(--c-on-accent);
    border-radius: var(--radius-pill);
    padding: 10px 28px;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.12s ease;
}
.welcome-finish:hover { background: var(--c-accent-hover); border-color: var(--c-accent-hover); }
.welcome-finish[disabled] { opacity: 0.6; cursor: default; }

/* Rated or not: two options that explain themselves, on the welcome screen
   and on the preferences page alike. */
.rating-choice-option { align-items: flex-start; }
.rating-choice-option input[type="radio"] { margin-top: 3px; }
.rating-choice-option input[type="radio"][disabled] { opacity: 0.45; cursor: default; }
.rating-choice-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.rating-choice-desc {
    font-size: 0.85em;
    font-weight: 400;
    line-height: 1.45;
    opacity: 0.75;
}
.rating-choice-login { margin-top: 2px; }
.settings-redo { font-size: 0.92em; }

.settings-section-status {
    margin: 4px 0 0;
    font-size: 0.85em;
    color: #b91c1c;
    line-height: 1.4;
}
.settings-section-status:empty { display: none; }
body.dark-mode .settings-section-status { color: #f87171; }

.settings-toggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    user-select: none;
    margin-top: 4px;
}

.settings-toggle input[type="checkbox"] {
    appearance: none;
    -webkit-appearance: none;
    width: 38px;
    height: 22px;
    border-radius: 999px;
    background-color: rgba(0, 0, 0, 0.15);
    position: relative;
    cursor: pointer;
    transition: background-color 0.2s ease;
    margin: 0;
}

.settings-toggle input[type="checkbox"]::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background-color: #fff;
    transition: transform 0.2s ease;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

.settings-toggle input[type="checkbox"]:checked {
    background-color: #2ecc71;
}

.settings-toggle input[type="checkbox"]:checked::after {
    transform: translateX(16px);
}

body.dark-mode .settings-toggle input[type="checkbox"] {
    background-color: rgba(255, 255, 255, 0.18);
}

body.dark-mode .settings-toggle input[type="checkbox"]:checked {
    background-color: #2ecc71;
}

.translation-modal .modal-dialog {
    max-width: 540px;
    width: 92%;
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 22px 24px;
}

.translation-modal-title {
    margin: 0;
    font-size: 1.15em;
    font-weight: bold;
}

.translation-modal-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.translation-modal-field label {
    font-size: 0.82em;
    opacity: 0.75;
}

.translation-modal-field input,
.translation-modal-field select,
.translation-modal-field textarea {
    background-color: transparent;
    color: inherit;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 8px;
    padding: 8px 10px;
    font: inherit;
    outline: none;
    transition: border-color 0.15s ease;
}

.translation-modal-field textarea {
    min-height: 140px;
    resize: vertical;
    line-height: 1.45;
}

body.dark-mode .translation-modal-field input,
body.dark-mode .translation-modal-field select,
body.dark-mode .translation-modal-field textarea {
    border-color: rgba(255, 255, 255, 0.18);
}

.translation-modal-field input:focus,
.translation-modal-field select:focus,
.translation-modal-field textarea:focus {
    border-color: rgba(0, 0, 0, 0.4);
}

body.dark-mode .translation-modal-field input:focus,
body.dark-mode .translation-modal-field select:focus,
body.dark-mode .translation-modal-field textarea:focus {
    border-color: rgba(255, 255, 255, 0.5);
}

.translation-modal-status {
    font-size: 0.85em;
    opacity: 0.7;
    min-height: 1.2em;
}

.translation-modal-actions {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 10px;
}

.translation-modal-actions .translation-modal-delete {
    margin-right: auto;
    background: none;
    border: none;
    color: #e74c3c;
    cursor: pointer;
    font: inherit;
    padding: 6px 8px;
    border-radius: 6px;
}

.translation-modal-actions .translation-modal-delete:hover {
    background-color: rgba(231, 76, 60, 0.12);
}

.feed-action-translate {
    color: inherit;
}

.feed-item-translated-tag,
.wiki-translated-tag {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 999px;
    font-size: 0.7em;
    font-weight: normal;
    background-color: rgba(0, 0, 0, 0.08);
    opacity: 0.8;
    vertical-align: middle;
}

body.dark-mode .feed-item-translated-tag,
body.dark-mode .wiki-translated-tag {
    background-color: rgba(255, 255, 255, 0.12);
}

.sidebar-header {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
}

body.dark-mode .sidebar-header > img,
body.dark-mode .leftdiv .sidebar-logo img {
    filter: invert(1) hue-rotate(180deg);
}

.sidebar-theme-toggle {
    background: transparent;
    border: 1px solid rgba(0, 0, 0, 0.15);
    color: inherit;
    cursor: pointer;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

body.dark-mode .sidebar-theme-toggle {
    border-color: rgba(255, 255, 255, 0.2);
}

.sidebar-theme-toggle:hover {
    background-color: rgba(0, 0, 0, 0.05);
}

body.dark-mode .sidebar-theme-toggle:hover {
    background-color: rgba(255, 255, 255, 0.06);
}

.sidebar-theme-toggle svg {
    display: block;
}

/* --- Wiki editor role gating --- */
body .wiki-editor-only { display: none; }
body.is-wiki-editor .wiki-editor-only { display: inline-flex; }
body .wiki-submitter-only { display: none; }
body.is-logged-in:not(.is-wiki-editor) .wiki-submitter-only { display: inline-flex; }

.wiki-castle-modal {
    position: fixed; inset: 0;
    display: flex; align-items: center; justify-content: center;
    z-index: 50;
}
.wiki-castle-modal[hidden] { display: none; }
.wiki-castle-modal-backdrop {
    position: absolute; inset: 0;
    background: rgba(0,0,0,0.45);
    cursor: pointer;
}
.wiki-castle-modal-card {
    position: relative;
    background: #fff; color: #1d1f23;
    padding: 22px 24px 18px;
    border-radius: 12px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.25);
    max-width: 460px;
    width: calc(100% - 40px);
    max-height: calc(100vh - 60px);
    overflow-y: auto;
}
body.dark-mode .wiki-castle-modal-card {
    background: #2c2e34; color: #f5f5f5;
}
.wiki-castle-modal-close {
    position: absolute;
    top: 6px; right: 10px;
    background: transparent; border: none;
    font-size: 1.5rem;
    color: inherit;
    cursor: pointer;
    opacity: 0.55;
    line-height: 1; padding: 4px 8px;
}
.wiki-castle-modal-close:hover { opacity: 1; }
.wiki-castle-editor-title { margin: 0 0 6px; font-size: 1.25em; font-weight: bold; }
.wiki-castle-editor-hint { margin: 0 0 16px; font-size: 0.92em; opacity: 0.75; line-height: 1.55; max-width: 640px; }
.wiki-castle-editor-board {
    display: grid;
    grid-template-columns: repeat(9, 1fr);
    grid-template-rows: repeat(9, 1fr);
    width: min(360px, 100%);
    aspect-ratio: 1 / 1;
    border: 1.5px solid #000;
    margin: 0 auto 14px;
    background: #fff;
}
body.dark-mode .wiki-castle-editor-board { border-color: #f5f5f5; background: #1f1d1d; }
.wiki-castle-editor-cell {
    border: 0.5px solid rgba(0, 0, 0, 0.5);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    user-select: none;
    transition: background-color 0.1s ease;
}
body.dark-mode .wiki-castle-editor-cell { border-color: rgba(245, 245, 245, 0.4); }
.wiki-castle-editor-cell:hover { background: rgba(46, 204, 113, 0.12); }
.wiki-castle-editor-piece {
    font-family: var(--font-kanji);
    font-size: clamp(0.8rem, 3vw, 1.4rem);
    font-weight: 700;
    line-height: 1;
}
.wiki-castle-editor-piece-promoted { color: #b91c1c; }
body.dark-mode .wiki-castle-editor-piece-promoted { color: #f87171; }
.wiki-castle-editor-palette {
    display: flex; flex-wrap: wrap; gap: 6px;
    margin-bottom: 14px;
    justify-content: center;
}
.wiki-castle-editor-palette-btn {
    width: 36px; height: 36px;
    padding: 0;
    border: 1px solid rgba(0, 0, 0, 0.3);
    background: #fff;
    color: #000;
    border-radius: 50%;
    cursor: pointer;
    font-family: var(--font-kanji);
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1;
    display: inline-flex; align-items: center; justify-content: center;
    transition: border-color 0.12s ease, background-color 0.12s ease;
}
.wiki-castle-editor-palette-btn:hover { border-color: #000; }
.wiki-castle-editor-palette-btn-active { border-color: #000; background: rgba(0, 0, 0, 0.06); }
body.dark-mode .wiki-castle-editor-palette-btn {
    background: #1f1d1d; color: #f5f5f5; border-color: rgba(255, 255, 255, 0.3);
}
body.dark-mode .wiki-castle-editor-palette-btn:hover { border-color: #f5f5f5; }
body.dark-mode .wiki-castle-editor-palette-btn-active { border-color: #f5f5f5; background: rgba(255, 255, 255, 0.08); }
.wiki-castle-editor-palette-eraser { font-size: 1.3rem; opacity: 0.7; }
.wiki-castle-editor-actions { display: flex; gap: 8px; align-items: center; justify-content: center; }
.wiki-castle-editor-btn {
    padding: 8px 16px;
    border: 1px solid rgba(0, 0, 0, 0.3);
    background: transparent;
    color: inherit;
    border-radius: 6px;
    cursor: pointer;
    font: inherit;
}
.wiki-castle-editor-btn:hover { border-color: #000; }
body.dark-mode .wiki-castle-editor-btn { border-color: rgba(255, 255, 255, 0.3); }
body.dark-mode .wiki-castle-editor-btn:hover { border-color: #f5f5f5; }
.wiki-castle-editor-btn-primary { background: #000; color: #fff; border-color: #000; }
.wiki-castle-editor-btn-primary:hover { background: rgba(0, 0, 0, 0.85); }
body.dark-mode .wiki-castle-editor-btn-primary { background: #f5f5f5; color: #000; border-color: #f5f5f5; }
body.dark-mode .wiki-castle-editor-btn-primary:hover { background: rgba(245, 245, 245, 0.85); }
.wiki-castle-editor-status { margin: 10px 0 0; font-size: 0.92em; opacity: 0.8; }
.wiki-castle-editor-status-error { color: #b91c1c; opacity: 1; }
body.dark-mode .wiki-castle-editor-status-error { color: #f87171; }
body .logged-in-only { display: none; }
body.is-logged-in .logged-in-only { display: inline-flex; }
body.is-logged-in .logged-out-only { display: none; }

/* --- Wiki draft (new page) --- */
body[data-page-draft] .wiki-article {
    padding: 24px 8px;
    max-width: 980px;
}
.wiki-draft.wiki-editor {
    border: 0;
    background: transparent;
    border-radius: 0;
    margin-top: 28px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 18px;
    overflow: visible;
}
.wiki-draft .page-form-field { gap: 4px; }
.wiki-draft .page-form-label {
    font-weight: bold;
    font-size: 0.95em;
    font-family: var(--font-ui);
    flex-direction: row;
    align-items: center;
    gap: 8px;
}
.wiki-draft .page-form-icon {
    flex-shrink: 0;
    opacity: 0.75;
}
.wiki-draft .modal-lishogi-input {
    width: 100%;
    box-sizing: border-box;
    padding: 14px 0;
    border: 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 0;
    background: transparent;
    color: inherit;
    font-family: var(--font-ui);
    font-size: 1em;
    outline: none;
}
body.dark-mode .wiki-draft .modal-lishogi-input {
    border-bottom-color: rgba(255, 255, 255, 0.18);
}
.wiki-draft .modal-lishogi-input:focus {
    border-bottom-color: rgba(0, 0, 0, 0.4);
}
body.dark-mode .wiki-draft .modal-lishogi-input:focus {
    border-bottom-color: rgba(255, 255, 255, 0.5);
}
.wiki-draft .inline-md-editor {
    border-radius: 4px;
    margin-top: 0;
}
.wiki-draft .wiki-editor-textarea { min-height: 320px; }
.wiki-draft .wiki-editor-tags {
    border-top: 0;
    padding: 0;
    flex-wrap: wrap;
    align-items: center;
}
.wiki-draft .wiki-editor-actions {
    border-top: 0;
    padding: 0;
    margin-top: 4px;
}
.wiki-draft-login-prompt {
    margin-top: 16px;
    padding: 16px;
    border: 1px dashed rgba(0, 0, 0, 0.2);
    border-radius: 4px;
    text-align: center;
}
body.dark-mode .wiki-draft-login-prompt { border-color: rgba(255, 255, 255, 0.22); }

/* --- Wiki review queue --- */
.review-card-link {
    text-decoration: none;
}
.review-card-target {
    font-size: 0.82em;
    opacity: 0.6;
    font-family: monospace;
}
.review-card-resolution {
    font-size: 0.82em;
    opacity: 0.75;
    margin-top: 2px;
}
.review-card-resolution-approved { color: #1f8a4d; }
.review-card-resolution-rejected { color: #b53324; }
body.dark-mode .review-card-resolution-approved { color: #6ee7a4; }
body.dark-mode .review-card-resolution-rejected { color: #ff8a7e; }

.review-detail-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
    margin: 8px 0 16px;
    font-size: 0.9em;
    opacity: 0.85;
}
.review-detail-target {
    font-family: monospace;
    color: inherit;
}
.review-detail-submitter { margin-left: auto; opacity: 0.8; }
.review-detail-resolution {
    margin: 10px 0;
    font-size: 0.95em;
    padding: 8px 12px;
    border-radius: 6px;
}
.review-detail-resolution-approved {
    background-color: rgba(46, 204, 113, 0.12);
    color: #1f8a4d;
}
.review-detail-resolution-rejected {
    background-color: rgba(231, 76, 60, 0.12);
    color: #b53324;
}
body.dark-mode .review-detail-resolution-approved { color: #6ee7a4; }
body.dark-mode .review-detail-resolution-rejected { color: #ff8a7e; }
.review-detail-note {
    font-style: italic;
    opacity: 0.85;
    margin: -6px 0 14px;
    font-size: 0.9em;
}
.review-detail-current {
    margin-top: 36px;
    padding-top: 24px;
    border-top: 1px dashed rgba(0, 0, 0, 0.18);
}
body.dark-mode .review-detail-current { border-top-color: rgba(255, 255, 255, 0.22); }
.review-detail-current-title {
    font-size: 1.1em;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    opacity: 0.7;
    margin: 0 0 12px;
}
.review-detail-current-page-title { opacity: 0.85; }

.review-action-approve {
    color: #1f8a4d;
    border-color: #2ecc71;
}
.review-action-approve:hover {
    background-color: rgba(46, 204, 113, 0.18);
}
.review-action-reject {
    color: #b53324;
    border-color: #e74c3c;
}
.review-action-reject:hover {
    background-color: rgba(231, 76, 60, 0.18);
}
body.dark-mode .review-action-approve { color: #6ee7a4; }
body.dark-mode .review-action-reject { color: #ff8a7e; }

/* --- Wiki upvote button --- */
.wiki-upvote-btn {
    width: auto !important;
    padding: 0 12px !important;
    gap: 4px;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    height: 36px;
    border-radius: 18px !important;
    transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.wiki-upvote-btn:hover { color: #2ecc71; border-color: #2ecc71; }
.wiki-upvote-btn.active { color: #2ecc71; border-color: #2ecc71; }
.wiki-upvote-glyph {
    font-family: var(--font-kanji);
    font-size: 16px;
    line-height: 1;
}
.wiki-upvote-count { font-size: 0.85em; line-height: 1; }

/* --- Wiki tag chips --- */
.wiki-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    justify-content: center;
    margin: 6px 0 14px;
}
.wiki-tags[hidden] { display: none; }

.wiki-tags .wiki-tag-chip {
    font-size: 0.92em;
    gap: 4px;
}

.wiki-tag-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    height: 26px;
    border-radius: 999px;
    font-family: var(--font-kanji);
    font-size: 0.85em;
    font-weight: normal;
    line-height: 1;
    color: inherit;
    border: 1px solid transparent;
    user-select: none;
}

.wiki-tag-beginner { color: #1f8a4d; }
.wiki-tag-advanced {  color: #b53324; }
.wiki-tag-variant  {  color: #7d3da3; }
.wiki-tag-yagura   {  color: #2c6fb5; }
.wiki-tag-mino     {  color: #c0883f; }
.wiki-tag-ibisha   {  color: #0f8a8a; }
.wiki-tag-furibisha {  color: #c0398a; }
body.dark-mode .wiki-tag-beginner { color: #6ee7a4; }
body.dark-mode .wiki-tag-advanced { color: #ff8a7e; }
body.dark-mode .wiki-tag-variant  { color: #d6a6ee; }
body.dark-mode .wiki-tag-yagura   { color: #8cb8ec; }
body.dark-mode .wiki-tag-mino     { color: #f0c98a; }
body.dark-mode .wiki-tag-ibisha    { color: #5fd0d0; }
body.dark-mode .wiki-tag-furibisha { color: #ef9fd0; }

.wiki-tag-toggle {
    cursor: pointer;
    background-color: transparent;
    border: 1px solid rgba(0, 0, 0, 0.2);
    color: inherit;
    font: inherit;
    opacity: 0.65;
    transition: opacity 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}
body.dark-mode .wiki-tag-toggle { border-color: rgba(255, 255, 255, 0.22); }
.wiki-tag-toggle:hover { opacity: 1; }
.wiki-tag-toggle.active { opacity: 1; }
.wiki-tag-toggle.wiki-tag-beginner.active { background-color: rgba(46, 204, 113, 0.22); border-color: #2ecc71; }
.wiki-tag-toggle.wiki-tag-advanced.active { background-color: rgba(231, 76, 60, 0.22); border-color: #e74c3c; }
.wiki-tag-toggle.wiki-tag-variant.active  { background-color: rgba(155, 89, 182, 0.22); border-color: #9b59b6; }
.wiki-tag-toggle.wiki-tag-yagura.active   { background-color: rgba(52, 152, 219, 0.22); border-color: #3498db; }
.wiki-tag-toggle.wiki-tag-mino.active     { background-color: rgba(230, 169, 80, 0.22); border-color: #e6a950; }
.wiki-tag-toggle.wiki-tag-ibisha.active    { background-color: rgba(15, 138, 138, 0.22); border-color: #14b8a6; }
.wiki-tag-toggle.wiki-tag-furibisha.active { background-color: rgba(192, 57, 138, 0.22); border-color: #d6549e; }

.wiki-editor-tags {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}
body.dark-mode .wiki-editor-tags { border-top-color: rgba(255, 255, 255, 0.1); }
.wiki-editor-tags-label {
    font-size: 0.85em;
    opacity: 0.7;
    margin-right: 4px;
}

.wiki-editor-description {
    width: 100%;
    border: 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    padding: 8px 14px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 0.95em;
    line-height: 1.4;
    resize: vertical;
    outline: none;
    min-height: 48px;
    opacity: 0.9;
}
body.dark-mode .wiki-editor-description { border-bottom-color: rgba(255, 255, 255, 0.1); }

/* --- Translation menu (per-page lang viewer) --- */
.wiki-toolbar-actions { position: relative; }
.wiki-lang-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 60;
    min-width: 200px;
    background-color: #ffffff;
    color: #000;
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 10px;
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.15);
    padding: 4px;
    display: flex;
    flex-direction: column;
}
body.dark-mode .wiki-lang-menu {
    background-color: #2e2b2b;
    color: #fff;
    border-color: rgba(255, 255, 255, 0.12);
}
.wiki-lang-menu-item {
    background: transparent;
    border: none;
    color: inherit;
    text-align: left;
    padding: 8px 10px;
    border-radius: 6px;
    font: inherit;
    cursor: pointer;
}
.wiki-lang-menu-item:hover { background-color: rgba(0, 0, 0, 0.06); }
body.dark-mode .wiki-lang-menu-item:hover { background-color: rgba(255, 255, 255, 0.08); }
.wiki-lang-menu-item.active { font-weight: 600; background-color: rgba(0, 0, 0, 0.04); }
body.dark-mode .wiki-lang-menu-item.active { background-color: rgba(255, 255, 255, 0.06); }
.wiki-lang-menu-empty {
    padding: 8px 10px;
    font-size: 0.85em;
    opacity: 0.65;
}
.wiki-lang-menu-sep {
    height: 1px;
    background-color: rgba(0, 0, 0, 0.08);
    margin: 4px 2px;
}
body.dark-mode .wiki-lang-menu-sep { background-color: rgba(255, 255, 255, 0.1); }

/* --- Pieces / pages popular section --- */
.pieces-section-title {
    margin: 18px 16px 8px;
    font-size: 0.95em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    opacity: 0.6;
}
.pieces-index-popular {
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
body.dark-mode .pieces-index-popular { border-bottom-color: rgba(255, 255, 255, 0.08); }

.pieces-index-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 2px;
}
.pieces-index-label {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    width: 100%;
}
.pieces-index-name {
    font-weight: bold;
    flex: 1 1 auto;
    min-width: 0;
}
.pieces-index-chips {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}
.pieces-index-bottom {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    width: 100%;
}
.pieces-index-bottom .pieces-index-move {
    flex: 1 1 auto;
    min-width: 0;
}
.pieces-index-upvotes {
    margin-left: auto;
    flex-shrink: 0;
    font-size: 0.85em;
    opacity: 0.7;
    font-family: var(--font-kanji);
    white-space: nowrap;
}
.pieces-index-creator {
    width: 100%;
    margin-top: 6px;
    font-size: 0.8em;
    opacity: 0.6;
    font-style: italic;
}

/* --- Wiki listing filter bar --- */
.wiki-filter {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
body.dark-mode .wiki-filter { border-bottom-color: rgba(255, 255, 255, 0.08); }

.wiki-filter-search {
    flex: 1 1 200px;
    min-width: 0;
    background-color: transparent;
    color: inherit;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 999px;
    padding: 8px 14px;
    font: inherit;
    font-size: 0.95em;
    outline: none;
    transition: border-color 0.15s ease;
}
body.dark-mode .wiki-filter-search { border-color: rgba(255, 255, 255, 0.18); }
.wiki-filter-search:focus { border-color: rgba(0, 0, 0, 0.4); }
body.dark-mode .wiki-filter-search:focus { border-color: rgba(255, 255, 255, 0.5); }

.wiki-filter-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.wiki-filter-select {
    flex: 0 0 auto;
    background-color: transparent;
    color: inherit;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 999px;
    padding: 8px 32px 8px 14px;
    font: inherit;
    font-size: 0.95em;
    cursor: pointer;
    outline: none;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 14px;
    transition: border-color 0.15s ease;
}
body.dark-mode .wiki-filter-select {
    border-color: rgba(255, 255, 255, 0.18);
    background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23bbb' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}
.wiki-filter-select:focus { border-color: rgba(0, 0, 0, 0.4); }
body.dark-mode .wiki-filter-select:focus { border-color: rgba(255, 255, 255, 0.5); }
.wiki-filter-select option { background-color: #ffffff; color: #000; }
body.dark-mode .wiki-filter-select option { background-color: #2e2b2b; color: #fff; }

.pages-create-btn {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    padding: 0;
    background: transparent;
    border: 1px solid rgba(0, 0, 0, 0.2);
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}
body.dark-mode .pages-create-btn { border-color: rgba(255, 255, 255, 0.22); }
.pages-create-btn:hover {
    background-color: rgba(0, 0, 0, 0.05);
    border-color: currentColor;
}
body.dark-mode .pages-create-btn:hover { background-color: rgba(255, 255, 255, 0.06); }
.pages-create-btn svg { display: block; }

.feed-loading-more {
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(0, 0, 0, 0.4);
}
body.dark-mode .feed-loading-more { color: rgba(255, 255, 255, 0.4); }
.feed-loading-more.is-loading::after {
    content: '';
    width: 18px;
    height: 18px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: kletka-spin 0.8s linear infinite;
}
@keyframes kletka-spin { to { transform: rotate(360deg); } }

.wiki-title-kanji {
    font-size: 0.85em;
    font-weight: 500;
    color: rgba(0, 0, 0, 0.6);
    margin-left: 4px;
}
body.dark-mode .wiki-title-kanji { color: rgba(255, 255, 255, 0.6); }
.wiki-aliases { display: none; }

/* Toasts */
.toast-container {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column-reverse;
    gap: 8px;
    z-index: 9999;
    pointer-events: none;
    width: max-content;
    max-width: calc(100vw - 32px);
}
.toast {
    pointer-events: auto;
    background: rgba(28, 30, 36, 0.96);
    color: #f5f5f5;
    padding: 10px 16px;
    border-radius: 10px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.28);
    font-size: 0.92rem;
    line-height: 1.35;
    max-width: 360px;
    cursor: pointer;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.18s ease, transform 0.18s ease;
}
body.dark-mode .toast {
    background: rgba(245, 245, 245, 0.95);
    color: #1d1f23;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.5);
}
.toast.toast-in { opacity: 1; transform: translateY(0); }
.toast.toast-out { opacity: 0; transform: translateY(-4px); }
.toast-title {
    font-weight: 600;
    margin-bottom: 4px;
    font-size: 0.95rem;
}
.toast-body { font-size: 0.9rem; }
.toast-success { background: #166534; color: #fff; }
.toast-error { background: #991b1b; color: #fff; }
body.dark-mode .toast-success { background: #22c55e; color: #052e16; }
body.dark-mode .toast-error { background: #f87171; color: #4c0519; }

/* ---- Play (Shogi matches) ---- */
.page-title-tag { font-weight: 400; opacity: 0.55; font-size: 0.7em; margin-left: 6px; }
.pages-header-actions { display: inline-flex; align-items: center; gap: 6px; }
.play-lead {
    margin: 12px 16px 14px;
    opacity: 0.7;
    font-size: 0.92rem;
    line-height: 1.45;
    max-width: 640px;
}

.play-modal-dialog { width: min(420px, 100%); }
.play-modal-dialog .modal-body { gap: 14px; }
.play-modal-title {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.play-modal-title-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.06);
    color: inherit;
    flex-shrink: 0;
}
body.dark-mode .play-modal-title-icon { background: rgba(255, 255, 255, 0.08); }
.play-modal-hint {
    margin: 0;
    font-size: 0.9rem;
    opacity: 0.75;
    line-height: 1.4;
    display: flex;
    align-items: flex-start;
    gap: 8px;
}
.play-modal-hint-icon { flex-shrink: 0; margin-top: 2px; }
.play-modal-search {
    position: relative;
    display: flex;
    align-items: center;
}
.play-modal-search-icon {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    opacity: 0.55;
}
.play-modal-search > .play-modal-input.wiki-filter-search { padding-left: 32px; }
.play-modal-input.wiki-filter-search {
    width: 100%;
    box-sizing: border-box;
    padding: 6px 12px;
    font-size: 0.88rem;
    border-radius: 6px;
    flex: none;
}

.play-icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    padding: 0;
    border: none;
    background: transparent;
    color: inherit;
    border-radius: 50%;
    cursor: pointer;
    opacity: 0.7;
    text-decoration: none;
    flex-shrink: 0;
    transition: opacity 0.12s ease, background-color 0.12s ease;
}
.play-icon-btn:hover { background: rgba(0,0,0,0.07); opacity: 1; }
body.dark-mode .play-icon-btn:hover { background: rgba(255,255,255,0.08); }
.play-icon-btn[hidden] { display: none; }
.play-icon-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.play-icon-btn-busy svg { animation: play-icon-spin 1.2s linear infinite; }
@keyframes play-icon-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

.play-share {
    display: flex; align-items: center; gap: 4px;
    padding: 6px 8px 6px 12px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 6px;
}
body.dark-mode .play-share { border-color: rgba(255, 255, 255, 0.15); }
.play-share[hidden] { display: none; }
.play-share-icon { flex-shrink: 0; opacity: 0.55; }
.play-share-input {
    flex: 1; min-width: 0;
    padding: 6px 4px;
    border: none;
    background: transparent;
    color: inherit;
    font-size: 0.92rem;
    outline: none;
}

.play-invite-form { position: relative; }
.play-invite-form > .wiki-filter-search { width: 100%; box-sizing: border-box; }
.play-invite-results {
    list-style: none; margin: 8px 0 0; padding: 0;
    max-height: 280px; overflow-y: auto;
    border: 1px solid rgba(0, 0, 0, 0.12);
}
body.dark-mode .play-invite-results { border-color: rgba(255, 255, 255, 0.15); }
.play-invite-results[hidden] { display: none; }
.play-invite-result {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 12px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
body.dark-mode .play-invite-result { border-bottom-color: rgba(255, 255, 255, 0.08); }
.play-invite-result:last-child { border-bottom: none; }
.play-invite-avatar { width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0; }
.play-invite-name { flex: 1; font-size: 0.95rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.play-invite-btn {
    width: 32px; height: 32px;
    border: none; background: transparent; color: inherit;
    border-radius: 50%; cursor: pointer; opacity: 0.65;
    display: inline-flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}
.play-invite-btn:hover { opacity: 1; background: rgba(0,0,0,0.06); }
body.dark-mode .play-invite-btn:hover { background: rgba(255,255,255,0.08); }
.play-invite-empty { padding: 10px 12px; opacity: 0.6; font-size: 0.92rem; }

.play-recent-card { gap: 10px; }
.play-recent-players {
    display: flex; align-items: center; gap: 8px;
    flex-wrap: wrap;
    width: 100%;
}
.play-recent-avatar { width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0; }
.play-recent-name {
    font-weight: 600; font-size: 0.95rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    min-width: 0;
}
.play-recent-vs { font-size: 0.85rem; opacity: 0.5; }
.play-recent-meta { display: flex; align-items: center; gap: 8px; }
.play-recent-chip {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    opacity: 0.7;
}
.play-recent-chip-active { color: #166534; opacity: 1; }
body.dark-mode .play-recent-chip-active { color: #4ade80; }
.play-recent-chip-finished { opacity: 0.55; }
.play-recent-chip-waiting { opacity: 0.55; font-style: italic; text-transform: none; letter-spacing: 0; }

/* Match room */
.content-play {
    /* The anchor for the floating back arrow. */
    position: relative;
    padding-bottom: 30px;
    display: flex;
    flex-direction: column;
}
.content-play .play-history-section { margin-top: auto; }
/* What replaced the play room's top bar: a floating way back, a chips row
   with height only while a chip is showing, and the old bar's buttons on
   the move-list title. */
.play-back-float { position: absolute; top: 8px; left: 8px; z-index: 40; }
.play-room-chips { display: flex; align-items: center; justify-content: center; gap: 12px; flex-wrap: wrap; padding: 0 56px; }
.play-history-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.play-history-head .play-history-title { margin: 0; }
/* An empty status line must not hand the chips row a line box. */
.play-status:empty { display: none; }
/* The chips set their own display (inline-flex), which outranks the UA rule
   for the hidden attribute; said explicitly, so a hidden chip is truly gone
   and the empty row keeps no height. */
.play-room-chips > [hidden] { display: none; }
.play-room-actions { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.play-spectators {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 0.85rem;
    opacity: 0.7;
}
.play-spectators[hidden] { display: none; }
.play-status { font-size: 0.95rem; opacity: 0.85; }

.play-room {
    display: grid;
    /* minmax(0, 1fr), not auto: an auto column takes the widest row's
       max-content, and a long player name would have carried the board
       past the edge of the screen with it. */
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr auto;
    gap: 10px;
    align-items: center;
    justify-items: center;
    margin-top: 12px;
}
.play-side { width: 100%; max-width: 540px; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.play-player {
    display: flex; align-items: center; gap: 10px;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: 0;
    position: relative;
}
.play-speech-bubble {
    position: absolute;
    left: 0;
    background: #fff;
    color: #000;
    border: 1px solid #000;
    border-radius: 14px;
    padding: 6px 12px;
    font-family: var(--font-kanji);
    font-size: 0.95rem;
    line-height: 1.2;
    max-width: 260px;
    word-break: break-word;
    z-index: 5;
    pointer-events: none;
    opacity: 0;
    transform: translateY(4px);
    transition: opacity 0.25s ease, transform 0.25s ease;
}
.play-speech-bubble.play-speech-show {
    opacity: 1;
    transform: translateY(0);
}
.play-side-top .play-speech-bubble { top: calc(100% + 10px); }
.play-side-bottom .play-speech-bubble { bottom: calc(100% + 10px); }
.play-speech-bubble::after {
    content: '';
    position: absolute;
    width: 10px;
    height: 10px;
    background: #fff;
    transform: rotate(45deg);
    left: 16px;
}
.play-side-top .play-speech-bubble::after {
    top: -6px;
    border-top: 1px solid #000;
    border-left: 1px solid #000;
}
.play-side-bottom .play-speech-bubble::after {
    bottom: -6px;
    border-bottom: 1px solid #000;
    border-right: 1px solid #000;
}
body.dark-mode .play-speech-bubble {
    background: #1f1d1d;
    color: #f5f5f5;
    border-color: #f5f5f5;
}
body.dark-mode .play-speech-bubble::after {
    background: #1f1d1d;
    border-color: #f5f5f5;
}
.play-player-avatar {
    width: 36px; height: 36px;
    border-radius: 50%;
    object-fit: cover;
    background: rgba(0,0,0,0.06);
    flex-shrink: 0;
}
body.dark-mode .play-player-avatar { background: rgba(255,255,255,0.08); }
.play-player-active .play-player-avatar {
    box-shadow: 0 0 0 2px #000;
}
body.dark-mode .play-player-active .play-player-avatar {
    box-shadow: 0 0 0 2px #f5f5f5;
}
.play-player-empty .play-player-avatar { opacity: 0.45; }
.play-player-info { display: flex; flex-direction: column; line-height: 1.2; }
.play-player-name { font-weight: 600; font-size: 0.95rem; }
.play-player-role { font-size: 0.78rem; opacity: 0.6; }
.play-player-clock {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 0.95rem;
    font-weight: 600;
    margin-top: 2px;
    opacity: 0.7;
}
.play-player-clock-running { opacity: 1; }
.play-player-clock-low { color: #b91c1c; }
body.dark-mode .play-player-clock-low { color: #f87171; }
.play-player-clock[hidden] { display: none; }

.play-time-control {
    position: relative;
    display: block;
    margin: 4px 0 12px;
    font-size: 0.92rem;
    width: 100%;
}
.play-time-control-label {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    opacity: 0.65;
    display: inline-flex;
    align-items: center;
}
.play-time-control-select {
    width: 100%;
    box-sizing: border-box;
    padding: 9px 32px 9px 36px; /* room for the leading icon and the native chevron */
    border: 1px solid rgba(0, 0, 0, 0.3);
    background: transparent;
    color: inherit;
    border-radius: 6px;
    font: inherit;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    /* Hand-drawn chevron via inline SVG so it inherits the text color. */
    background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 14px 14px;
}
body.dark-mode .play-time-control-select { border-color: rgba(255, 255, 255, 0.3); }

.play-modal-primary {
    margin-top: 8px;
    padding: 9px 16px;
    border: 1px solid #000;
    background: #000;
    color: #fff;
    border-radius: 6px;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
.play-modal-primary:hover { background: rgba(0, 0, 0, 0.85); }
.play-modal-primary:disabled { opacity: 0.5; cursor: wait; }
body.dark-mode .play-modal-primary { background: #f5f5f5; color: #000; border-color: #f5f5f5; }
body.dark-mode .play-modal-primary:hover { background: rgba(245, 245, 245, 0.85); }
/* Icon-only variant: pill that's just the play glyph. */
.play-modal-primary-icon {
    width: 100%;
    padding: 12px;
    gap: 0;
}
.play-modal-primary-icon svg { display: block; }

.play-modal-actions {
    display: flex;
    gap: 8px;
    margin-top: 8px;
    flex-wrap: wrap;
}
.play-modal-actions > .play-modal-primary,
.play-modal-actions > .play-modal-secondary {
    margin-top: 0;
    flex: 1;
    min-width: 0;
}
.play-modal-secondary {
    padding: 9px 16px;
    border: 1px solid rgba(0, 0, 0, 0.3);
    background: transparent;
    color: inherit;
    border-radius: 6px;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
.play-modal-secondary:hover { background: rgba(0, 0, 0, 0.05); }
.play-modal-secondary:disabled { opacity: 0.5; cursor: wait; }
body.dark-mode .play-modal-secondary { border-color: rgba(255, 255, 255, 0.3); }
body.dark-mode .play-modal-secondary:hover { background: rgba(255, 255, 255, 0.06); }

/* Lobby cards (public matches/simul/tournament) lay out horizontally:
 * player/host info on the left, meta chips (TC, count, Join) pushed to
 * the right edge so the action chip is always reachable. */
.play-public-card {
    flex-direction: row;
    align-items: center;
    gap: 14px;
}
.play-public-card .play-recent-players {
    flex: 1;
    min-width: 0;
    width: auto;
}
.play-public-card .play-recent-meta {
    margin-left: auto;
    flex-shrink: 0;
}
.play-public-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    border-radius: 999px;
    font-size: 0.78rem;
    background: rgba(0, 0, 0, 0.06);
}
body.dark-mode .play-public-chip { background: rgba(255, 255, 255, 0.08); }
.play-public-chip-join {
    background: #000;
    color: #fff;
    font-weight: 600;
}
body.dark-mode .play-public-chip-join { background: #f5f5f5; color: #000; }
/* Icon-only chip variant: tighter padding, square aspect. */
.play-public-chip-icon {
    padding: 6px 10px;
    gap: 0;
}
.play-public-chip-icon svg { display: block; }

.play-hand {
    display: flex; flex-wrap: wrap; gap: 10px;
    min-height: 46px;
    padding: 4px 0;
}
/* Inside a side row the hand takes whatever the player block leaves, and its
   rows align towards the board's outer edge: the top hand ends at the right,
   the bottom one starts at the left, so a wrapped second row does not float
   loose in the middle. */
.play-side .play-hand { flex: 1 1 auto; min-width: 0; }
.play-side-top .play-hand { justify-content: flex-end; }
.play-side-bottom .play-hand { justify-content: flex-start; }
.play-hand-piece {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center;
    width: 42px; height: 42px;
    padding: 0;
    border: 1px solid #000;
    border-radius: 50%;
    background: #fff;
    color: #000;
    font: inherit;
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color 0.12s ease, color 0.12s ease, transform 0.12s ease;
}
.play-hand-piece:hover { transform: translateY(-1px); }
body.dark-mode .play-hand-piece {
    background: #1a1a1a; color: #f5f5f5; border-color: #f5f5f5;
}
.play-hand-piece.play-hand-selected {
    background: #000; color: #fff;
}
body.dark-mode .play-hand-piece.play-hand-selected {
    background: #f5f5f5; color: #1a1a1a;
}
.play-hand-glyph {
    font-family: var(--font-kanji);
    font-size: 1.45rem;
    font-weight: 700;
    line-height: 1;
}
.play-hand-count {
    position: absolute;
    bottom: -3px;
    right: -3px;
    min-width: 20px; height: 20px;
    padding: 0 5px;
    box-sizing: border-box;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px;
    background: #000;
    color: #fff;
    font-family: var(--font-mono, inherit);
    font-variant-numeric: tabular-nums;
    font-size: 0.78rem;
    font-weight: 700;
    line-height: 1;
    box-shadow: 0 0 0 2px #fff;
    pointer-events: none;
}
body.dark-mode .play-hand-count {
    background: #f5f5f5; color: #1a1a1a;
    box-shadow: 0 0 0 2px #1a1a1a;
}
.play-hand-piece.play-hand-selected .play-hand-count {
    background: #fff; color: #000;
    box-shadow: 0 0 0 2px #000;
}
body.dark-mode .play-hand-piece.play-hand-selected .play-hand-count {
    background: #1a1a1a; color: #f5f5f5;
    box-shadow: 0 0 0 2px #f5f5f5;
}
.play-hand-empty { font-size: 0.78rem; opacity: 0.5; }

/* ---- Dragging a piece ----
   The ghost is the piece in flight, fixed to the viewport just above the
   finger (centred under a mouse); the square it is over answers with an
   inset ring. Scoped by .play-room-mine - a seated player at an active
   board - which is also what turns scrolling off on the pieces themselves,
   and only on the pieces, so the rest of the page still pans and a
   spectator's finger on a piece scrolls like anywhere else. */
.play-room-mine .play-cell .play-piece,
.play-room-mine .play-hand-piece { touch-action: none; }
.play-drag-ghost {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 300;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    will-change: transform;
    filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.35));
}
.play-drag-ghost .play-piece { transform: scale(1.12); }
.play-drag-ghost.play-drag-return { transition: transform 0.15s ease; }
.play-cell-drag-over::before {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    box-shadow: inset 0 0 0 3px rgba(255, 165, 0, 0.75);
    pointer-events: none;
}
.play-hand-dragging { opacity: 0.45; }
/* The press a dragged piece gives its square as it lands. The flipped
   variant carries the rotation through, or a gote piece would right itself
   for the length of the settle. */
.play-piece-settle { animation: play-piece-settle 0.14s ease; }
.play-piece-settle-flipped { animation: play-piece-settle-flipped 0.14s ease; }
@keyframes play-piece-settle {
    from { transform: scale(1.14); }
    to { transform: scale(1); }
}
@keyframes play-piece-settle-flipped {
    from { transform: rotate(180deg) scale(1.14); }
    to { transform: rotate(180deg) scale(1); }
}

.play-board-wrap { position: relative; width: 100%; max-width: 540px; }
/* Right-click board annotations (arrows + square highlights). The SVG
   overlay sits above the pieces but never intercepts clicks. */
.play-annot-overlay {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 4;
    overflow: visible;
}
.play-annot-square { fill: rgba(255, 152, 0, 0.45); }
.play-annot-arrow-line {
    stroke: rgba(255, 138, 0, 0.5);
    stroke-width: 0.22;
    stroke-linecap: round;
}
.play-annot-arrow-head { fill: rgba(255, 138, 0, 0.5); }
.play-board {
    display: grid;
    grid-template-columns: repeat(9, 1fr);
    grid-template-rows: repeat(9, 1fr);
    aspect-ratio: 1 / 1;
    width: 100%;
    background: transparent;
    border: 2px solid #000;
    box-shadow: none;
}
body.dark-mode .play-board {
    background: transparent;
    border-color: #f5f5f5;
}
.play-cell {
    border: 1px solid #000;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    position: relative;
    user-select: none;
}
body.dark-mode .play-cell { border-color: #f5f5f5; }
.play-cell-selected { background: rgba(0,0,0,0.10); }
body.dark-mode .play-cell-selected { background: rgba(255,255,255,0.14); }
.play-cell-legal::after {
    content: ''; position: absolute;
    width: 28%; height: 28%;
    border-radius: 50%;
    background: rgba(0,0,0,0.30);
}
body.dark-mode .play-cell-legal::after { background: rgba(255,255,255,0.40); }
.play-cell-check { background: rgba(178, 34, 34, 0.18); }
body.dark-mode .play-cell-check { background: rgba(255, 80, 80, 0.25); }
.play-cell-last-from { background: rgba(255, 196, 0, 0.18); }
.play-cell-last-to { background: rgba(255, 165, 0, 0.32); }
body.dark-mode .play-cell-last-from { background: rgba(255, 196, 0, 0.16); }
body.dark-mode .play-cell-last-to { background: rgba(255, 165, 0, 0.28); }
.play-cell-castle { background: rgba(46, 204, 113, 0.22); }
.play-cell-castle.play-cell-last-to { background: rgba(46, 204, 113, 0.42); }
body.dark-mode .play-cell-castle { background: rgba(46, 204, 113, 0.22); }
body.dark-mode .play-cell-castle.play-cell-last-to { background: rgba(46, 204, 113, 0.4); }
/* A staged premove: blue, the colour no other square state uses, on both
   the departure and the landing square. */
.play-cell-premove { background: rgba(59, 130, 246, 0.30); }
body.dark-mode .play-cell-premove { background: rgba(96, 165, 250, 0.30); }

/* Spectator chat, murmured from the board's bottom-left corner. Anchored to
   .play-board-wrap (already position:relative), above the annotation layer
   (z-index 4), and untouchable so no bubble ever eats a click on a square. */
.play-spectator-bubbles {
    position: absolute;
    left: 8px;
    bottom: 8px;
    z-index: 6;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    max-width: 72%;
    pointer-events: none;
}
.play-spectator-bubble {
    background: rgba(255, 255, 255, 0.94);
    color: #000;
    border: 1px solid #000;
    border-radius: 10px;
    padding: 4px 10px;
    font-size: 0.82rem;
    line-height: 1.35;
    overflow-wrap: anywhere;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
    opacity: 0;
    transform: translateY(4px);
    transition: opacity 0.25s ease, transform 0.25s ease;
}
.play-spectator-bubble-show { opacity: 1; transform: translateY(0); }
.play-spectator-bubble-name { font-weight: 700; margin-right: 6px; opacity: 0.65; }
body.dark-mode .play-spectator-bubble {
    background: rgba(31, 29, 29, 0.94);
    color: #f5f5f5;
    border-color: #f5f5f5;
}
.play-history-castle { color: #1a7f3a; font-weight: 600; }
body.dark-mode .play-history-castle { color: #4ade80; }
.play-history-opening { color: #1e40af; font-weight: 600; }
body.dark-mode .play-history-opening { color: #60a5fa; }

/* ------------------------------------------------------------------ */
/* Push subscription UI on /notifications                              */
/* ------------------------------------------------------------------ */

.notifications-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
.push-subscribe-wrap {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    max-width: 520px;
}
.push-subscribe-wrap[hidden] { display: none; }
.push-subscribe-status {
    font-size: 0.85rem;
    opacity: 0.75;
    line-height: 1.35;
    text-align: right;
}
.push-subscribe-status-on { color: #1a7f3a; opacity: 1; font-weight: 600; }
body.dark-mode .push-subscribe-status-on { color: #4ade80; }
.push-subscribe-btn {
    padding: 6px 14px;
    border: 1px solid rgba(0,0,0,0.2);
    background: transparent;
    border-radius: 6px;
    font: inherit;
    color: inherit;
    font-size: 0.88rem;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease;
    white-space: nowrap;
}
body.dark-mode .push-subscribe-btn { border-color: rgba(255,255,255,0.25); }
.push-subscribe-btn:hover { background: rgba(0,0,0,0.05); }
body.dark-mode .push-subscribe-btn:hover { background: rgba(255,255,255,0.06); }
.push-subscribe-btn-on {
    background: #1a7f3a;
    border-color: #1a7f3a;
    color: #fff;
}
.push-subscribe-btn-on:hover { background: #166b30; }
.push-subscribe-btn-disabled,
.push-subscribe-btn:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Head-to-head badge under each player's name in the play room. */
.play-player-h2h {
    display: inline-block;
    font-size: 0.78rem;
    opacity: 0.75;
    margin-top: 2px;
    padding: 1px 8px;
    background: rgba(0,0,0,0.05);
    border-radius: 999px;
    line-height: 1.45;
    white-space: nowrap;
}
body.dark-mode .play-player-h2h { background: rgba(255,255,255,0.06); }
.play-player-h2h[hidden] { display: none; }

/* ------------------------------------------------------------------ */
/* Simul session page                                                  */
/* ------------------------------------------------------------------ */

.simul-header {
    align-items: center;
}
.simul-header-info { flex: 1; min-width: 240px; }

/* Subtitle is a row of chips (host, time control, board count, status). */
.simul-subtitle {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 8px 0 0;
}
.simul-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid rgba(0, 0, 0, 0.10);
    background: transparent;
    font-size: 0.82rem;
    font-weight: 500;
    line-height: 1.6;
    opacity: 0.85;
}
body.dark-mode .simul-chip { border-color: rgba(255, 255, 255, 0.12); }
.simul-chip svg { flex-shrink: 0; opacity: 0.6; }
.simul-chip-status { opacity: 1; }
.simul-chip-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
    opacity: 0.6;
}

.simul-header-actions {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

/* Invite link: compact icon + faded inline link, mirrors tournament page. */
.simul-invite {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 12px 0 4px;
    padding: 0;
    background: transparent;
    border: none;
}
.simul-invite[hidden] { display: none; }
.simul-invite-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: none;
    background: transparent;
    color: inherit;
    border-radius: 50%;
    cursor: pointer;
    opacity: 0.7;
    transition: opacity 0.12s ease, background-color 0.12s ease, color 0.12s ease;
}
.simul-invite-btn:hover { background: rgba(0, 0, 0, 0.07); opacity: 1; }
body.dark-mode .simul-invite-btn:hover { background: rgba(255, 255, 255, 0.08); }
.simul-invite-btn svg { display: block; }
.simul-invite-btn-ok {
    background: #1a7f3a;
    color: #fff;
    opacity: 1;
}
.simul-invite-btn-ok:hover { background: #166b30; }
body.dark-mode .simul-invite-btn-ok {
    background: #4ade80;
    color: #0d2818;
}
body.dark-mode .simul-invite-btn-ok:hover { background: #22c55e; }
.simul-invite-link {
    flex: 1;
    min-width: 0;
    font-size: 0.86rem;
    opacity: 0.55;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    user-select: all;
    cursor: text;
    font-family: var(--font-mono);
}

.simul-status-banner {
    margin: 12px 0 8px;
    padding: 10px 14px;
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: 8px;
    font-size: 0.92rem;
    opacity: 0.85;
}
body.dark-mode .simul-status-banner { border-color: rgba(255, 255, 255, 0.12); }

.simul-boards { margin-top: 0; }
.simul-error {
    padding: 24px;
    text-align: center;
    color: #b91c1c;
}
body.dark-mode .simul-error { color: #f87171; }

/* Reuses .pieces-index-card for hover/border behavior; only adds the
 * internal layout for the simul-specific number + opponent + status. */
.simul-board-card {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.simul-board-num {
    font-size: 0.78rem;
    opacity: 0.55;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
}
.simul-board-opponent {
    font-size: 1.08rem;
    font-weight: 600;
}
.simul-board-status {
    font-size: 0.85rem;
    margin-top: 2px;
}
.simul-board-status-active { color: #1a7f3a; }
body.dark-mode .simul-board-status-active { color: #4ade80; }
.simul-board-status-finished {
    color: rgba(0,0,0,0.55);
    font-style: italic;
}
body.dark-mode .simul-board-status-finished { color: rgba(255,255,255,0.55); }
.simul-board-finished {
    opacity: 0.7;
}

/* Icon-only action buttons in simul / tournament headers and matchup
 * cards. Neutral by default (mirrors .wiki-icon-btn). The "primary" and
 * "danger" variants are kept very subtle - only a hint of colour at hover. */
.simul-icon-btn,
.tournament-icon-btn {
    background: transparent;
    border: 1px solid rgba(0, 0, 0, 0.2);
    color: inherit;
    cursor: pointer;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
.simul-icon-btn svg,
.tournament-icon-btn svg { display: block; }
body.dark-mode .simul-icon-btn,
body.dark-mode .tournament-icon-btn { border-color: rgba(255, 255, 255, 0.22); }
.simul-icon-btn:hover,
.tournament-icon-btn:hover {
    background: rgba(0, 0, 0, 0.05);
    border-color: currentColor;
}
body.dark-mode .simul-icon-btn:hover,
body.dark-mode .tournament-icon-btn:hover { background: rgba(255, 255, 255, 0.06); }
.simul-icon-btn-danger,
.tournament-icon-btn-danger { opacity: 0.7; }
.simul-icon-btn-danger:hover,
.tournament-icon-btn-danger:hover { opacity: 1; }

/* Public lobby card variants for simul/tournament. */
.play-public-card-simul .play-recent-name,
.play-public-card-tournament .play-recent-name { font-weight: 600; }

.play-recent-name-winner {
    font-weight: 700;
    color: #1a7f3a;
}
body.dark-mode .play-recent-name-winner { color: #4ade80; }

.play-public-tag {
    display: inline-block;
    margin-left: 8px;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    line-height: 1.4;
}
.play-public-tag-simul { background: rgba(30,64,175,0.14); color: #1e40af; }
.play-public-tag-tournament { background: rgba(146,64,14,0.14); color: #92400e; }
body.dark-mode .play-public-tag-simul { background: rgba(96,165,250,0.18); color: #60a5fa; }
body.dark-mode .play-public-tag-tournament { background: rgba(252,211,77,0.18); color: #fde68a; }

.play-visibility {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 12px 0;
}
.play-visibility-option {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    column-gap: 10px;
    padding: 10px 12px;
    border: 1px solid rgba(0,0,0,0.14);
    border-radius: 8px;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
body.dark-mode .play-visibility-option { border-color: rgba(255,255,255,0.18); }
.play-visibility-option:hover { background: rgba(0,0,0,0.03); }
body.dark-mode .play-visibility-option:hover { background: rgba(255,255,255,0.04); }
.play-visibility-option input[type="radio"] {
    grid-row: 1 / span 2;
    align-self: center;
    margin: 0;
}
.play-visibility-option > span {
    grid-column: 2;
    grid-row: 1;
    font-weight: 600;
}
.play-visibility-option > small {
    grid-column: 2;
    grid-row: 2;
    font-size: 0.82rem;
    opacity: 0.7;
}
.play-visibility-option input[type="radio"]:checked ~ span {
    color: #1a7f3a;
}
body.dark-mode .play-visibility-option input[type="radio"]:checked ~ span {
    color: #4ade80;
}

/* ------------------------------------------------------------------ */
/* Tournament page                                                     */
/* ------------------------------------------------------------------ */

.tournament-header {
    align-items: center;
}
.tournament-header-info { flex: 1; min-width: 240px; }

/* Subtitle is a row of chips (host, time control, count, status).     */
.tournament-subtitle {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 8px 0 0;
}
.tournament-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid rgba(0, 0, 0, 0.10);
    background: transparent;
    font-size: 0.82rem;
    font-weight: 500;
    line-height: 1.6;
    opacity: 0.85;
}
body.dark-mode .tournament-chip { border-color: rgba(255, 255, 255, 0.12); }
.tournament-chip svg { flex-shrink: 0; opacity: 0.6; }
.tournament-chip-status { opacity: 1; }
.tournament-chip-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
    opacity: 0.6;
}

.tournament-header-actions {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.tournament-need-players,
.tournament-login-required {
    font-size: 0.86rem;
    opacity: 0.65;
    font-style: italic;
}

/* Status banner: neutral, borderless inline notice. */
.tournament-status-banner {
    margin: 12px 16px 8px;
    padding: 4px 0;
    border: none;
    font-size: 0.92rem;
    opacity: 0.7;
}
.tournament-status-banner-winner {
    font-weight: 700;
    opacity: 1;
    text-align: center;
    padding: 16px 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    font-size: 1.05rem;
}
.tournament-winner-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

/* Invite link: compact icon + faded inline link, no big card around. */
.tournament-invite {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 12px 0 4px;
    padding: 0;
    background: transparent;
    border: none;
}
.tournament-invite[hidden] { display: none; }
.tournament-invite-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: none;
    background: transparent;
    color: inherit;
    border-radius: 50%;
    cursor: pointer;
    opacity: 0.7;
    transition: opacity 0.12s ease, background-color 0.12s ease, color 0.12s ease;
}
.tournament-invite-btn:hover { background: rgba(0, 0, 0, 0.07); opacity: 1; }
body.dark-mode .tournament-invite-btn:hover { background: rgba(255, 255, 255, 0.08); }
.tournament-invite-btn svg { display: block; }
.tournament-invite-btn-ok {
    background: #1a7f3a;
    color: #fff;
    opacity: 1;
}
.tournament-invite-btn-ok:hover { background: #166b30; }
body.dark-mode .tournament-invite-btn-ok {
    background: #4ade80;
    color: #0d2818;
}
body.dark-mode .tournament-invite-btn-ok:hover { background: #22c55e; }
.tournament-invite-link {
    flex: 1;
    min-width: 0;
    font-size: 0.86rem;
    opacity: 0.55;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    user-select: all;
    cursor: text;
    font-family: var(--font-mono);
}

/* Participants grid: reuses .pieces-index + .pieces-index-card so it
 * matches the wiki/match listing visuals exactly. The card holds the
 * same .play-recent-players row as lobby cards. */
.tournament-participants-list .play-recent-players {
    width: 100%;
    margin: 0;
}
.tournament-host-badge {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: rgba(146, 64, 14, 0.12);
    color: #92400e;
}
.tournament-host-badge svg { width: 12px; height: 12px; }
body.dark-mode .tournament-host-badge {
    background: rgba(252, 211, 77, 0.18);
    color: #fde68a;
}

/* Bracket: horizontal flex with each column taking equal share of the
 * available width. Cards inside are constrained so they stay compact
 * even when the column is wide. */
/* ---- The bracket ------------------------------------------------------
 * Rebuilt: rounds are columns joined by stubs, each card wears its state
 * (waiting / live / decided / bye), the viewer's own pairing is ringed in
 * the accent colour and carries the one button that matters, and a
 * finished draw ends on the champion instead of a grey card. The wrap
 * scrolls sideways on a phone - a draw is wide by nature, and squeezing
 * it into columns of crumbs was what made the old page unreadable. */
/* ---- The bracket (vertical) -------------------------------------------
 * Rounds stack top to bottom: the draw reads in the order it is played,
 * needs no sideways scrolling on a phone, and the final is a card, not a
 * sliver at the end of a scrollbar. Within a round the cards sit side by
 * side only where whole cards fit. */
.tournament-bracket-wrap { margin: 20px 16px 24px; }
.tournament-bracket {
    display: flex;
    flex-direction: column;
    gap: 24px;
}
.tournament-bracket-round-header {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    font-weight: 700;
    opacity: 0.55;
    margin: 0 0 10px;
}
.tournament-bracket-round-header::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--c-border);
}
.tournament-bracket-round-body {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    justify-content: center;
}
.tournament-bracket-node {
    flex: 1 1 280px;
    max-width: 430px;
    min-width: 0;
}
/* Double elimination: the three sections (winners / losers / grand final)
 * each open with a heavier title than the per-round headers under it. */
.tournament-bracket-group-title {
    margin-bottom: -12px;
    font-size: 0.86rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.16em;
}
.tournament-bracket-group-title-winners { color: #16a34a; }
.tournament-bracket-group-title-losers { color: #dc2626; }
.tournament-bracket-group-title-finals { color: #b8860b; }

.tournament-matchup {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--c-border);
    border-radius: 12px;
    background: var(--c-box);
    overflow: hidden;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.tournament-matchup:hover { border-color: var(--c-font-dim); }
.tournament-matchup-active {
    border-color: var(--c-accent);
    box-shadow: 0 2px 14px rgba(0, 0, 0, 0.10);
}
.tournament-matchup-mine {
    outline: 2px solid var(--c-accent);
    outline-offset: 2px;
}
.tournament-matchup-pending { opacity: 0.78; }
.tournament-matchup-bye { border-style: dashed; opacity: 0.6; }

.tournament-matchup-slot {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    min-height: 46px;
}
.tournament-matchup-slot:first-of-type { border-bottom: 1px solid var(--c-border); }
.tournament-matchup-slot-empty { opacity: 0.45; }
.tournament-matchup-slot-winner {
    background: linear-gradient(90deg, rgba(234, 179, 8, 0.16), transparent 70%);
}
.tournament-matchup-slot-winner .tournament-matchup-name { font-weight: 700; }
.tournament-matchup-slot-loser { opacity: 0.55; }
.tournament-matchup-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}
.tournament-matchup-name {
    flex: 1;
    min-width: 0;
    font-size: 0.92rem;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: 6px;
}
.tournament-matchup-name-tbd { opacity: 0.5; letter-spacing: 0.2em; }
.tournament-matchup-you {
    flex-shrink: 0;
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--c-accent);
    border: 1px solid var(--c-accent);
    border-radius: 999px;
    padding: 1px 7px;
}
.tournament-matchup-trophy {
    flex-shrink: 0;
    color: #b8860b;
    display: inline-flex;
    align-items: center;
}

.tournament-matchup-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 10px;
    min-height: 34px;
    border-top: 1px solid var(--c-border);
    background: var(--c-box-alt);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.tournament-matchup-state { display: inline-flex; align-items: center; gap: 6px; opacity: 0.6; }
.tournament-matchup-state-live { opacity: 1; color: #dc2626; }
body.dark-mode .tournament-matchup-state-live { color: #f87171; }
.tournament-live-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: currentColor;
    animation: tournament-live-pulse 1.4s ease-in-out infinite;
}
@keyframes tournament-live-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.35; transform: scale(0.8); }
}
.tournament-matchup-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    text-decoration: none;
    color: inherit;
    opacity: 0.65;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    transition: opacity 0.12s ease;
}
.tournament-matchup-link:hover { opacity: 1; }
/* The one button that matters: the viewer's own live board. */
.tournament-matchup-go {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--c-accent);
    color: #fff;
    border-radius: 8px;
    padding: 5px 12px;
    font-size: 0.74rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    text-decoration: none;
    animation: tournament-go-pulse 1.8s ease-in-out infinite;
}
@keyframes tournament-go-pulse {
    0%, 100% { filter: none; }
    50% { filter: brightness(1.18); }
}

.tournament-bracket-champion-row .tournament-bracket-champion {
    max-width: 430px;
    margin: 0 auto;
}
.tournament-bracket-champion {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 18px 14px;
    border: 1px solid rgba(234, 179, 8, 0.5);
    border-radius: 14px;
    background: linear-gradient(180deg, rgba(234, 179, 8, 0.12), transparent);
    text-align: center;
}
.tournament-bracket-champion-avatar {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
    box-shadow: 0 0 0 3px rgba(234, 179, 8, 0.7);
}
.tournament-bracket-champion-name {
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
}
.tournament-bracket-champion-trophy { color: #b8860b; }

/* The invite row and the participants list keep the same gutter. */
.tournament-invite,
section[data-tournament-participants] {
    margin-left: 16px;
    margin-right: 16px;
}

/* The landing card that walks a player onto their board. */
.tournament-autogo {
    position: fixed;
    inset: 0;
    z-index: 400;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.55);
    padding: 20px;
}
.tournament-autogo-card {
    background: var(--c-box);
    border: 1px solid var(--c-border);
    border-radius: 16px;
    padding: 26px 28px 22px;
    text-align: center;
    max-width: 360px;
    width: 100%;
    box-shadow: 0 18px 60px rgba(0, 0, 0, 0.35);
}
.tournament-autogo-title { margin: 0; font-size: 1.2rem; font-weight: 700; }
.tournament-autogo-opp { margin: 6px 0 0; opacity: 0.7; font-size: 0.95rem; }
.tournament-autogo-count {
    font-size: 3.2rem;
    font-weight: 700;
    line-height: 1;
    color: var(--c-accent);
    margin: 16px 0;
    font-variant-numeric: tabular-nums;
}
.tournament-autogo-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
}
.tournament-autogo-go {
    background: var(--c-accent);
    color: #fff;
    text-decoration: none;
    border-radius: 10px;
    padding: 10px 18px;
    font-weight: 700;
}
.tournament-autogo-stay {
    background: none;
    border: none;
    cursor: pointer;
    color: inherit;
    opacity: 0.6;
    font-size: 0.9rem;
    padding: 10px 6px;
}
.tournament-autogo-stay:hover { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
    .tournament-live-dot, .tournament-matchup-go { animation: none; }
}
@media (max-width: 700px) {
    .tournament-status-banner,
    .tournament-countdown,
    .tournament-bracket-wrap,
    .tournament-invite,
    section[data-tournament-participants] { margin-left: 12px; margin-right: 12px; }
    .tournament-subtitle { gap: 5px; }
    .tournament-bracket { gap: 18px; }
    .tournament-bracket-node { flex-basis: 100%; max-width: none; }
    .tournament-matchup-slot { padding: 9px 10px; min-height: 42px; }
    .tournament-matchup-name { font-size: 0.88rem; }
    .tournament-autogo-card { padding: 22px 18px 18px; }
}

.tournament-error {
    padding: 24px;
    text-align: center;
    color: #b91c1c;
}
body.dark-mode .tournament-error { color: #f87171; }

.tournament-modal-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 12px;
}
.tournament-modal-label {
    font-size: 0.85rem;
    opacity: 0.7;
    font-weight: 600;
}

.play-analysis-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-weight: 800;
    font-family: var(--font-ui);
    color: #fff;
    cursor: help;
    text-align: center;
    line-height: 1;
}
/* One colour per verdict, running from the two that are worth showing off
   down to the one that lost the game. Same family as the badge coins: hue
   carries the meaning, so the glyph does not have to be read to know whether
   the news is good. */
.play-analysis-badge-brilliant  { background: #0d9488; }
.play-analysis-badge-great      { background: #16a34a; }
.play-analysis-badge-best       { background: #2563eb; }
.play-analysis-badge-excellent  { background: #4b7bd6; }
.play-analysis-badge-good       { background: #6b7280; }
.play-analysis-badge-inaccuracy { background: #ca8a04; }
.play-analysis-badge-mistake    { background: #ea580c; }
.play-analysis-badge-miss       { background: #9333ea; }
.play-analysis-badge-blunder    { background: #b91c1c; }

.play-analysis-badge-history {
    width: 22px; height: 22px;
    font-size: 0.7rem;
    margin-left: 2px;
    vertical-align: middle;
}

.play-analysis-badge-cell {
    position: absolute;
    top: -8px; right: -8px;
    width: 22px; height: 22px;
    font-size: 0.72rem;
    z-index: 4;
    box-shadow: 0 0 0 2px #fff, 0 1px 4px rgba(0,0,0,0.35);
}
body.dark-mode .play-analysis-badge-cell { box-shadow: 0 0 0 2px #1f1d1d, 0 1px 4px rgba(0,0,0,0.6); }
.play-piece {
    width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-kanji);
    /* THE GLYPH FILLS THE SQUARE.
       At 4vw the character was a third of the height of the cell it sat in:
       readable under a pointer on a desktop, a footnote on a phone, where the
       cell is around 40px and the kanji came out at 16. The floor, the rate
       and the cap all go up together so a piece reads as a piece at every
       width. The tile and disc styles are unaffected: their SVG is laid over
       the cell at 96%, not sized off this. */
    font-size: clamp(1.2rem, 7.2vw, 2.2rem);
    font-weight: 700;
    color: #000;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    line-height: 1;
}
body.dark-mode .play-piece { color: #f5f5f5; }
.play-piece-promoted { color: #b91c1c; font-weight: 800; }
body.dark-mode .play-piece-promoted { color: #f87171; }
.play-piece-flipped { transform: rotate(180deg); }
.play-piece-western {
    font-family: var(--font-kanji);
    font-size: clamp(1.3rem, 7.8vw, 2.35rem);
}

/* The chess-style figures: silhouettes drawn by piece-styles.js. Sized in em
   so they scale with the piece font-size; they paint with currentColor, so
   .play-piece-promoted tints them red as the promotion overlay. */
.piece-western-svg {
    display: block;
    width: 1.4em;
    height: 1.4em;
}

/* ---- the other glyph styles ------------------------------------------
   Each style is one class that piece-styles.js puts on the piece; the board
   itself never changes. `play-piece-drawn` marks the styles that are a
   picture rather than text (koma, western, moves, dobutsu): a text-stroke
   outline would erase them, so board-themes.css gives those a solid second
   ink instead. */

/* The boxwood tile (koma, koma1, intl - they share `play-piece-tile`). The
   tile is an SVG so the characters scale with the cell at whatever size a
   board is drawn, and its inks are fixed on purpose - a real piece is black
   on wood in the dark too. */
.play-piece-tile {
    --koma-wood: #f2dca3;
    --koma-edge: #7d5a2a;
    --koma-ink: #1b1410;
    --koma-ink-promoted: #b0231c;
}
.piece-koma-svg {
    display: block;
    width: 1.6em;
    height: 1.75em;
    overflow: visible;
}
/* On a board the tile fills the square. It is positioned out of flow on
   purpose: the board's rows are `1fr`, whose minimum is the content's
   intrinsic height, and an in-flow SVG at 100% width has one (its aspect
   ratio) - so rows with pieces grew taller than empty rows. An absolute
   child contributes nothing to the row, whatever its size. */
.play-piece.play-piece-tile,
.play-piece.play-piece-disc { position: relative; }
.play-piece .piece-koma-svg,
.play-piece .piece-disc-svg {
    position: absolute;
    top: 2%; left: 2%;
    width: 96%; height: 96%;
}
.play-piece-modal-kanji .piece-koma-svg,
.play-piece-modal-kanji .piece-disc-svg { margin: 0 auto; }
/* In hand the button is a 42px circle with the count badge over its bottom
   edge, so the tile is smaller there and sits a little high to keep its
   character out from under the badge. */
.play-hand-glyph .piece-koma-svg {
    width: 1.3em;
    height: 1.42em;
    margin-top: -0.22em;
}
.play-hand-glyph .piece-disc-svg {
    width: 1.3em;
    height: 1.3em;
    margin-top: -0.2em;
}
.piece-koma-svg text,
.piece-disc-svg text {
    font-family: var(--font-kanji);
    font-weight: 700;
}
.piece-koma-wood {
    fill: var(--koma-wood);
    stroke: var(--koma-edge);
    stroke-width: 0.9;
    stroke-linejoin: round;
}
.piece-koma-ink { fill: var(--koma-ink); }
.piece-koma-ink-promoted { fill: var(--koma-ink-promoted); }

/* Discs: the kanji on a round piece, the way xiangqi draws its pieces. Same
   token scheme as the tile, so the piece-colour rules can treat it alike. */
.play-piece-disc {
    --disc-face: #f6ead2;
    --disc-edge: #5c4832;
    --disc-ink: #1b1410;
    --disc-ink-promoted: #b0231c;
}
.piece-disc-svg {
    display: block;
    width: 1.5em;
    height: 1.5em;
    overflow: visible;
}
.piece-disc-face {
    fill: var(--disc-face);
    stroke: var(--disc-edge);
    stroke-width: 1;
}
.piece-disc-ring {
    fill: none;
    stroke: var(--disc-edge);
    stroke-width: 0.5;
    opacity: 0.7;
}
.piece-disc-ink { fill: var(--disc-ink); }
.piece-disc-ink-promoted { fill: var(--disc-ink-promoted); }

/* Letters: the initials of western notation, the + of a promoted piece
   raised beside the letter. */
.play-piece-letters {
    font-family: var(--font-ui);
    font-weight: 800;
    letter-spacing: -0.02em;
}
.piece-letters-plus {
    font-size: 0.55em;
    line-height: 1;
    align-self: flex-start;
    vertical-align: top;
    margin-right: 0.04em;
}

/* Movement diagrams: the piece as a square, its steps as dots, its slides as
   arrows. Inherits currentColor like the western arrows do. */
.piece-moves-svg {
    display: block;
    width: 1.45em;
    height: 1.45em;
}

/* Dobutsu: colour emoji ignore `color`, so the promoted mark is a separate
   glyph that picks the red up on its own. */
.play-piece-dobutsu {
    font-family: 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif;
    font-weight: 400;
}
.piece-dobutsu {
    position: relative;
    display: inline-block;
    line-height: 1;
    font-size: 1.08em;
}
.piece-dobutsu-plus {
    position: absolute;
    top: -0.3em;
    right: -0.45em;
    font-family: var(--font-ui);
    font-size: 0.55em;
    font-weight: 800;
    line-height: 1;
}

/* The preview beside each option on the preferences page: a king, a silver
   and a tokin drawn in that option's style, whichever style is chosen. */
.piece-style-preview {
    display: inline-flex;
    gap: 2px;
    flex: 0 0 auto;
}
.piece-style-sample {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 32px;
    height: 32px;
    border: 1px solid var(--c-border);
    background: var(--c-box);
    color: var(--c-font-strong);
    font-family: var(--font-kanji);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1;
}
.piece-style-sample.play-piece-promoted { color: #b91c1c; }
body.dark-mode .piece-style-sample.play-piece-promoted { color: #f87171; }
.piece-style-sample.play-piece-western { font-size: 1.3rem; }
.piece-style-sample .piece-koma-svg,
.piece-style-sample .piece-disc-svg {
    position: absolute;
    top: 3%; left: 3%;
    width: 94%; height: 94%;
}

.settings-radio-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 6px;
}
.settings-radio-group .settings-toggle {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 8px;
    transition: border-color 0.15s ease, background-color 0.15s ease;
    margin-top: 0;
}
.settings-radio-group .settings-toggle:hover {
    border-color: rgba(0, 0, 0, 0.3);
}
.settings-radio-group .settings-toggle input[type="radio"] {
    appearance: none;
    -webkit-appearance: none;
    width: 16px;
    height: 16px;
    border: 1px solid rgba(0, 0, 0, 0.4);
    border-radius: 50%;
    margin: 0;
    cursor: pointer;
    position: relative;
    flex-shrink: 0;
}
.settings-radio-group .settings-toggle input[type="radio"]:checked {
    border-color: #000;
}
.settings-radio-group .settings-toggle input[type="radio"]:checked::after {
    content: '';
    position: absolute;
    top: 3px;
    left: 3px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #000;
}
.settings-radio-group .settings-toggle:has(input[type="radio"]:checked) {
    border-color: #000;
    background: rgba(0, 0, 0, 0.04);
}
body.dark-mode .settings-radio-group .settings-toggle {
    border-color: rgba(255, 255, 255, 0.15);
}
body.dark-mode .settings-radio-group .settings-toggle:hover {
    border-color: rgba(255, 255, 255, 0.35);
}
body.dark-mode .settings-radio-group .settings-toggle input[type="radio"] {
    border-color: rgba(255, 255, 255, 0.45);
}
body.dark-mode .settings-radio-group .settings-toggle input[type="radio"]:checked {
    border-color: #f5f5f5;
}
body.dark-mode .settings-radio-group .settings-toggle input[type="radio"]:checked::after {
    background: #f5f5f5;
}
body.dark-mode .settings-radio-group .settings-toggle:has(input[type="radio"]:checked) {
    border-color: #f5f5f5;
    background: rgba(255, 255, 255, 0.05);
}

.play-promotion {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    z-index: 10;
}
.play-promotion[hidden] { display: none; }
.play-promotion-backdrop {
    position: absolute; inset: 0;
    background: rgba(0,0,0,0.5);
    cursor: pointer;
}
.play-promotion-card {
    position: relative;
    background: #fff; color: #1d1f23;
    padding: 20px 24px; border-radius: 10px;
    text-align: center;
    box-shadow: 0 8px 30px rgba(0,0,0,0.3);
    min-width: 220px;
}
body.dark-mode .play-promotion-card { background: #2c2e34; color: #f5f5f5; }
.play-promotion-title {
    margin: 0 0 12px;
    font-weight: 600;
    font-size: 1rem;
    color: inherit;
}
.play-promotion-buttons { display: flex; gap: 10px; justify-content: center; }
.play-promotion-buttons button {
    padding: 8px 18px;
    border-radius: 6px;
    border: 1px solid rgba(0,0,0,0.2);
    background: rgba(0,0,0,0.05);
    color: inherit;
    cursor: pointer;
    font: inherit;
    font-size: 0.95rem;
    min-width: 96px;
}
body.dark-mode .play-promotion-buttons button {
    background: rgba(255,255,255,0.08);
    border-color: rgba(255,255,255,0.15);
}
.play-promotion-buttons button:first-child {
    background: #c2410c; color: #fff; border-color: #c2410c;
}
.play-promotion-cancel {
    position: absolute;
    top: 4px; right: 8px;
    background: transparent;
    border: none;
    font-size: 1.2rem;
    color: inherit;
    cursor: pointer;
    opacity: 0.6;
    line-height: 1;
    padding: 4px 6px;
}
.play-promotion-cancel:hover { opacity: 1; }

/* Match result banner sits at the top of the play room (just below the
 * page header). Neutral wiki-style colours; the green/red are reserved
 * for the viewer's own perspective so they read result at a glance. */
.play-result-banner {
    /* Clear of the floating back arrow, and centred text keeps it honest. */
    margin: 6px 52px 0;
    padding: 10px 16px;
    border: 1px solid rgba(0, 0, 0, 0.10);
    font-weight: 600;
    font-size: 0.95rem;
    text-align: center;
}
body.dark-mode .play-result-banner { border-color: rgba(255, 255, 255, 0.12); }
.play-result-banner[hidden] { display: none; }
.play-result-banner-win {
    color: #1a7f3a;
    border-color: rgba(26, 127, 58, 0.30);
    background: rgba(26, 127, 58, 0.06);
}
body.dark-mode .play-result-banner-win {
    color: #4ade80;
    border-color: rgba(74, 222, 128, 0.35);
    background: rgba(74, 222, 128, 0.07);
}
.play-result-banner-loss {
    color: #b91c1c;
    border-color: rgba(185, 28, 28, 0.30);
    background: rgba(185, 28, 28, 0.05);
}
body.dark-mode .play-result-banner-loss {
    color: #f87171;
    border-color: rgba(248, 113, 113, 0.35);
    background: rgba(248, 113, 113, 0.06);
}
.play-result-banner-neutral { opacity: 0.85; }

.play-piece-modal {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    z-index: 12;
}
.play-piece-modal[hidden] { display: none; }
.play-piece-modal-backdrop {
    position: absolute; inset: 0;
    background: rgba(0,0,0,0.45);
    cursor: pointer;
}
.play-piece-modal-card {
    position: relative;
    background: #fff; color: #1d1f23;
    padding: 20px 24px 16px;
    border-radius: 12px;
    text-align: center;
    box-shadow: 0 12px 40px rgba(0,0,0,0.25);
    max-width: 320px;
    width: calc(100% - 40px);
}
body.dark-mode .play-piece-modal-card {
    background: #2c2e34; color: #f5f5f5;
}
.play-piece-modal-kanji {
    font-family: var(--font-kanji);
    font-size: 3rem;
    font-weight: 700;
    line-height: 1;
    margin-bottom: 8px;
    color: inherit;
}
.play-piece-modal-promoted { color: #b91c1c; }
body.dark-mode .play-piece-modal-promoted { color: #f87171; }
.play-piece-modal-name {
    margin: 0 0 8px;
    font-size: 1.05rem;
    font-weight: 600;
}
.play-piece-modal-move {
    margin: 0 0 14px;
    font-size: 0.9rem;
    opacity: 0.85;
    line-height: 1.4;
}
.play-piece-modal-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
    padding: 6px 12px;
    border: 1px solid currentColor;
    border-radius: 999px;
    font-size: 0.85rem;
    color: #c2410c;
    text-decoration: none;
    transition: background-color 0.12s ease;
}
.play-piece-modal-link:hover { background: rgba(194, 65, 12, 0.1); text-decoration: none; }
body.dark-mode .play-piece-modal-link { color: #fb923c; }
.play-piece-modal-close {
    position: absolute;
    top: 6px; right: 10px;
    background: transparent; border: none;
    font-size: 1.3rem;
    color: inherit;
    cursor: pointer;
    opacity: 0.55;
    line-height: 1; padding: 4px 8px;
}
.play-piece-modal-close:hover { opacity: 1; }

.play-controls { margin: 12px 0; display: flex; gap: 10px; align-items: center; }

.play-history-section { margin-top: 20px; }
.play-history-title { margin: 0 0 6px; font-size: 0.95rem; opacity: 0.8; }
.play-history {
    max-height: 220px; overflow-y: auto;
    border: 1px solid rgba(0, 0, 0, 0.1);
}
body.dark-mode .play-history { border-color: rgba(255, 255, 255, 0.1); }
.play-history-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.88rem;
}
.play-history-row {
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
body.dark-mode .play-history-row { border-bottom-color: rgba(255, 255, 255, 0.06); }
.play-history-row:last-child { border-bottom: none; }
.play-history-clickable { cursor: pointer; }
.play-history-clickable:hover { background: rgba(0, 0, 0, 0.04); }
body.dark-mode .play-history-clickable:hover { background: rgba(255, 255, 255, 0.05); }
.play-history-current { background: rgba(255, 165, 0, 0.18); }
body.dark-mode .play-history-current { background: rgba(255, 165, 0, 0.22); }
.play-history-row td { padding: 6px 10px; vertical-align: middle; }
.play-history-num {
    width: 36px; text-align: right;
    font-variant-numeric: tabular-nums;
    opacity: 0.55; font-size: 0.82rem;
}
.play-history-desc { line-height: 1.4; }
.play-history-short {
    width: 1%; white-space: nowrap;
    font-family: var(--font-kanji);
    font-size: 0.95rem;
    opacity: 0.75;
    text-align: right;
}
.play-history-gote .play-history-num,
.play-history-gote .play-history-short { opacity: 0.5; }
.play-history-takenback .play-history-desc,
.play-history-takenback .play-history-short {
    text-decoration: line-through;
    opacity: 0.45;
}
.play-history-takeback {
    background: rgba(255, 165, 0, 0.10);
    font-style: italic;
}
body.dark-mode .play-history-takeback { background: rgba(255, 165, 0, 0.14); }
.play-history-takeback .play-history-num {
    font-style: normal;
    opacity: 0.8;
    text-align: center;
}
.play-history-empty { padding: 14px; opacity: 0.6; font-size: 0.9rem; text-align: center; }

.play-confirm-modal {
    position: fixed; inset: 0;
    display: flex; align-items: center; justify-content: center;
    z-index: 100;
}
.play-confirm-modal[hidden] { display: none; }
.play-confirm-backdrop {
    position: absolute; inset: 0;
    background: rgba(0, 0, 0, 0.5);
    cursor: pointer;
}
.play-confirm-card {
    position: relative;
    background: #fff;
    color: #1d1f23;
    padding: 22px 26px;
    border-radius: 10px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
    min-width: 280px;
    max-width: 92vw;
    text-align: center;
}
body.dark-mode .play-confirm-card { background: #2c2e34; color: #f5f5f5; }
.play-confirm-title {
    margin: 0 0 8px;
    font-weight: 600;
    font-size: 1.02rem;
}
.play-confirm-body {
    margin: 0 0 16px;
    font-size: 0.92rem;
    opacity: 0.85;
    line-height: 1.4;
}
.play-confirm-body[hidden] { display: none; }
.play-confirm-actions {
    display: flex; gap: 10px; justify-content: center;
    margin-top: 14px;
}
.play-confirm-btn {
    padding: 8px 18px;
    border-radius: 6px;
    border: 1px solid rgba(0, 0, 0, 0.2);
    background: rgba(0, 0, 0, 0.05);
    color: inherit;
    cursor: pointer;
    font: inherit;
    font-size: 0.95rem;
    min-width: 96px;
}
body.dark-mode .play-confirm-btn {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.15);
}
.play-confirm-btn-ok {
    background: #c2410c;
    color: #fff;
    border-color: #c2410c;
}
.play-confirm-btn-ok:hover { background: #9a3309; border-color: #9a3309; }
/* Force-end offers one button per outcome, stacked so a long player name
   doesn't squeeze the others out of the row. */
.play-admin-choices {
    display: flex; flex-direction: column; gap: 8px;
    margin-top: 4px;
}
.play-admin-choices:empty { display: none; }
.play-admin-choice { width: 100%; }
.play-admin-choice-busy { opacity: 0.6; }


.play-takeback-incoming {
    box-shadow: 0 0 0 2px #c2410c, 0 0 8px rgba(194, 65, 12, 0.4);
    animation: play-takeback-pulse 1.4s ease-in-out infinite;
}
@keyframes play-takeback-pulse {
    0%, 100% { box-shadow: 0 0 0 2px #c2410c, 0 0 6px rgba(194, 65, 12, 0.4); }
    50% { box-shadow: 0 0 0 2px #c2410c, 0 0 14px rgba(194, 65, 12, 0.7); }
}
.play-replay-controls { display: flex; gap: 4px; margin-top: 10px; flex-wrap: wrap; align-items: center; }
.play-replay-controls[hidden] { display: none; }
.play-replay-live { color: #b91c1c; }
body.dark-mode .play-replay-live { color: #f87171; }

.play-chat-form {
    display: flex;
    gap: 0;
    margin: 0;
    width: 100%;
    align-items: stretch;
}
.play-chat-form[hidden] { display: none; }
.play-chat-input {
    flex: 1;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-bottom: none;
    border-radius: 0;
    background: transparent;
    color: inherit;
    font-family: inherit;
    font-size: 0.92rem;
    outline: none;
}
body.dark-mode .play-chat-input {
    border-color: rgba(255, 255, 255, 0.18);
}
.play-chat-send {
    flex-shrink: 0;
    width: 44px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-left: none;
    border-bottom: none;
    border-radius: 0;
    background: transparent;
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.play-chat-send:hover { background: rgba(0, 0, 0, 0.06); }
body.dark-mode .play-chat-send { border-color: rgba(255, 255, 255, 0.18); }
body.dark-mode .play-chat-send:hover { background: rgba(255, 255, 255, 0.08); }

/* ---- The chat log ----
   Everything said at this board, kept on the match and shown above the move
   list. It shares the box the input and the history already merge into: the
   input's missing bottom border is this log's top edge. */
.play-chat-log {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 180px;
    overflow-y: auto;
    padding: 8px 10px;
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-bottom: none;
    font-size: 0.88rem;
}
.play-chat-log[hidden] { display: none; }
body.dark-mode .play-chat-log { border-color: rgba(255, 255, 255, 0.1); }
.play-chat-msg { line-height: 1.4; overflow-wrap: anywhere; }
.play-chat-msg-name { font-weight: 600; margin-right: 6px; }
.play-chat-msg-gote .play-chat-msg-name { opacity: 0.7; }

/* An emoji that is a piece: the same boxwood tile the board draws, scaled to
   ride in a line of text. The tile SVG is display:block 1.6em elsewhere; here
   it fills the inline box. */
.play-chat-emoji {
    display: inline-flex;
    width: 1.1em;
    height: 1.2em;
    vertical-align: -0.22em;
    margin: 0 0.06em;
}
.play-chat-emoji .piece-koma-svg { width: 100%; height: 100%; }

/* The emoji tray: a drawer that opens between the input and the log rather
   than a floating panel, so it cannot cover the board on a phone. */
.play-chat-emoji-pop {
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-bottom: none;
    padding: 8px 10px;
}
.play-chat-emoji-pop[hidden] { display: none; }
body.dark-mode .play-chat-emoji-pop { border-color: rgba(255, 255, 255, 0.1); }
.play-chat-emoji-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
}
.play-chat-emoji-label {
    margin: 8px 0 4px;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--c-font-dim);
}
.play-chat-emoji-opt {
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 6px;
    background: transparent;
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}
.play-chat-emoji-opt:hover { background: rgba(0, 0, 0, 0.07); }
body.dark-mode .play-chat-emoji-opt:hover { background: rgba(255, 255, 255, 0.1); }
.play-chat-emoji-opt-piece .play-chat-emoji {
    width: 1.35em;
    height: 1.48em;
    vertical-align: baseline;
    margin: 0;
}

.play-sync-indicator {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.8rem;
    opacity: 0.75;
    margin-left: 8px;
}
.play-sync-indicator[hidden] { display: none; }
.play-sync-indicator svg { animation: play-icon-spin 1.2s linear infinite; }

/* ------------------------------------------------------------------ */
/* Opening editor / viewer                                            */
/* ------------------------------------------------------------------ */

/* The viewer carries `wiki-editor-only`, which the global rule turns into
 * `display: inline-flex` for editors. Override to keep block layout. */
body.is-wiki-editor .opening-viewer.wiki-editor-only { display: block; }

.opening-viewer {
    margin: 18px 0 28px 0;
    padding: 20px 22px 18px;
    border: 1px solid rgba(0,0,0,0.08);
    border-radius: 14px;
    background: #fdfaf2;
    box-shadow: 0 1px 3px rgba(0,0,0,0.04), 0 6px 16px rgba(0,0,0,0.04);
}
body.dark-mode .opening-viewer {
    border-color: rgba(255,255,255,0.10);
    background: #232020;
    box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}

.opening-viewer-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
    padding-bottom: 14px;
    border-bottom: 1px solid rgba(0,0,0,0.08);
}
body.dark-mode .opening-viewer-header { border-bottom-color: rgba(255,255,255,0.10); }

.opening-viewer-toggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}
.opening-viewer-toggle-label {
    font-size: 0.82rem;
    opacity: 0.65;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
}
.opening-viewer-toggle-btn {
    border: 1px solid rgba(0,0,0,0.16);
    background: transparent;
    padding: 6px 14px;
    font: inherit;
    color: inherit;
    font-size: 0.88rem;
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.opening-viewer-toggle-btn:first-of-type {
    border-radius: 8px 0 0 8px;
}
.opening-viewer-toggle-btn:last-of-type {
    border-radius: 0 8px 8px 0;
    border-left: none;
}
body.dark-mode .opening-viewer-toggle-btn { border-color: rgba(255,255,255,0.20); }
body.dark-mode .opening-viewer-toggle-btn:last-of-type { border-left: none; }
.opening-viewer-toggle-btn:hover { background: rgba(0,0,0,0.04); }
body.dark-mode .opening-viewer-toggle-btn:hover { background: rgba(255,255,255,0.06); }
.opening-viewer-toggle-btn-active {
    background: #1f1d1d;
    color: #fdfaf2;
    border-color: #1f1d1d;
}
body.dark-mode .opening-viewer-toggle-btn-active {
    background: #fdfaf2;
    color: #1f1d1d;
    border-color: #fdfaf2;
}

.opening-viewer-side-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 14px;
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}
.opening-viewer-side-sente { background: rgba(26,127,58,0.14); color: #1a7f3a; }
.opening-viewer-side-gote  { background: rgba(185,28,28,0.14); color: #b91c1c; }
body.dark-mode .opening-viewer-side-sente { background: rgba(74,222,128,0.18); color: #4ade80; }
body.dark-mode .opening-viewer-side-gote  { background: rgba(248,113,113,0.18); color: #f87171; }

.opening-viewer-layout {
    display: grid;
    grid-template-columns: minmax(280px, 380px) minmax(0, 1fr);
    gap: 20px;
    align-items: start;
}
@media (max-width: 720px) {
    .opening-viewer-layout { grid-template-columns: 1fr; }
}

.opening-viewer-board-col,
.opening-editor-board-col {
    display: flex;
    flex-direction: column;
    gap: 6px;
    align-items: stretch;
    min-width: 0;
}
.opening-viewer-board-col { max-width: 380px; }

.opening-viewer-hand,
.opening-editor-hand {
    min-height: 34px;
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 4px 6px;
    align-items: center;
    background: rgba(0,0,0,0.025);
    border-radius: 6px;
}
body.dark-mode .opening-viewer-hand,
body.dark-mode .opening-editor-hand { background: rgba(255,255,255,0.04); }

.opening-viewer-board.play-board,
.opening-board.play-board {
    max-width: 100%;
}

.opening-viewer-controls,
.opening-editor-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-items: center;
    padding-top: 6px;
    justify-content: center;
}
.opening-viewer-nav,
.opening-editor-nav {
    border: 1px solid rgba(0,0,0,0.18);
    background: transparent;
    padding: 6px 12px;
    font-size: 0.95rem;
    cursor: pointer;
    border-radius: 6px;
    line-height: 1;
    color: inherit;
    min-width: 38px;
    transition: background-color 0.12s ease;
}
body.dark-mode .opening-viewer-nav,
body.dark-mode .opening-editor-nav {
    border-color: rgba(255,255,255,0.22);
    color: #f5f5f5;
}
.opening-viewer-nav:hover,
.opening-editor-nav:hover { background: rgba(0,0,0,0.06); }
body.dark-mode .opening-viewer-nav:hover,
body.dark-mode .opening-editor-nav:hover { background: rgba(255,255,255,0.08); }

.opening-viewer-side-col,
.opening-editor-side-col {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

.opening-viewer-status,
.opening-editor-status-line {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 600;
    font-size: 0.95rem;
    line-height: 1.3;
    padding: 8px 12px;
    background: rgba(0,0,0,0.03);
    border-radius: 8px;
}
body.dark-mode .opening-viewer-status,
body.dark-mode .opening-editor-status-line { background: rgba(255,255,255,0.04); }
.opening-viewer-status-label-muted { opacity: 0.55; font-weight: 500; font-style: italic; }
.opening-viewer-status-dot,
.opening-editor-turn-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}
.opening-viewer-status-dot-player,
.opening-editor-turn-dot-player { background: #1a7f3a; }
.opening-viewer-status-dot-opponent,
.opening-editor-turn-dot-opponent { background: #b91c1c; }
body.dark-mode .opening-viewer-status-dot-player,
body.dark-mode .opening-editor-turn-dot-player { background: #4ade80; }
body.dark-mode .opening-viewer-status-dot-opponent,
body.dark-mode .opening-editor-turn-dot-opponent { background: #f87171; }
.opening-editor-status-line.opening-status-error { color: #b91c1c; }
body.dark-mode .opening-editor-status-line.opening-status-error { color: #f87171; }

.opening-viewer-comment {
    font-size: 0.92rem;
    line-height: 1.55;
    opacity: 0.88;
    white-space: pre-wrap;
    padding: 8px 10px;
    background: rgba(0,0,0,0.04);
    border-left: 3px solid rgba(0,0,0,0.18);
    border-radius: 0 4px 4px 0;
}
body.dark-mode .opening-viewer-comment {
    background: rgba(255,255,255,0.05);
    border-left-color: rgba(255,255,255,0.25);
}
.opening-viewer-comment:empty { display: none; }

.opening-viewer-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 480px;
    overflow-y: auto;
    padding: 4px 6px 4px 0;
    margin-top: 4px;
}
.opening-viewer-list::-webkit-scrollbar { width: 6px; }
.opening-viewer-list::-webkit-scrollbar-thumb {
    background: rgba(0,0,0,0.18);
    border-radius: 3px;
}
body.dark-mode .opening-viewer-list::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.22); }

.opening-list-empty {
    margin: 24px 0;
    padding: 22px 16px;
    text-align: center;
    opacity: 0.6;
    font-style: italic;
    border: 1px dashed rgba(0,0,0,0.14);
    border-radius: 8px;
    font-size: 0.9rem;
}
body.dark-mode .opening-list-empty { border-color: rgba(255,255,255,0.18); }

.opening-list-step {
    display: grid;
    grid-template-columns: 26px 1fr;
    column-gap: 10px;
    row-gap: 2px;
    padding: 8px 10px;
    border-radius: 8px;
    transition: background-color 0.12s ease;
}
.opening-list-step:hover { background: rgba(0,0,0,0.03); }
body.dark-mode .opening-list-step:hover { background: rgba(255,255,255,0.04); }

.opening-list-num {
    font-weight: 700;
    color: rgba(0,0,0,0.4);
    text-align: right;
    font-size: 0.95rem;
    padding-top: 2px;
    font-variant-numeric: tabular-nums;
}
body.dark-mode .opening-list-num { color: rgba(255,255,255,0.45); }

.opening-list-player-line,
.opening-list-opp-line {
    display: flex;
    align-items: baseline;
    gap: 6px;
    flex-wrap: wrap;
    line-height: 1.5;
}
.opening-list-opp-line {
    grid-column: 2;
    margin-left: 4px;
    margin-top: 2px;
    opacity: 0.72;
    font-size: 0.86rem;
}
.opening-list-opp-arrow {
    color: rgba(0,0,0,0.35);
    flex-shrink: 0;
    font-weight: bold;
}
body.dark-mode .opening-list-opp-arrow { color: rgba(255,255,255,0.4); }
.opening-list-opp-label {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.55;
    font-weight: 600;
}

.opening-list-btn {
    border: none;
    background: transparent;
    padding: 3px 9px;
    border-radius: 5px;
    cursor: pointer;
    font: inherit;
    color: inherit;
    line-height: 1.4;
    transition: background-color 0.12s ease, transform 0.06s ease;
}
.opening-list-btn:active { transform: translateY(1px); }
.opening-list-player-move {
    font-weight: 700;
    font-size: 1.02rem;
    color: #1a7f3a;
}
body.dark-mode .opening-list-player-move { color: #4ade80; }
.opening-list-opp-move {
    font-weight: 500;
    color: rgba(0,0,0,0.72);
    font-size: 0.92rem;
}
body.dark-mode .opening-list-opp-move { color: rgba(255,255,255,0.78); }
.opening-list-btn:hover { background: rgba(0,0,0,0.08); }
body.dark-mode .opening-list-btn:hover { background: rgba(255,255,255,0.10); }
.opening-list-btn-current {
    background: rgba(255,165,0,0.32);
    box-shadow: 0 0 0 1px rgba(255,165,0,0.5) inset;
}
body.dark-mode .opening-list-btn-current { background: rgba(255,180,80,0.30); }

.opening-list-comment {
    font-size: 0.85rem;
    font-style: italic;
    opacity: 0.7;
}

.opening-list-opening {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 6px 10px;
    margin-bottom: 4px;
    background: rgba(0,0,0,0.04);
    border-radius: 6px;
    flex-wrap: wrap;
}
body.dark-mode .opening-list-opening { background: rgba(255,255,255,0.05); }
.opening-list-opening-label {
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.65;
}

.opening-list-alts {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    flex-wrap: wrap;
    margin-left: 4px;
    font-size: 0.82rem;
}
.opening-list-alts-label {
    opacity: 0.55;
    font-style: italic;
}
.opening-list-alt-chip {
    border: 1px dashed rgba(0,0,0,0.25);
    background: transparent;
    padding: 1px 6px;
    border-radius: 10px;
    font: inherit;
    color: inherit;
    font-size: 0.82rem;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
body.dark-mode .opening-list-alt-chip { border-color: rgba(255,255,255,0.30); }
.opening-list-alt-chip:hover {
    background: rgba(0,0,0,0.06);
    border-style: solid;
}
body.dark-mode .opening-list-alt-chip:hover { background: rgba(255,255,255,0.08); }
.opening-list-alt-chip-current {
    background: rgba(255,165,0,0.30);
    border-style: solid;
    border-color: rgba(255,165,0,0.6);
    font-weight: 600;
}

.opening-list-variation-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    margin-top: 6px;
    background: rgba(255,165,0,0.10);
    border: 1px solid rgba(255,165,0,0.30);
    border-radius: 6px;
    font-size: 0.88rem;
    flex-wrap: wrap;
}
.opening-list-variation-icon {
    color: rgba(180,90,0,0.9);
    font-size: 1rem;
}
body.dark-mode .opening-list-variation-icon { color: rgba(255,180,80,0.9); }
.opening-list-variation-text { flex: 1; min-width: 0; }
.opening-list-back-mainline {
    border: 1px solid rgba(0,0,0,0.2);
    background: transparent;
    padding: 4px 10px;
    border-radius: 4px;
    cursor: pointer;
    font: inherit;
    color: inherit;
    font-size: 0.85rem;
}
body.dark-mode .opening-list-back-mainline { border-color: rgba(255,255,255,0.3); }

.opening-viewer-empty {
    margin: 16px 0;
    padding: 18px;
    text-align: center;
    opacity: 0.7;
    font-style: italic;
    border: 1px dashed rgba(0,0,0,0.18);
    border-radius: 6px;
}
body.dark-mode .opening-viewer-empty { border-color: rgba(255,255,255,0.22); }

/* Editor side toggle */
.opening-side-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
    padding: 6px 10px;
    background: rgba(0,0,0,0.04);
    border-radius: 8px;
}
body.dark-mode .opening-side-toggle { background: rgba(255,255,255,0.05); }
.opening-side-toggle-label {
    font-size: 0.85rem;
    opacity: 0.75;
}
.opening-side-toggle-btn {
    border: 1px solid rgba(0,0,0,0.18);
    background: transparent;
    padding: 4px 12px;
    border-radius: 6px;
    cursor: pointer;
    font: inherit;
    color: inherit;
    font-size: 0.88rem;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
body.dark-mode .opening-side-toggle-btn { border-color: rgba(255,255,255,0.25); }
.opening-side-toggle-btn:hover { background: rgba(0,0,0,0.06); }
body.dark-mode .opening-side-toggle-btn:hover { background: rgba(255,255,255,0.08); }
.opening-side-toggle-btn-active {
    background: #1a7f3a;
    border-color: #1a7f3a;
    color: #fff;
}
.opening-side-toggle-btn-active:hover { background: #166b30; }

/* Editor's full tree (kept tree-shaped for editing) */
.opening-tree-list {
    list-style: decimal;
    margin: 4px 0 4px 20px;
    padding: 0;
}
.opening-tree-li { margin: 2px 0; line-height: 1.5; }
.opening-tree-move {
    border: none; background: transparent;
    padding: 1px 6px; border-radius: 4px;
    cursor: pointer; font: inherit; color: inherit;
}
.opening-tree-move:hover { background: rgba(0,0,0,0.08); }
body.dark-mode .opening-tree-move:hover { background: rgba(255,255,255,0.12); }
.opening-tree-move-current {
    background: rgba(255,165,0,0.32);
    font-weight: 700;
}
body.dark-mode .opening-tree-move-current { background: rgba(255,165,0,0.32); }
.opening-tree-gote .opening-tree-move { font-style: italic; opacity: 0.85; }
.opening-tree-comment-inline { opacity: 0.75; font-size: 0.85rem; }
.opening-tree-variation {
    margin: 2px 0 4px 12px;
    padding-left: 8px;
    border-left: 2px solid rgba(255,165,0,0.4);
}
body.dark-mode .opening-tree-variation { border-left-color: rgba(255,180,80,0.4); }
.opening-tree-empty { opacity: 0.6; font-style: italic; }
.opening-tree-comment { font-size: 0.88rem; opacity: 0.8; }

/* Editor modal */
.opening-editor-modal {
    position: fixed;
    inset: 0;
    z-index: 1200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
}
.opening-editor-modal[hidden] { display: none; }
.opening-editor-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0,0,0,0.45);
}
.opening-editor-card {
    position: relative;
    background: #fdfaf2;
    border: 1px solid rgba(0,0,0,0.2);
    border-radius: 10px;
    width: min(960px, 100%);
    max-height: 92vh;
    overflow-y: auto;
    padding: 18px 20px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.35);
}
body.dark-mode .opening-editor-card {
    background: #1f1d1d;
    border-color: rgba(255,255,255,0.18);
    color: #f5f5f5;
}
.opening-editor-close {
    position: absolute;
    top: 6px;
    right: 10px;
    background: transparent;
    border: none;
    font-size: 1.6rem;
    line-height: 1;
    cursor: pointer;
    color: inherit;
}
.opening-editor-title {
    font-size: 1.15rem;
    margin: 0 0 4px 0;
}
.opening-editor-hint {
    font-size: 0.88rem;
    opacity: 0.75;
    margin: 0 0 12px 0;
}
.opening-editor-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 16px;
    align-items: start;
}
@media (max-width: 760px) {
    .opening-editor-layout { grid-template-columns: 1fr; }
}
.opening-editor-board.play-board { max-width: 100%; }
.opening-editor-comment {
    width: 100%;
    min-height: 56px;
    resize: vertical;
    padding: 6px 8px;
    border: 1px solid rgba(0,0,0,0.2);
    border-radius: 4px;
    font: inherit;
    background: transparent;
    color: inherit;
    box-sizing: border-box;
}
body.dark-mode .opening-editor-comment { border-color: rgba(255,255,255,0.25); }
.opening-editor-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    flex-wrap: wrap;
}
.opening-editor-btn {
    padding: 6px 14px;
    border: 1px solid rgba(0,0,0,0.25);
    border-radius: 4px;
    background: transparent;
    cursor: pointer;
    font: inherit;
    color: inherit;
}
.opening-editor-btn:disabled { opacity: 0.5; cursor: not-allowed; }
body.dark-mode .opening-editor-btn { border-color: rgba(255,255,255,0.3); }
.opening-editor-btn-primary {
    background: #1a7f3a;
    color: #fff;
    border-color: #1a7f3a;
}
.opening-editor-btn-primary:hover { background: #166b30; }
.opening-editor-promotion {
    margin-top: 12px;
    padding: 10px 12px;
    border: 1px dashed rgba(0,0,0,0.25);
    border-radius: 6px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
body.dark-mode .opening-editor-promotion { border-color: rgba(255,255,255,0.3); }
.opening-editor-promotion-text { margin: 0; font-weight: 600; }
.opening-editor-promotion-actions { display: flex; gap: 8px; }
.opening-hand-piece { cursor: pointer; }
.opening-hand-empty { opacity: 0.4; font-size: 0.9rem; padding: 0 4px; }

/* --- Donation: sidebar button, floating pill, Pix modal --- */
.dropbutton-donate {
    background: none;
    border: none;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
    padding: 8px;
    border-radius: 5px;
}
.dropbutton-donate:hover { color: #d33b6b; }

.donate-pill {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 90;
    display: flex;
    align-items: stretch;
    background-color: #d33b6b;
    color: #fff;
    border-radius: 999px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
    overflow: hidden;
    animation: donate-pop 0.35s ease;
}
@media (max-width: 900px) {
    .donate-pill {
        top: calc(10px + env(safe-area-inset-top, 0px));
        right: 10px;
        bottom: auto;
    }
}
@keyframes donate-pop {
    from { opacity: 0; transform: translateY(12px) scale(0.92); }
    to   { opacity: 1; transform: none; }
}
.donate-pill-main {
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    font: inherit;
    font-weight: 600;
    padding: 11px 16px;
    white-space: nowrap;
}
.donate-pill-main:hover { background-color: rgba(255, 255, 255, 0.12); }
.donate-pill-close {
    background: none;
    border: none;
    border-left: 1px solid rgba(255, 255, 255, 0.3);
    color: inherit;
    cursor: pointer;
    display: flex;
    align-items: center;
    padding: 0 10px;
}
.donate-pill-close:hover { background-color: rgba(255, 255, 255, 0.18); }

.donate-dialog {
    width: min(420px, 100%);
    padding: 24px;
    text-align: center;
    align-items: center;
}
.donate-close { position: absolute; top: 10px; right: 10px; }
.donate-title { margin: 4px 0 8px; font-size: 1.3em; }
.donate-why { margin: 0 0 16px; opacity: 0.85; line-height: 1.5; font-size: 0.95em; }
.donate-qr {
    width: 220px;
    height: 220px;
    margin: 0 auto 8px;
    background: #fff;
    border-radius: 10px;
    padding: 8px;
    box-sizing: content-box;
    display: flex;
    align-items: center;
    justify-content: center;
}
.donate-qr:empty { display: none; }
/* While qrcode.js is on its way: the box holds its place so the dialog does
   not grow by 220 px when the SVG arrives. */
.donate-qr.donate-qr-pending:empty { display: block; min-height: 220px; }
.donate-scan { margin: 0 0 16px; font-size: 0.85em; opacity: 0.7; }
.donate-key-row {
    display: flex;
    align-items: stretch;
    gap: 8px;
    width: 100%;
    margin-bottom: 16px;
}
.donate-key-block {
    flex: 1;
    min-width: 0;
    text-align: left;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 8px;
    padding: 8px 12px;
}
body.dark-mode .donate-key-block { border-color: rgba(255, 255, 255, 0.2); }
.donate-key-label { display: block; font-size: 0.7em; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.6; }
.donate-key {
    display: block;
    font-family: monospace;
    font-size: 0.9em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.donate-copy {
    background-color: #d33b6b;
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 0 16px;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: filter 0.15s ease;
}
.donate-copy:hover { filter: brightness(1.08); }
.donate-thanks { margin: 0 0 14px; font-size: 0.9em; opacity: 0.8; }
.donate-dismiss {
    background: none;
    border: none;
    color: inherit;
    opacity: 0.55;
    cursor: pointer;
    font: inherit;
    font-size: 0.85em;
    text-decoration: underline;
}
.donate-dismiss:hover { opacity: 0.85; }

/* Mobile: the modal slides up as a bottom sheet ("slightly different"). */
.donate-modal--mobile { align-items: flex-end; padding: 0; }
.donate-modal--mobile .donate-dialog {
    width: 100%;
    border-radius: 18px 18px 0 0;
    max-height: 92vh;
    animation: donate-sheet-up 0.3s ease;
}
@keyframes donate-sheet-up {
    from { transform: translateY(100%); }
    to   { transform: none; }
}



/* ======================================================================
   Wiki + games home, and the forum
   ====================================================================== */

/* --- Sidebar --- */
.sidebar-logo {
    display: inline-flex;
    align-items: center;
    line-height: 0;
    padding: 0;
}
.sidebar-logo img { display: block; }
/* The generic .leftdiv a underline would slide under the logo on hover. */
.sidebar-logo::after { content: none; }

/* --- Home hero --- */
.home-hero {
    padding: 34px 16px 26px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
body.dark-mode .home-hero { border-bottom-color: rgba(255, 255, 255, 0.1); }

.home-hero-title {
    margin: 0;
    font-size: 2em;
    font-weight: bold;
    letter-spacing: 0.01em;
}
.home-hero-tagline {
    margin: 6px 0 0;
    font-size: 1.05em;
    opacity: 0.8;
}
.home-hero-intro {
    margin: 12px 0 0;
    max-width: 46ch;
    line-height: 1.5;
    opacity: 0.62;
    font-size: 0.92em;
}
.home-hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 20px;
}

.home-cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 18px;
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: 999px;
    color: inherit;
    text-decoration: none;
    font-size: 0.95em;
    transition: border-color 0.15s ease, background-color 0.15s ease, transform 0.15s ease;
}
.home-cta:hover {
    border-color: rgba(0, 0, 0, 0.55);
    transform: translateY(-1px);
}
body.dark-mode .home-cta { border-color: rgba(255, 255, 255, 0.22); }
body.dark-mode .home-cta:hover { border-color: rgba(255, 255, 255, 0.6); }

.home-cta-primary {
    background-color: #1d1f23;
    border-color: #1d1f23;
    color: #ffffff;
}
.home-cta-primary:hover {
    background-color: #000000;
    border-color: #000000;
}
body.dark-mode .home-cta-primary {
    background-color: #ffffff;
    border-color: #ffffff;
    color: #1d1f23;
}
body.dark-mode .home-cta-primary:hover {
    background-color: #e6e6e6;
    border-color: #e6e6e6;
}

.home-cta-quiet {
    padding: 7px 14px;
    font-size: 0.88em;
    opacity: 0.75;
}

.home-wiki-card .pieces-index-kanji { font-size: 2em; }

/* The home page's forum block is built from .home-prose-body and the same
   .pieces-index rows as every other list on that page, so it carries no
   styles of its own. */

/* --- Forum page ---
   The title block claims the row and the button is pinned to the far end by
   its own flex, not only by the header's justify-content: whatever else the
   cascade does to .page-header, these two cannot end up touching. */
.forum-header { justify-content: space-between; gap: 16px; }
.forum-header-text {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
/* A long board name truncates rather than shoving the button. */
.forum-header .page-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.forum-new-btn {
    flex: 0 0 auto;
    margin-left: auto;
    gap: 7px;
    padding: 8px 16px;
    white-space: nowrap;
}
.forum-crumb {
    font-size: 0.8em;
    color: inherit;
    text-decoration: none;
    opacity: 0.6;
}
.forum-crumb:hover { opacity: 1; }

.forum-lead {
    margin: 4px 16px 0;
    font-size: 0.92em;
    line-height: 1.5;
    opacity: 0.7;
    max-width: 62ch;
}

/* The house rules: one calm band under the header, saying what is expected
   of a post before anyone writes one. */
.forum-rules {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 14px 16px 4px;
    padding: 12px 14px;
    border-left: 2px solid rgba(0, 0, 0, 0.25);
    background-color: rgba(0, 0, 0, 0.03);
    font-size: 0.88em;
    line-height: 1.5;
    opacity: 0.78;
}
body.dark-mode .forum-rules {
    border-left-color: rgba(255, 255, 255, 0.3);
    background-color: rgba(255, 255, 255, 0.05);
}
.forum-rules-icon {
    flex: 0 0 auto;
    margin-top: 2px;
    opacity: 0.7;
}

.forum-guest {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin: 10px 16px 0;
    font-size: 0.88em;
    line-height: 1.5;
    opacity: 0.8;
}
.forum-guest-cta {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid currentColor;
    white-space: nowrap;
}

/* --- Opening a thread --- */
.forum-composer {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 16px;
    padding: 18px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 12px;
}
body.dark-mode .forum-composer { border-color: rgba(255, 255, 255, 0.14); }
.forum-composer-heading { margin: 0; font-size: 1.05em; font-weight: 600; }
.forum-composer-as { margin: 0; font-size: 0.82em; opacity: 0.6; }
.forum-composer-as:empty { display: none; }
.forum-field { display: flex; flex-direction: column; gap: 6px; }
.forum-field-label {
    font-size: 0.75em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    opacity: 0.55;
}
.forum-subject-input {
    font: inherit;
    font-size: 1.05em;
    padding: 10px 14px;
    border-radius: 10px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    background-color: transparent;
    color: inherit;
    outline: none;
}
body.dark-mode .forum-subject-input { border-color: rgba(255, 255, 255, 0.18); }
.forum-composer-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
    flex-wrap: wrap;
}
.forum-composer-status { flex: 1 1 auto; font-size: 0.85em; opacity: 0.7; }
.forum-composer-status.is-error { color: #c0392b; opacity: 1; }
body.dark-mode .forum-composer-status.is-error { color: #ff8f80; }

/* --- The thread index ---
   A list of subjects, not a feed: one line for the subject, one for the
   meta, so every row is the same height and the eye can run down the
   column. The chips get their own right-hand slot for the same reason. */
.forum-list { display: flex; flex-direction: column; padding: 0 12px 8px; }

.forum-thread {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 11px 12px;
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
body.dark-mode .forum-thread { border-bottom-color: rgba(255, 255, 255, 0.08); }
.forum-thread:hover { background-color: rgba(0, 0, 0, 0.03); }
body.dark-mode .forum-thread:hover { background-color: rgba(255, 255, 255, 0.05); }

.forum-thread-avatar {
    width: 32px;
    height: 32px;
    flex: 0 0 32px;
    margin-top: 1px;
    border-radius: 50%;
    object-fit: cover;
}
.forum-thread-main { flex: 1 1 auto; min-width: 0; }
.forum-thread-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
}
.forum-thread-title {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.98em;
    font-weight: 600;
    line-height: 1.35;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.forum-thread-tags {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 6px;
}
.forum-thread-meta {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 3px;
    font-size: 0.76em;
    line-height: 1.4;
    opacity: 0.6;
    overflow: hidden;
    white-space: nowrap;
}
.forum-thread-meta-item { flex: 0 0 auto; }
.forum-thread-meta-sep { flex: 0 0 auto; opacity: 0.5; }
.forum-thread-author {
    font-weight: 500;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.forum-footer {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 8px 16px 40px;
}
.forum-more {
    background: none;
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: 999px;
    color: inherit;
    cursor: pointer;
    font: inherit;
    font-size: 0.88em;
    padding: 8px 20px;
    opacity: 0.75;
    transition: opacity 0.15s ease, border-color 0.15s ease;
}
.forum-more:hover { opacity: 1; border-color: rgba(0, 0, 0, 0.5); }
body.dark-mode .forum-more { border-color: rgba(255, 255, 255, 0.22); }
body.dark-mode .forum-more:hover { border-color: rgba(255, 255, 255, 0.6); }

.forum-end {
    font-size: 0.85em;
    opacity: 0.45;
    padding: 16px 0 0;
}

/* --- Thread page --- */
.thread-board-link {
    font-size: 0.85em;
    opacity: 0.6;
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid transparent;
    margin-left: 6px;
}
.thread-board-link:hover { opacity: 1; border-bottom-color: currentColor; }

.thread-title {
    margin: 4px 16px 0;
    font-size: 1.5em;
    font-weight: 600;
    line-height: 1.25;
    overflow-wrap: anywhere;
}

/* A thread's subject, wherever a post is rendered as a card. */
.feed-item-title {
    font-size: 1.05em;
    font-weight: 600;
    line-height: 1.3;
    margin-bottom: 2px;
    overflow-wrap: anywhere;
}

/* Replies are signed by the session; the composer says by whom. */
.composer-as {
    font-size: 0.8em;
    opacity: 0.6;
    margin-top: 8px;
}


/* ======================================================================
   Theme layer
   ----------------------------------------------------------------------
   Two skins over one structure.

   The site chrome - home, wiki, forum, profile, settings - is Material:
   rounded surfaces, pill controls, tonal hovers, dividers instead of
   frames.

   The play area keeps the flat, squared, dense Lishogi treatment. It is
   scoped by the body attributes the play views already carry
   ([data-play-page], [data-simul-code], [data-tournament-code]), so no
   markup changes are needed and the split cannot drift.
   ====================================================================== */

::selection { background: var(--c-accent); color: var(--c-on-accent); }

/* The UA rule for [hidden] is display:none at the lowest priority, so any
   author `display` on the element beats it. This layer sets display on a lot
   of things (fields, cards, chips), which silently un-hid elements that JS had
   marked hidden - the sign-up-only fields showed on the sign-in form. */
[hidden] { display: none !important; }

/* --- App shell ------------------------------------------------------ */
.content {
    box-sizing: border-box;
    background-color: var(--c-box);
    border: none;
    border-radius: var(--radius-lg);
    margin-top: 16px;
    margin-bottom: 24px;
    /* Same card height as the rail. 16 + (100vh - 40) + 24 = 100vh, so the
       page itself never scrolls - the column scrolls inside its own card. */
    height: calc(100vh - 40px);
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    box-shadow: var(--elev-1);
    scrollbar-width: thin;
    scrollbar-color: var(--c-border) transparent;
}
.content::-webkit-scrollbar { width: 10px; }
.content::-webkit-scrollbar-track { background: transparent; }
.content::-webkit-scrollbar-thumb {
    background-color: var(--c-border);
    border: 3px solid transparent;
    background-clip: content-box;
    border-radius: var(--radius-pill);
}
.content::-webkit-scrollbar-thumb:hover { background-color: var(--c-font-dim); }

/* --- Left rail: its own card, icon + label rows --------------------- */
.leftdiv {
    box-sizing: border-box;
    width: var(--rail-w);
    top: 16px;
    height: calc(100vh - 40px);
    gap: 5px;
    padding: 22px 12px 18px;
    justify-content: flex-start;
    align-items: stretch;
    font-size: 0.95em;
    background-color: var(--c-box);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-1);
}
body.dark-mode .leftdiv { background-color: var(--c-box); }
.leftdiv .sidebar-logo { margin: 0 0 26px 10px; }

.leftdiv .dropbutton-row {
    border-radius: var(--radius-pill);
    transition: background-color 0.12s ease;
}
.leftdiv .dropbutton-row:hover { background-color: var(--c-hover); }

.leftdiv .dropbutton-link {
    display: flex;
    align-items: center;
    gap: 14px;
    flex: 1;
    min-width: 0;
    width: 100%;
    padding: 11px 16px;
    border: none;
    border-radius: inherit;
    background: none;
    color: var(--c-font);
    font: inherit;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    transition: color 0.12s ease;
}
.leftdiv .dropbutton-link > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.nav-icon { flex: 0 0 20px; opacity: 0.75; }
.nav-tag {
    margin-left: auto;
    flex: 0 0 auto;
    font-size: 0.68em;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 0.5;
}

.leftdiv .dropbutton-arrow {
    order: 2;
    margin-right: 10px;
    color: var(--c-font-dim);
    background: none;
}

/* Where you are. */
.dropbutton.is-current > .dropbutton-row { background-color: var(--c-accent-soft); }
.dropbutton.is-current > .dropbutton-row > .dropbutton-link {
    color: var(--c-accent-on-soft);
    font-weight: 600;
}
.dropbutton.is-current .nav-icon { opacity: 1; }

.leftdiv .subitems a {
    padding: 9px 14px 9px 50px;
    margin-left: 0;
    border-radius: var(--radius-pill);
    font-size: 0.86em;
    color: var(--c-font-dim);
    opacity: 1;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.leftdiv .subitems a:hover { background-color: var(--c-hover); color: var(--c-font-strong); }

/* The sliding underline belongs to the old serif look - the pill replaces it. */
.leftdiv a::after,
.dropbutton-arrow::after { content: none; }

.sidebar-logo { padding: 0; }
.sidebar-logo::after { content: none; }

/* Compose is a nav item like the others. `.logged-in-only` turns display into
   inline-flex, which would shrink the row - restore flex. */
body.is-logged-in .leftdiv .dropbutton-compose { display: flex; }

/* The overflow entry exists only where the bar runs out of room. */
.dropbutton-more { display: none; }

/* The play menu is a phone thing: on the bar, tapping Jogar opens a small
   sheet (home / a board / a puzzle). On the rail Jogar stays a plain link,
   so its drawer never opens here - the phone block's `.dropbutton.expanded
   .subitems` rule is a class deeper and wins where the sheet belongs. */
.leftdiv nav[data-key="play"] .subitems { display: none; }

/* Footer of the rail: avatar row, then the utility switches. */
.sidebar-auth { padding: 10px 4px 0; align-items: stretch; }

/* Signed out, this is the only thing worth clicking down here - the bell,
   bookmarks, profile and log out are all .logged-in-only now. */
.sidebar-auth-login {
    justify-content: center;
    gap: 8px;
    width: 100%;
    padding: 10px 16px;
    border-radius: var(--radius-pill);
    background-color: var(--c-accent);
    color: var(--c-on-accent);
    font-weight: 600;
    font-size: 0.92em;
    opacity: 1;
    box-shadow: var(--elev-1);
    transition: background-color 0.12s ease, box-shadow 0.12s ease;
}
.sidebar-auth-login:hover {
    background-color: var(--c-accent-hover);
    box-shadow: var(--elev-2);
    opacity: 1;
}
.sidebar-auth-login svg { flex: 0 0 18px; }
.leftdiv .sidebar-shortcuts { margin-top: 6px; padding: 0 4px; gap: 4px; }
.leftdiv .sidebar-shortcut { color: var(--c-font-dim); }
.leftdiv .sidebar-shortcut:hover { background-color: var(--c-hover); color: var(--c-font-strong); }

/* --- Headers -------------------------------------------------------- */
.page-header,
.board-header {
    padding: 18px 24px 14px;
    background-color: transparent;
    border-bottom: 1px solid var(--c-border-soft);
}
body.dark-mode .page-header,
body.dark-mode .board-header { border-bottom-color: var(--c-border-soft); }

.page-title,
.board-title {
    font-size: 1.35em;
    font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--c-font-strong);
}
.page-title-tag { color: var(--c-font-dim); opacity: 1; }

.pieces-section-title {
    margin: 0;
    padding: 20px 24px 8px;
    background-color: transparent;
    border: none;
    font-size: 0.75em;
    font-weight: 600;
    letter-spacing: 0.08em;
    opacity: 1;
    color: var(--c-font-dim);
}

/* --- List rows ------------------------------------------------------ */
.pieces-index {
    display: flex;
    flex-direction: column;
    padding: 0 12px 8px;
}

.pieces-index-card {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    border: none;
    border-radius: var(--radius-md);
    transition: background-color 0.12s ease;
}
body.dark-mode .pieces-index-card { border: none; }

.pieces-index-card:hover,
body.dark-mode .pieces-index-card:hover {
    background-color: var(--c-hover);
    transform: none;
    box-shadow: none;
    border: none;
}

/* Rows with a kanji: glyph left, text stacked beside it. Browsers without
   :has() keep the stacked card. */
.pieces-index-card:has(> .pieces-index-kanji) {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    column-gap: 0;
    row-gap: 2px;
}
.pieces-index-card:has(> .pieces-index-kanji) > .pieces-index-kanji {
    grid-column: 1;
    grid-row: 1 / -1;
    align-self: center;
    /* Fixed so multi-glyph names (王/玉, 成銀) do not ragged-edge the titles. */
    width: 52px;
    margin-right: 12px;
    text-align: center;
}
.pieces-index-card:has(> .pieces-index-kanji) > .pieces-index-label,
.pieces-index-card:has(> .pieces-index-kanji) > .pieces-index-bottom,
.pieces-index-card:has(> .pieces-index-kanji) > .pieces-index-creator {
    grid-column: 2;
    min-width: 0;
}

.pieces-index-kanji {
    font-family: var(--font-kanji);
    font-size: 1.35em;
    line-height: 1.15;
    white-space: nowrap;
    opacity: 0.9;
}
.pieces-index-label { min-width: 0; }
.pieces-index-name {
    color: var(--c-font-strong);
    font-weight: 500;
    font-size: 0.98em;
}
.pieces-index-bottom {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    width: auto;
    max-width: none;
    text-align: left;
    margin-top: 0;
}
.pieces-index-bottom .pieces-index-move {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.pieces-index-bottom .pieces-index-upvotes { flex: 0 0 auto; }
.pieces-index-move { color: var(--c-font-dim); font-size: 0.82em; }
.pieces-index-creator { color: var(--c-font-dim); font-size: 0.76em; }
.pieces-index-upvotes { color: var(--c-font-dim); }
.pieces-index-popular { border-bottom: none; }

.wiki-tag-chip {
    border-radius: var(--radius-pill);
    background-color: var(--c-box-alt);
    color: inherit;
    padding: 3px 9px;
    min-width: 0;
    height: auto;
    font-size: 0.74em;
    font-weight: 500;
    gap: 4px;
}

/* --- Category chips: kanji, one tone each ---------------------------- */
.wiki-cat-chip { font-family: var(--font-kanji); font-size: 0.86em; }
.wiki-cat-pieces   { background-color: var(--tone-pieces-bg);   color: var(--tone-pieces-fg); }
.wiki-cat-castles  { background-color: var(--tone-castles-bg);  color: var(--tone-castles-fg); }
.wiki-cat-openings { background-color: var(--tone-openings-bg); color: var(--tone-openings-fg); }
.wiki-cat-culture  { background-color: var(--tone-culture-bg);  color: var(--tone-culture-fg); }

/* --- Difficulty ------------------------------------------------------
   Written out on the article page and still filterable; the list cards leave
   it off, so there is no meter here any more. */
.wiki-tag-chip.wiki-tag-beginner     { background-color: var(--tone-easy-bg);   color: var(--tone-easy-fg); }
.wiki-tag-chip.wiki-tag-intermediate { background-color: var(--tone-medium-bg); color: var(--tone-medium-fg); }
.wiki-tag-chip.wiki-tag-advanced     { background-color: var(--tone-hard-bg);   color: var(--tone-hard-fg); }

/* The remaining tags keep their existing hues, now on a tonal pill. */
.wiki-tag-chip.wiki-tag-variant   { background-color: rgba(125, 61, 163, 0.14); }
.wiki-tag-chip.wiki-tag-yagura    { background-color: rgba(44, 111, 181, 0.14); }
.wiki-tag-chip.wiki-tag-mino      { background-color: rgba(192, 136, 63, 0.16); }
.wiki-tag-chip.wiki-tag-ibisha    { background-color: rgba(15, 138, 138, 0.14); }
.wiki-tag-chip.wiki-tag-furibisha { background-color: rgba(192, 57, 138, 0.14); }


.pages-empty,
.page-empty,
.page-loading { color: var(--c-font-dim); opacity: 1; padding: 18px 12px; }
.feed .page-loading, .feed .page-empty { padding: 32px 12px; }

/* --- Feed rows (thread, bookmarks, profile) ------------------------- */
.feed {
    padding: 0 12px 8px;
}
.feed-item,
body.dark-mode .feed-item {
    padding: 14px 12px;
    border-bottom: 1px solid var(--c-border-soft);
    border-radius: var(--radius-md);
}
.feed-item-clickable:hover,
body.dark-mode .feed-item-clickable:hover { background-color: var(--c-hover); }
.feed-item-name { color: var(--c-font-strong); }
.feed-item-handle { color: var(--c-font-dim); }
.feed-action { color: var(--c-font-dim); opacity: 1; border-radius: var(--radius-pill); }
.feed-action:hover { color: var(--c-accent); }
.feed-item-title { color: var(--c-font-strong); }

/* --- Links (prose only: card rows and icon buttons are links too) ---- */
.wiki-body-rendered a,
.feed-item-text a,
.feed-comment-text a,
.forum-rules a,
.thread-board-link {
    color: var(--c-accent);
    text-decoration: none;
}
.wiki-body-rendered a:hover,
.feed-item-text a:hover,
.feed-comment-text a:hover,
.forum-rules a:hover,
.thread-board-link:hover { text-decoration: underline; }

/* --- Buttons: Material pills ---------------------------------------- */
.home-cta,
.forum-more,
.compose-button,
.auth-submit,
.ban-ok,
.modal-confirm,
.play-modal-primary,
body.dark-mode .home-cta,
body.dark-mode .forum-more {
    border-radius: var(--radius-pill);
    border: 1px solid var(--c-border);
    background-color: transparent;
    color: var(--c-accent);
    font-weight: 500;
    letter-spacing: 0.01em;
    padding: 9px 22px;
    transition: background-color 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
}
.home-cta:hover,
.forum-more:hover,
body.dark-mode .home-cta:hover,
body.dark-mode .forum-more:hover {
    background-color: var(--c-accent-soft);
    border-color: var(--c-border);
    color: var(--c-accent-on-soft);
    transform: none;
}

/* Filled tonal button - the primary action. Declared after the outlined
   rule above because both are single-class selectors. */
.home-cta.home-cta-primary,
body.dark-mode .home-cta.home-cta-primary,
.compose-button,
.auth-submit,
.ban-ok,
.modal-confirm,
.play-modal-primary {
    background-color: var(--c-accent);
    border-color: var(--c-accent);
    color: var(--c-on-accent);
    box-shadow: var(--elev-1);
}
.home-cta.home-cta-primary:hover,
body.dark-mode .home-cta.home-cta-primary:hover,
.compose-button:hover,
.auth-submit:hover,
.ban-ok:hover,
.modal-confirm:hover,
.play-modal-primary:hover {
    background-color: var(--c-accent-hover);
    border-color: var(--c-accent-hover);
    color: var(--c-on-accent);
    box-shadow: var(--elev-2);
}
.home-cta-quiet {
    padding: 7px 18px;
    font-size: 0.88em;
    box-shadow: none;
}
/* The other side of the same scale: a section's one real entrance, sized so
   it reads as the action of the block rather than as another link in it. */
.home-cta-wide {
    padding: 14px 34px;
    font-size: 1.05em;
    font-weight: 600;
}
.home-forum-actions { display: flex; margin-top: 14px; }
@media (max-width: 600px) {
    .home-cta-wide { width: 100%; justify-content: center; }
}

.pages-create-btn {
    color: var(--c-font-dim);
    border-radius: var(--radius-pill);
    padding: 8px;
}
.pages-create-btn:hover { color: var(--c-accent); background-color: var(--c-hover); }

/* --- Fields: rounded, Google search style --------------------------- */
.wiki-filter { padding: 12px 24px 4px; background-color: transparent; border: none; }
.wiki-filter-search,
.wiki-filter-select,
.modal-lishogi-input,
.play-time-control-select,
.play-share-input,
body.dark-mode .wiki-filter-search,
body.dark-mode .wiki-filter-select {
    background-color: var(--c-box-alt);
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    color: var(--c-font);
    padding: 10px 18px;
}
.wiki-filter-search:focus,
.wiki-filter-select:focus,
.modal-lishogi-input:focus,
.play-time-control-select:focus {
    border-color: var(--c-accent);
    outline: none;
    background-color: var(--c-box);
    box-shadow: var(--elev-1);
}

/* --- Home ------------------------------------------------------------ */
.home-hero {
    display: flex;
    align-items: center;
    gap: 28px;
    padding: 32px 24px;
    background-color: transparent;
    border-bottom: 1px solid var(--c-border-soft);
}
.home-hero-text { flex: 1 1 auto; min-width: 0; }
.home-hero-title {
    font-size: 2.1em;
    font-weight: 500;
    letter-spacing: -0.02em;
    color: var(--c-font-strong);
}
.home-hero-tagline { color: var(--c-font); opacity: 1; font-size: 1.02em; margin-top: 8px; }
.home-hero-intro { color: var(--c-font-dim); opacity: 1; margin-top: 10px; }
.home-hero-actions { margin-top: 22px; }

/* The board is the same black-and-white one the matches use - it reuses
   .play-board / .play-cell / .play-piece, so it can never drift from it.
   Only the size and the caption belong here. */
.home-showcase {
    flex: 0 0 auto;
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}
.home-board {
    width: 246px;
    user-select: none;
}
.home-board .play-cell { cursor: default; }
.home-board .play-piece { font-size: 17px; font-weight: 600; }
.home-showcase-caption {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 0.74em;
    letter-spacing: 0.02em;
    color: var(--c-font-dim);
    min-height: 1.4em;
}
.home-showcase-players {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: inherit;
    text-decoration: none;
    border-radius: var(--radius-pill);
    padding: 3px 8px;
    transition: background-color 0.12s ease;
}
a.home-showcase-players:hover { background-color: var(--c-hover); }
.home-showcase-player { display: inline-flex; align-items: center; gap: 5px; min-width: 0; }
.home-showcase-avatar {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 18px;
}
.home-showcase-name {
    color: var(--c-font-strong);
    font-weight: 500;
    max-width: 84px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.home-showcase-vs { opacity: 0.6; }
.home-showcase-ply { font-variant-numeric: tabular-nums; opacity: 0.75; }

@media (max-width: 820px) {
    .home-hero { flex-direction: column; align-items: flex-start; }
    .home-showcase { align-self: center; }
    .home-board { width: 214px; }
    .home-board .play-piece { font-size: 15px; }
}

/* --- Studies hub ----------------------------------------------------- */
.studies-hero { align-items: flex-start; gap: 16px; }
/* The 15ch cap was wrapping the headline into a narrow column while the row
   had space to spare. */
.studies-hero-title { font-size: 1.75em; line-height: 1.15; max-width: none; }
.studies-hero .home-hero-text { flex: 1 1 auto; }
.studies-hero .home-hero-intro { max-width: 52ch; }
.studies-counts {
    margin: 14px 0 0;
    font-size: 0.85em;
    color: var(--c-font-dim);
    font-variant-numeric: tabular-nums;
}

/* The faces are a signature, not a gallery: overlapped and small. */
.studies-faces {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    padding-top: 6px;
}
.studies-face {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    object-fit: cover;
    border: 2px solid var(--c-box);
    margin-left: -8px;
}
.studies-face:first-child { margin-left: 0; }
/* A framed face is wrapped; the overlap moves to the wrapper and the ring
 * needs the same 2px of box colour the bare faces get. */
.studies-faces > .avatar-frame { margin-left: -8px; --frame-gap: 1px; }
.studies-faces > .avatar-frame:first-child { margin-left: 0; }
.studies-faces > .avatar-frame > .studies-face { margin-left: 0; }

.contrib-chip {
    gap: 5px;
    font-variant-numeric: tabular-nums;
}
.contrib-chip-pages {
    background-color: var(--tone-castles-bg);
    color: var(--tone-castles-fg);
}
.contrib-icon { flex: 0 0 13px; }

.studies-person { flex-direction: row; align-items: center; gap: 12px; }
.studies-person-avatar {
    width: 28px;
    height: 28px;
    flex: 0 0 28px;
    border-radius: 50%;
    object-fit: cover;
}

/* --- Wiki byline on card rows --------------------------------------- */
/* Faces only: overlapped, like the contributor cluster in the studies hero. */
.wiki-credit {
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
}
.wiki-credit-avatar {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 20px;
    border: 2px solid var(--c-box);
}
.wiki-credit-avatar + .wiki-credit-avatar { margin-left: -7px; }

/* --- Play lobby hero -------------------------------------------------- */
.play-hero { align-items: center; gap: 24px; }
.play-hero .home-hero-text { flex: 1 1 auto; min-width: 0; }
.play-hero-title { font-size: 1.75em; line-height: 1.15; }
/* The lead was wrapping into a narrow column while the row had room. */
.play-hero .home-hero-intro { max-width: 46ch; }
.play-hero-actions { flex-wrap: wrap; }
.play-hero-actions .home-cta { cursor: pointer; }
.home-cta { gap: 8px; }
.cta-icon { flex: 0 0 17px; }

@media (max-width: 820px) {
    .studies-hero { flex-direction: column; }
    .studies-faces { max-width: none; }
}

.studies-sections { padding-bottom: 4px; }
.studies-card { padding: 14px 12px; }
.studies-card-kanji { font-size: 1.7em; opacity: 1; color: var(--c-accent); }
.studies-card-count {
    display: inline-block;
    min-width: 22px;
    padding: 2px 10px;
    border-radius: var(--radius-pill);
    background-color: var(--c-accent-soft);
    color: var(--c-accent-on-soft);
    font-size: 0.75em;
    font-weight: 600;
    text-align: center;
}
.play-lead { color: var(--c-font-dim); margin: 4px 24px 8px; opacity: 1; }

/* --- Forum ----------------------------------------------------------- */
.forum-lead { color: var(--c-font-dim); opacity: 1; margin-left: 24px; margin-right: 24px; }
.forum-crumb { color: var(--c-font-dim); opacity: 1; }
.forum-crumb:hover { color: var(--c-accent); }

.forum-rules,
body.dark-mode .forum-rules {
    background-color: var(--c-accent-soft);
    color: var(--c-accent-on-soft);
    border: none;
    border-radius: var(--radius-lg);
    opacity: 1;
    margin: 16px 24px 4px;
    padding: 14px 18px;
}
.forum-rules-icon { color: var(--c-accent-on-soft); }

.forum-guest {
    color: var(--c-font-dim);
    opacity: 1;
    margin: 12px 24px 0;
}
.forum-guest-cta { color: var(--c-accent); border-bottom-color: transparent; }
.forum-guest-cta:hover { border-bottom-color: currentColor; }

.forum-composer,
body.dark-mode .forum-composer {
    background-color: var(--c-box-alt);
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-lg);
    margin: 16px 24px;
    padding: 20px 22px;
}
.forum-composer-heading { color: var(--c-font-strong); }
.forum-composer-as { color: var(--c-font-dim); opacity: 1; }
.forum-field-label { color: var(--c-font-dim); opacity: 1; }
.forum-subject-input,
body.dark-mode .forum-subject-input {
    background-color: var(--c-box);
    border: 1px solid var(--c-border);
    border-radius: var(--radius-md);
    color: var(--c-font);
}
.forum-subject-input:focus { border-color: var(--c-accent); }
/* The message field, drawn like the subject field above it: the same box,
   border and corners, so the two read as one form rather than a field and
   a bare textarea with the browser's own black focus ring. */
.forum-composer .forum-body-input,
body.dark-mode .forum-composer .forum-body-input {
    box-sizing: border-box;
    width: 100%;
    padding: 10px 14px;
    min-height: 140px;
    background-color: var(--c-box);
    border: 1px solid var(--c-border);
    border-radius: var(--radius-md);
    color: var(--c-font);
    font: inherit;
    font-size: 1.05em;
    line-height: 1.5;
    resize: vertical;
    outline: none;
    transition: border-color 0.12s ease;
}
.forum-composer .forum-body-input:focus { border-color: var(--c-accent); }
.forum-composer .forum-body-input::placeholder,
body.dark-mode .forum-composer .forum-body-input::placeholder { color: var(--c-font-dim); }
.forum-composer-status { color: var(--c-font-dim); opacity: 1; }
.forum-composer-status.is-error,
body.dark-mode .forum-composer-status.is-error { color: var(--c-bad); }

.forum-list { padding: 0 12px 8px; }
.forum-thread,
body.dark-mode .forum-thread {
    border-bottom: 1px solid var(--c-border-soft);
    border-radius: var(--radius-md);
}
.forum-thread:hover,
body.dark-mode .forum-thread:hover { background-color: var(--c-hover); }
.forum-thread-title { color: var(--c-font-strong); }
.forum-thread-meta { color: var(--c-font-dim); opacity: 1; }
.forum-thread-pin { background-color: var(--c-accent-soft); color: var(--c-accent-on-soft); }
.forum-board-chip {
    background-color: transparent;
    border: 1px solid var(--c-border);
    color: var(--c-font-dim);
    font-size: 0.68em;
    padding: 2px 8px;
}
.forum-thread-pinned { background-color: var(--c-accent-soft); }
.forum-thread-pinned:hover { background-color: var(--c-accent-soft); }

.forum-end { color: var(--c-font-dim); opacity: 1; }
.forum-footer { padding: 12px 24px 40px; }

.thread-title { color: var(--c-font-strong); margin-left: 24px; margin-right: 24px; }
.thread-comments-title { padding-left: 24px; padding-right: 24px; }
/* `.logged-in-only` turns display into inline-flex, which would collapse a
   form that has to span the column. */
body.is-logged-in .thread-comment-form { display: block; }
/* The reply box came from the old feed composer: a full-bleed band with a
   blurred backdrop, framed by rules above and below. In this layer the card
   is the frame, so the rules go. */
.thread-comment-form,
body.dark-mode .thread-comment-form { border: none; padding: 0; }
.thread-comment-form .comment-composer,
body.dark-mode .thread-comment-form .comment-composer {
    background-color: var(--c-box-alt);
    backdrop-filter: none;
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-lg);
    margin: 8px 24px 32px;
    padding: 16px 18px;
}
.comment-composer .composer-input { font-size: 1.02em; }

.thread-comment-guest {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin: 12px 24px 32px;
    color: var(--c-font-dim);
    font-size: 0.88em;
}

/* --- Modals ---------------------------------------------------------- */
.modal-dialog,
body.dark-mode .modal-dialog {
    background-color: var(--c-box);
    border: none;
    border-radius: 28px;
    box-shadow: var(--elev-2);
    color: var(--c-font);
}
.modal-title { color: var(--c-font-strong); font-weight: 500; }
.modal-close, .modal-cancel { border-radius: var(--radius-pill); }

.wiki-castle-modal-card,
.play-promotion-card,
.play-piece-modal-card {
    background: var(--c-box);
    color: var(--c-font);
    border-radius: var(--radius-md);
}
body.dark-mode .wiki-castle-modal-card,
body.dark-mode .play-piece-modal-card { background: var(--c-box-alt); color: var(--c-font); }
body.dark-mode .wiki-picker-menu { background: var(--c-box-alt); border-radius: var(--radius-md); }
body.dark-mode .sidebar-auth-avatar-link:hover { border-color: var(--c-accent); }

/* --- Sign in / sign up page ------------------------------------------ */
.auth-page {
    display: flex;
    justify-content: center;
    padding: 48px 24px 64px;
}
.auth-page-card {
    width: 100%;
    max-width: 380px;
}
.auth-page .auth-hero { text-align: center; margin-bottom: 22px; }
.auth-page .auth-title {
    margin: 0;
    font-size: 1.5em;
    font-weight: 500;
    color: var(--c-font-strong);
}
.auth-page .auth-subtitle { margin: 6px 0 0; color: var(--c-font-dim); font-size: 0.92em; }
.auth-page .auth-tabs {
    display: flex;
    gap: 6px;
    margin-bottom: 20px;
}
.auth-page .auth-tab {
    flex: 1;
    padding: 9px 14px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--c-font-dim);
    font: inherit;
    font-size: 0.9em;
    font-weight: 500;
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.auth-page .auth-tab:hover { background-color: var(--c-hover); color: var(--c-font-strong); }
.auth-page .auth-tab.active {
    background-color: var(--c-accent-soft);
    border-color: transparent;
    color: var(--c-accent-on-soft);
    font-weight: 600;
}
.auth-page .auth-tab-indicator { display: none; }
.auth-page .auth-body { display: flex; flex-direction: column; gap: 14px; }
.auth-page .auth-field { display: flex; flex-direction: column; gap: 6px; }
.auth-page .auth-label { font-size: 0.82em; color: var(--c-font-dim); }
/* Same outlined field as the draft form - two forms in one app should not
   have two field styles. */
.auth-page .auth-input {
    background-color: transparent;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    color: var(--c-font);
    font: inherit;
    font-size: 0.95em;
    padding: 12px 14px;
    outline: none;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.auth-page .auth-input::placeholder { color: var(--c-font-dim); opacity: 0.8; }
.auth-page .auth-input:hover { border-color: var(--c-font-dim); }
.auth-page .auth-input:focus {
    border-color: var(--c-accent);
    box-shadow: 0 0 0 1px var(--c-accent);
}
.auth-page .auth-error {
    margin: 0;
    color: var(--c-bad);
    font-size: 0.85em;
}
.auth-page .auth-submit { width: 100%; margin-top: 4px; }
.auth-page .auth-avatar-uploader {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    border: 1px dashed var(--c-border);
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: 0.88em;
    color: var(--c-font-dim);
}
.auth-page .auth-avatar-uploader:hover { border-color: var(--c-accent); color: var(--c-font-strong); }
.auth-page .auth-avatar-preview {
    width: 44px; height: 44px;
    flex: 0 0 44px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background-color: var(--c-box-alt);
    overflow: hidden;
}
.auth-page .auth-avatar-preview img { width: 100%; height: 100%; object-fit: cover; }
.auth-page .auth-avatar-clear {
    margin-left: auto;
    background: none; border: none; cursor: pointer;
    color: var(--c-font-dim); font-size: 1.2em;
}

/* The home headline is the wordmark. */
.home-hero-logo {
    display: block;
    margin: 0 0 10px;
    width: 190px;
    max-width: 100%;
    height: auto;
}
body.dark-mode .home-hero-logo { filter: invert(1) hue-rotate(180deg); }
/* The lobby's copy of the wordmark is for phones; the phone block shows it. */
.play-hero-logo { display: none; }

/* --- Create page -----------------------------------------------------
   The draft form used the modal input styling and gave no clue which kind of
   page you were writing. */
.draft-kind {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 16px 24px 4px;
    padding: 14px 18px;
    border-radius: var(--radius-lg);
    background-color: var(--c-box-alt);
}
.draft-kind-kanji {
    font-family: var(--font-kanji);
    font-size: 1.7em;
    line-height: 1;
    color: var(--c-accent);
    flex: 0 0 auto;
}
.draft-kind-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.draft-kind-name { color: var(--c-font-strong); font-size: 0.98em; }
.draft-kind-desc { color: var(--c-font-dim); font-size: 0.85em; }

.draft-form {
    display: flex;
    flex-direction: column;
    gap: 22px;
    padding: 20px 24px 40px;
    box-sizing: border-box;
    border: none;
    background: transparent;
}
.draft-form .page-form-label {
    font-size: 0.75em;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.draft-form .page-form-hint { color: var(--c-font-dim); font-size: 0.82em; }

/* Outlined Material fields. A pill is right for a search box or a button;
   on a wide text field it fought the label above it and made the row read as
   a control rather than something to type in. */

.draft-input {
    background-color: transparent;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    color: var(--c-font);
    font: inherit;
    font-size: 0.95em;
    padding: 12px 14px;
    outline: none;
    width: 100%;
    box-sizing: border-box;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.draft-input::placeholder { color: var(--c-font-dim); opacity: 0.8; }
.draft-input:hover { border-color: var(--c-font-dim); }
.draft-input:focus {
    border-color: var(--c-accent);
    box-shadow: 0 0 0 1px var(--c-accent);
}
.draft-textarea {
    min-height: 68px;
    line-height: 1.5;
    resize: vertical;
    font-family: var(--font-ui);
}

/* The slug field completes a URL, so the prefix is a fixed segment of it. */
.draft-slug-field {
    display: flex;
    align-items: stretch;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.draft-slug-field:hover { border-color: var(--c-font-dim); }
.draft-slug-field:focus-within {
    border-color: var(--c-accent);
    box-shadow: 0 0 0 1px var(--c-accent);
}
.draft-slug-prefix {
    display: flex;
    align-items: center;
    padding: 0 12px;
    background-color: var(--c-box-alt);
    border-right: 1px solid var(--c-border);
    color: var(--c-font-dim);
    font-size: 0.9em;
    white-space: nowrap;
}
.draft-slug-input {
    border: none;
    border-radius: 0;
    flex: 1 1 auto;
    min-width: 0;
}
.draft-slug-input:hover,
.draft-slug-input:focus { border: none; box-shadow: none; }

/* Tags here are controls, so they carry their name. */
.draft-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.draft-tag {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 14px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--c-font-dim);
    font: inherit;
    font-size: 0.84em;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.draft-tag:hover { background-color: var(--c-hover); color: var(--c-font-strong); }
.draft-tag.active {
    background-color: var(--c-accent-soft);
    border-color: transparent;
    color: var(--c-accent-on-soft);
    font-weight: 500;
}
.draft-tag-kanji { font-family: var(--font-kanji); font-size: 1.1em; line-height: 1; }

.draft-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    border: none;
    padding: 0;
}
.draft-actions .wiki-editor-status { flex: 1 1 auto; color: var(--c-font-dim); font-size: 0.86em; }

/* --- Body editor toolbar --------------------------------------------- */
.wiki-editor-toolbar,
body.dark-mode .wiki-editor-toolbar {
    gap: 2px;
    padding: 6px 8px;
    background: var(--c-box-alt);
    border-bottom: 1px solid var(--c-border-soft);
    align-items: center;
}
.wiki-tool-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    box-sizing: border-box;
    padding: 0;
    border: none;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--c-font-dim);
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.wiki-tool-btn:hover { background-color: var(--c-hover); color: var(--c-font-strong); }
.wiki-tool-sep {
    width: 1px;
    height: 18px;
    margin: 0 6px;
    background-color: var(--c-border);
}
.wiki-editor:not(.draft-form),
body.dark-mode .wiki-editor:not(.draft-form) {
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.wiki-editor:not(.draft-form):focus-within {
    border-color: var(--c-accent);
    box-shadow: 0 0 0 1px var(--c-accent);
}

.wiki-editor-textarea,
body.dark-mode .wiki-editor-textarea {
    background: transparent;
    border: none;
    color: var(--c-font);
    font-family: var(--font-ui);
    font-size: 0.95em;
    line-height: 1.6;
    padding: 14px 16px;
    min-height: 260px;
    outline: none;
    width: 100%;
    box-sizing: border-box;
    resize: vertical;
}
/* The draft form carries .wiki-editor too, whose rules also zero the padding. */
.draft-form.wiki-editor {
    border: none;
    border-radius: 0;
    overflow: visible;
    padding: 20px 24px 40px;
}

/* --- Preferences -----------------------------------------------------
   Was the last page still using its own centred title, bold section headings
   and separator rules. Same header band, same section labels, same pill rows
   as everywhere else. */
.settings-page {
    padding: 8px 24px 48px;
    max-width: none;
    margin: 0;
    gap: 30px;
}
.settings-section { gap: 6px; }
.settings-section-title {
    font-size: 0.75em;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-font-dim);
    padding-top: 6px;
}
.settings-section-hint {
    color: var(--c-font-dim);
    opacity: 1;
    font-size: 0.88em;
    max-width: 58ch;
}
.settings-section + .settings-section { border-top: none; }

.settings-radio-group { gap: 6px; margin-top: 10px; }
.settings-radio-group .settings-toggle,
body.dark-mode .settings-radio-group .settings-toggle {
    margin-top: 0;
    padding: 11px 16px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    max-width: 420px;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
.settings-radio-group .settings-toggle:hover { background-color: var(--c-hover); }
/* Matches the specificity of the older rule further up, which uses the
   attribute form and would otherwise keep its own border colour. */
.settings-radio-group .settings-toggle:has(input[type="radio"]:checked),
body.dark-mode .settings-radio-group .settings-toggle:has(input[type="radio"]:checked) {
    background-color: var(--c-accent-soft);
    border-color: transparent;
    color: var(--c-accent-on-soft);
    font-weight: 500;
}
.settings-toggle input[type="checkbox"]:checked,
body.dark-mode .settings-toggle input[type="checkbox"]:checked {
    background-color: var(--c-accent);
    border-color: var(--c-accent);
}
.settings-section-status { color: var(--c-bad); font-size: 0.85em; }

/* --- Board diagrams in articles -------------------------------------- */
.wiki-diagram {
    display: flex;
    justify-content: center;
    margin: 22px 0 14px;
}
/* The frame carries the declared width, so the copy button below the board
   lines up with the board's edge instead of the prose column's. */
.wiki-diagram-frame {
    display: flex;
    flex-direction: column;
    max-width: 100%;
    min-width: 120px;
}
/* border-box so the board's 2px frame stays inside the declared width. */
.wiki-diagram-board { width: 100%; box-sizing: border-box; }
.wiki-diagram .play-cell { cursor: default; }
.wiki-diagram .play-piece { font-size: clamp(0.7rem, 2.6vw, 1.35rem); }
/* Under the board rather than over it: a diagram whose corner square is hidden
   by a button is a diagram that is telling the reader the wrong thing. Dim
   until the diagram is hovered, but always there, because a phone has no
   hover to reveal it with. */
.wiki-diagram-copy {
    align-self: flex-end;
    margin-top: 6px;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background-color: transparent;
    color: var(--c-font-dim);
    cursor: pointer;
    opacity: 0.45;
    transition: opacity 0.12s ease, background-color 0.12s ease, color 0.12s ease;
}
.wiki-diagram:hover .wiki-diagram-copy,
.wiki-diagram-copy:focus-visible { opacity: 1; }
.wiki-diagram-copy:hover { background-color: var(--c-hover); color: var(--c-font-strong); }

/* --- The diagram builder --------------------------------------------- */
.board-builder-dialog { max-width: 520px; width: 100%; }
.board-builder-body { display: flex; flex-direction: column; gap: 14px; }
.board-builder-size {
    display: flex;
    align-items: flex-end;
    gap: 12px;
    flex-wrap: wrap;
}
.board-builder-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.75em;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.board-builder-field .draft-input { width: 92px; }
.board-builder-presets { margin-left: auto; display: flex; gap: 8px; }
.board-builder-hint { margin: 0; font-size: 0.85em; color: var(--c-font-dim); }

/* The position as one line: copy it out to any other shogi tool, paste one
   back in from anywhere. It is the same board as the grid below, so the two
   follow each other while the dialog is open. */
.board-builder-code { display: flex; flex-direction: column; gap: 6px; }
.board-builder-code-label {
    font-size: 0.75em;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.board-builder-code-row { display: flex; align-items: stretch; gap: 8px; }
.board-builder-code-input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 8px 10px;
    font-family: var(--font-mono);
    font-size: 0.8rem;
    line-height: 1.45;
    resize: vertical;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
.board-builder-code-copy {
    flex: 0 0 auto;
    width: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--c-font-dim);
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.board-builder-code-copy:hover { background-color: var(--c-hover); color: var(--c-font-strong); }
.board-builder-code-hint { margin: 0; font-size: 0.8em; color: var(--c-font-dim); }
.board-builder-code-hint.is-bad { color: var(--c-bad); }

.board-builder-sides { display: flex; gap: 6px; margin-bottom: 8px; }
.board-builder-side {
    flex: 1 1 auto;
    padding: 8px 14px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--c-font-dim);
    font: inherit;
    font-size: 0.85em;
    cursor: pointer;
}
.board-builder-side.active {
    background-color: var(--c-accent-soft);
    border-color: transparent;
    color: var(--c-accent-on-soft);
    font-weight: 600;
}
.board-builder-pieces { display: flex; flex-wrap: wrap; gap: 6px; }
.board-builder-piece {
    width: 40px;
    height: 40px;
    box-sizing: border-box;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--c-font-strong);
    font-family: var(--font-kanji);
    font-size: 1.05rem;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
.board-builder-piece:hover { background-color: var(--c-hover); }
.board-builder-piece.active { border-color: var(--c-accent); box-shadow: 0 0 0 1px var(--c-accent); }
.board-builder-piece.play-piece-promoted { color: var(--c-bad); }
.board-builder-eraser { font-family: var(--font-ui); color: var(--c-font-dim); }
.board-builder-grid-wrap { display: flex; justify-content: center; }
.board-builder-grid { width: 100%; max-width: 340px; }
.board-builder-grid .play-cell { cursor: pointer; }

/* --- Wiki authorship + discussion ------------------------------------ */
.wiki-footer { gap: 8px; }
.wiki-meta-line {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    justify-content: flex-start;
}
.wiki-person {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--c-font-strong);
    text-decoration: none;
    padding: 3px 8px 3px 3px;
    border-radius: var(--radius-pill);
    transition: background-color 0.12s ease;
}
.wiki-person:hover { background-color: var(--c-hover); }
.wiki-person-avatar {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 22px;
}
.wiki-meta-date { color: var(--c-font-dim); }

/* The verified mark for anyone who can edit the wiki. */
.role-badge-verified { color: var(--c-accent); }
.role-badge-editor { color: var(--c-accent); }
/* A username, anywhere on the site: the profile is one click away. It
   inherits the colour and weight of whatever it sits in, so a name in a
   card or a byline looks as it did and only gains the underline on hover.
   The span form (role="link") is for names inside cards that are links. */
.user-link { color: inherit; text-decoration: none; cursor: pointer; }
.user-link:hover, .user-link:focus-visible { text-decoration: underline; }
span.user-link { display: inline; }
.wiki-credit .user-link { display: inline-flex; }

/* Staff carry the same mark in the accent: an admin's name reads as the
   site's, wherever it appears - comments, the profile header, a seat in the
   room. */
.role-badge-admin { color: var(--c-accent); }
/* Beside a profile name the mark scales with the heading; beside a seat name
   it keeps the comment size and stays on the baseline of the name. */
.profile-name-row .role-badge svg { width: 20px; height: 20px; }
/* The mark belongs to the name, not to the row: the row's 12px gap plus the
   badge's own margin put it a word's width away, where it read as the next
   pill. Pulled back so it sits 5px off the last letter. */
.profile-role { margin-left: -7px; line-height: 0; }
.profile-name-row .role-badge { margin-left: 0; }
.play-player-name .role-badge { margin-left: 5px; }

/* The discussion is not prose, so it does not need a reading measure - it
   uses the column like the rest of the page. */
.wiki-social {
    margin: 34px 0 0;
    padding: 0 24px;
    max-width: none;
}
.wiki-social-actions {
    display: flex;
    justify-content: flex-start;
    padding: 12px 0 4px;
}
.wiki-vote {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 20px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--c-font);
    font: inherit;
    font-size: 0.92em;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.wiki-vote:hover { background-color: var(--c-hover); border-color: var(--c-font-dim); }
.wiki-vote.active {
    background-color: var(--c-accent-soft);
    border-color: transparent;
    color: var(--c-accent-on-soft);
    font-weight: 600;
}
.wiki-vote-glyph { font-family: var(--font-kanji); font-size: 1.1em; line-height: 1; }
.wiki-vote-count { font-variant-numeric: tabular-nums; opacity: 0.8; }

.wiki-social .pieces-section-title { padding-left: 0; padding-right: 0; }

.wiki-comments { display: flex; flex-direction: column; gap: 4px; }
.wiki-comments .page-empty { text-align: left; padding: 18px 0; }
.wiki-comment {
    display: flex;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--c-border-soft);
}
.wiki-comment:last-child { border-bottom: none; }
.wiki-comment-avatar {
    width: 34px;
    height: 34px;
    flex: 0 0 34px;
    border-radius: 50%;
    object-fit: cover;
}
.wiki-comment-main { flex: 1 1 auto; min-width: 0; }
.wiki-comment-head {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}
.wiki-comment-author {
    color: var(--c-font-strong);
    font-weight: 600;
    font-size: 0.9em;
    text-decoration: none;
}
.wiki-comment-author:hover { text-decoration: underline; }
.wiki-comment-date { color: var(--c-font-dim); font-size: 0.8em; }
.wiki-comment-delete {
    margin-left: auto;
    background: none;
    border: none;
    color: var(--c-font-dim);
    font-size: 1.1em;
    line-height: 1;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: var(--radius-pill);
}
.wiki-comment-delete:hover { color: var(--c-bad); background-color: var(--c-hover); }
.wiki-comment-body {
    margin: 4px 0 0;
    font-size: 0.92em;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.wiki-comment-form,
body.is-logged-in .wiki-social .wiki-comment-form {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    margin-top: 16px;
    width: 100%;
}
.wiki-comment-form .draft-textarea { min-height: 92px; }
.wiki-comment-form-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
}
.wiki-comment-status { flex: 1 1 auto; color: var(--c-font-dim); font-size: 0.85em; }
.wiki-comment-status.is-error { color: var(--c-bad); }
.wiki-comment-login { margin-top: 14px; font-size: 0.9em; color: var(--c-font-dim); }
.wiki-comment-login a { color: var(--c-accent); }

/* --- Match room ------------------------------------------------------
   Only the frame around the board. .play-board / .play-cell / .play-piece and
   the hand pieces are deliberately untouched: the board stays exactly as it
   is. */
body[data-play-page="room"] .content { padding-bottom: 32px; }

.play-history-actions { justify-content: flex-end; }
.play-status {
    flex: 1 1 auto;
    text-align: center;
    font-size: 0.95rem;
    opacity: 1;
    color: var(--c-font-strong);
    font-weight: 500;
}
.play-spectators { color: var(--c-font-dim); }

.play-result-banner,
body.dark-mode .play-result-banner {
    /* 52px clears the floating back arrow (8px offset + 36px button). */
    margin: 6px 52px 0;
    padding: 12px 18px;
    border: none;
    border-radius: var(--radius-lg);
    background-color: var(--c-box-alt);
    color: var(--c-font-strong);
    font-weight: 600;
    font-size: 0.92rem;
}
.play-result-banner-win,
body.dark-mode .play-result-banner-win {
    background-color: var(--tone-easy-bg);
    color: var(--tone-easy-fg);
}
.play-result-banner-loss,
body.dark-mode .play-result-banner-loss {
    background-color: var(--tone-hard-bg);
    color: var(--tone-hard-fg);
}

.play-player-name { color: var(--c-font-strong); font-weight: 600; }
.play-player-role { color: var(--c-font-dim); opacity: 1; }
.play-player-clock { color: var(--c-font-strong); }

/* History: the app's section label and row treatment, not a bordered box. */
.play-history-section { margin-top: 26px; padding: 0 24px; }
.play-history-title {
    margin: 0 0 6px;
    padding: 0;
    font-size: 0.75em;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 1;
    color: var(--c-font-dim);
}
.play-history,
body.dark-mode .play-history {
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-md);
    max-height: 260px;
}
.play-history-row,
body.dark-mode .play-history-row { border-bottom: 1px solid var(--c-border-soft); }
.play-history-row:last-child { border-bottom: none; }
.play-history-clickable:hover { background-color: var(--c-hover); }
.play-history-current,
body.dark-mode .play-history-current {
    background-color: var(--c-accent-soft);
    color: var(--c-accent-on-soft);
}
.play-history-num { color: var(--c-font-dim); opacity: 1; }

.play-replay-controls {
    gap: 6px;
    margin: 14px 24px 0;
    justify-content: center;
}
.play-room-actions .play-icon-btn,
.play-replay-controls .play-icon-btn {
    box-sizing: border-box;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    color: var(--c-font-dim);
    opacity: 1;
}
.play-room-actions .play-icon-btn:hover,
.play-replay-controls .play-icon-btn:hover {
    background-color: var(--c-hover);
    color: var(--c-font-strong);
}

/* --- Wiki article ----------------------------------------------------
   The article was centred while every other page in the app is left-aligned,
   and it had no header band, so it read as a different site. Same header
   shape, same type scale, same rules as the lists it comes from. */
.wiki-article {
    padding: 0 0 40px;
    max-width: none;
}
.wiki-toolbar-row {
    margin: 0;
    padding: 14px 24px 10px;
}
.wiki-back {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--c-font-dim);
    opacity: 1;
    font-size: 0.85em;
    border-radius: var(--radius-pill);
    padding: 4px 10px;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.wiki-back:hover { background-color: var(--c-hover); color: var(--c-font-strong); opacity: 1; }

/* An article still reads best centred - only the scale, colour and spacing
   change to match the rest of the app. */
.wiki-title {
    text-align: center;
    margin: 0;
    padding: 0 24px;
    font-size: 1.9em;
    font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--c-font-strong);
}
.wiki-kanji {
    text-align: center;
    padding: 0 24px;
    font-size: 3.4em;
    margin: 0 0 6px;
    color: var(--c-font-strong);
}
.wiki-tags {
    justify-content: center;
    padding: 0 24px;
    margin: 12px 0 0;
}
.wiki-movement {
    text-align: center;
    margin: 14px auto 0;
    padding: 0 24px;
    max-width: 60ch;
    color: var(--c-font-dim);
    opacity: 1;
    font-size: 0.95em;
}
.wiki-body {
    padding: 26px 24px 0;
    display: block;
}
/* The article keeps its reading measure, centred exactly as before: the
   max-width moved from the container to the prose blocks, with auto margins,
   so nothing about the text changed. Only the references - a list of sources,
   not prose - are allowed the full column, next to the footer below them. */
.wiki-body-rendered { max-width: none; width: 100%; }
.wiki-body-rendered > p,
.wiki-body-rendered > ul,
.wiki-body-rendered > ol,
.wiki-body-rendered > blockquote,
.wiki-body-rendered > pre,
.wiki-body-rendered > table,
.wiki-body-rendered > .wiki-figure,
.wiki-body-rendered > h1,
.wiki-body-rendered > h2,
.wiki-body-rendered > h3,
.wiki-body-rendered > h4 {
    max-width: var(--prose);
    margin-left: auto;
    margin-right: auto;
}
.wiki-body-rendered .wiki-references,
.wiki-body-rendered .wiki-references ol { max-width: none; }
/* Diagrams are drawings of a board, so they follow the prose column too. */
.wiki-body-rendered > .wiki-diagram { max-width: var(--prose); margin-left: auto; margin-right: auto; }

.wiki-icon-btn {
    border-radius: var(--radius-pill);
    color: var(--c-font-dim);
    border: 1px solid var(--c-border);
}
.wiki-icon-btn:hover { color: var(--c-accent); background-color: var(--c-hover); }

.wiki-footer {
    margin: 30px 0 0;
    padding: 0 24px;
    max-width: none;
    border-top: none;
    color: var(--c-font-dim);
    opacity: 1;
    font-size: 0.82em;
    align-items: flex-start;
    text-align: left;
}

/* Figures in the article body: the diagrams are uploaded images, so they are
   already bounded by .wiki-body-rendered - this only gives them the same
   rounded frame the rest of the app uses. */
.wiki-body-rendered .wiki-figure {
    /* auto, or this resets the centring the prose measure sets. */
    margin: 20px auto;
    text-align: left;
}
.wiki-body-rendered .wiki-figure img {
    max-width: 100%;
    height: auto;
    border-radius: var(--radius-md);
    border: 1px solid var(--c-border-soft);
}
.wiki-body-rendered .wiki-figure figcaption {
    margin-top: 8px;
    font-size: 0.82em;
    color: var(--c-font-dim);
}

/* --- Profile --------------------------------------------------------- */
/* Segmented control, not underlined tabs: the pill radius alone fought with
   the inherited bottom-border style and produced a half-round tab. */
.profile-tabs,
body.dark-mode .profile-tabs {
    gap: 6px;
    padding: 2px 24px 8px;
    border-bottom: none;
}
.profile-tab,
body.dark-mode .profile-tab {
    flex: 0 1 auto;
    padding: 9px 18px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--c-font-dim);
    opacity: 1;
    font-size: 0.88rem;
    font-weight: 500;
}
.profile-tab:hover,
body.dark-mode .profile-tab:hover {
    background-color: var(--c-hover);
    color: var(--c-font-strong);
    opacity: 1;
}
.profile-tab-active,
body.dark-mode .profile-tab-active {
    background-color: var(--c-accent-soft);
    border-color: transparent;
    color: var(--c-accent-on-soft);
    font-weight: 600;
}
.profile-tab-count {
    opacity: 0.7;
    font-variant-numeric: tabular-nums;
}

.profile-header,
body.dark-mode .profile-header {
    padding: 24px 24px 14px;
    border-bottom: none;
}
.profile-name-row {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.profile-follow {
    border: 1px solid var(--c-accent);
    background-color: var(--c-accent);
    color: var(--c-on-accent);
    border-radius: var(--radius-pill);
    padding: 6px 18px;
    font: inherit;
    font-size: 0.84em;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.profile-follow:hover { background-color: var(--c-accent-hover); border-color: var(--c-accent-hover); }
/* Already following: outlined, so unfollowing never looks like the main action. */
.profile-follow.is-following {
    background-color: transparent;
    color: var(--c-accent);
    border-color: var(--c-border);
}
.profile-follow.is-following:hover {
    background-color: var(--c-accent-soft);
    color: var(--c-accent-on-soft);
}

/* Three of the five stats are plain spans and two are buttons; only the
   buttons carried padding, so the row broke into two baselines. Give them all
   the same box and let the buttons differ only by the hover affordance. */
.profile-stats {
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 18px;
    opacity: 1;
    color: var(--c-font-dim);
    margin-top: 10px;
    margin-left: 0;
}
/* Words, not pills: the bold number is all the separation a row of four
   needs, and the first number sits under the name's left edge. */
.profile-stat {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    padding: 2px 0;
    border-radius: var(--radius-pill);
    line-height: 1.4;
}
.profile-stat strong { color: var(--c-font-strong); font-weight: 600; }
.profile-stat-btn {
    background: none;
    border: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
    transition: background-color 0.12s ease;
    /* The hover pill grows outwards, so the text does not move. */
    padding: 2px 8px;
    margin: 0 -8px;
}
.profile-stat-btn:hover { background-color: var(--c-hover); }
/* The one action on the header sits at its right edge. */
/* Follow and challenge as one pair at the right end of the row. Each used
   to carry its own auto margin, so the two were pushed as far apart as the
   row allowed: follow floating mid-row, challenge at the edge. */
.profile-name-row .profile-follow { margin-left: auto; }
.profile-name-row .profile-follow:not([hidden]) ~ .profile-follow { margin-left: 0; }

.profile-person { flex-direction: row; align-items: center; gap: 12px; }
.profile-person .play-recent-avatar { width: 32px; height: 32px; }

/* ======================================================================
   Play
   ----------------------------------------------------------------------
   The board is the only square thing: .play-board / .play-cell /
   .play-piece keep their own grid and hairlines further up this file. The
   pages around it - lobby, simul, tournament, match room - use the same
   card, rows and pills as the rest of the site.
   ====================================================================== */

/* Match / simul / tournament rows: players left, meta chips right. */
.play-public-card,
.play-recent-card,
.profile-match-card {
    flex-direction: row;
    align-items: center;
    gap: 14px;
}
.play-public-card > .play-recent-players,
.play-recent-card > .play-recent-players,
.profile-match-card > .play-recent-players { flex: 1 1 auto; width: auto; min-width: 0; }
.play-public-card > .play-recent-meta,
.play-recent-card > .play-recent-meta,
.profile-match-card > .play-recent-meta { flex: 0 0 auto; }

.play-recent-meta { gap: 6px; }
/* Admin moderation row: the card links to the room like any other, with the
   force-end control parked outside the link so it doesn't navigate. */
.play-admin-card { flex-direction: row; align-items: center; gap: 10px; }
.play-admin-card-link {
    display: flex; align-items: center; gap: 14px;
    flex: 1 1 auto; min-width: 0;
    color: inherit; text-decoration: none;
}
.play-admin-card-link > .play-recent-players { flex: 1 1 auto; width: auto; min-width: 0; }
.play-admin-card-link > .play-recent-meta { flex: 0 0 auto; }
.play-admin-end-btn { color: #c2410c; opacity: 0.85; }
.play-admin-end-btn:hover { opacity: 1; background: rgba(194, 65, 12, 0.12); }
body.dark-mode .play-admin-end-btn { color: #f97316; }
body.dark-mode .play-admin-end-btn:hover { background: rgba(249, 115, 22, 0.16); }


.play-public-chip,
body.dark-mode .play-public-chip {
    border-radius: var(--radius-pill);
    background-color: var(--c-box-alt);
    color: var(--c-font-dim);
    padding: 4px 10px;
    font-size: 0.74em;
    font-weight: 500;
}
.play-public-chip-icon { padding: 5px; }
.play-public-chip-join,
body.dark-mode .play-public-chip-join {
    background-color: var(--c-accent);
    color: var(--c-on-accent);
}
.pieces-index-card:hover .play-public-chip-join { background-color: var(--c-accent-hover); }

.play-public-tag {
    border-radius: var(--radius-pill);
    padding: 2px 9px;
    font-size: 0.7em;
    font-weight: 600;
    letter-spacing: 0.03em;
}
.play-public-tag-simul,
body.dark-mode .play-public-tag-simul {
    background-color: var(--tone-pieces-bg);
    color: var(--tone-pieces-fg);
}
.play-public-tag-tournament,
body.dark-mode .play-public-tag-tournament {
    background-color: var(--tone-openings-bg);
    color: var(--tone-openings-fg);
}

.play-recent-name { color: var(--c-font-strong); font-weight: 500; }
.play-recent-vs { color: var(--c-font-dim); }
.play-recent-avatar { border-radius: 50%; }
.play-recent-chip { border-radius: var(--radius-pill); }
.play-recent-chip-aborted { opacity: 0.55; font-style: italic; }
.play-player-clock { font-family: var(--font-mono); }

/* Match room: the panels around the board are cards like anywhere else -
   but the board keeps its own square 2px frame, so the wrapper must not clip
   it with a radius. */
.play-board-wrap { border-radius: 0; overflow: visible; }
.play-modal-dialog { border-radius: 28px; }
.play-share-input {
    border-radius: var(--radius-pill);
    padding: 9px 16px;
}
/* The select has a clock icon absolutely positioned inside its left edge and a
   chevron drawn on its right, so both need their room reserved. The pill
   padding used above would drop the left inset back to 16px and print the
   clock on top of the first digit. */
.play-time-control-select {
    border-radius: var(--radius-pill);
    padding: 9px 36px 9px 40px;
    background-position: right 14px center;
}
.play-icon-btn { border-radius: var(--radius-pill); }
.play-visibility-option { border-radius: var(--radius-md); }

/* --- Mobile ----------------------------------------------------------
   Everything below re-asserts geometry that the desktop rules above would
   otherwise win, because this layer sits after the original media query in
   the file. */
@media (max-width: 900px) {
    /* ---- Bottom bar ---- */
    .leftdiv {
        top: auto;
        bottom: 0;
        left: 0;
        right: 0;
        width: 100%;
        height: auto;
        padding: 4px 4px calc(4px + var(--inset-b));
        /* border-box, or width:100% plus the padding overflows the viewport. */
        box-sizing: border-box;
        /* 58px, down from 74: the bar was taking a tenth of a small screen.
           Every bar-relative offset below (content padding, the donate
           pill, the sheets) moved by the same 16px - change one, change
           all. */
        min-height: calc(58px + var(--inset-b));
        border-radius: 0;
        border-top: 1px solid var(--c-border);
        box-shadow: none;
        gap: 0;
        flex-direction: row;
        justify-content: space-evenly;
        align-items: stretch;
        background-color: var(--c-box);
        overflow: visible;
    }
    body.dark-mode .leftdiv { background-color: var(--c-box); }

    .leftdiv .dropbutton,
    body.is-logged-in .leftdiv .dropbutton-compose {
        flex: 1 1 0;
        min-width: 0;
        width: auto;
        display: flex;
        position: relative;
    }

    /* Only the frequent destinations ride in the bar; preferences, support
       and donate are occasional - all one tap behind the overflow item.
       Declared after the rule above, and pinned to the element, so neither
       ordering nor a specificity tie can re-show them. */
    .leftdiv nav.dropbutton[data-key="preferences"],
    .leftdiv nav.dropbutton[data-key="support"],
    .leftdiv nav.dropbutton[data-key="donate"],
    /* Tsume is a top-level section on the rail, but a phone bar holds four or
       five destinations and there are already six. It rides in the overflow
       sheet, which is the same number of taps it took inside studies. */
    .leftdiv nav.dropbutton[data-key="tsume"],
    /* The sections added in 2026. All four live in the overflow sheet: a
       phone bar that tried to hold them alongside play, studies and the
       forum was eleven items wide, which is how this rule earned its
       comment above. */
    .leftdiv nav.dropbutton[data-key="achievements"],
    .leftdiv nav.dropbutton[data-key="ranking"],
    .leftdiv nav.dropbutton[data-key="clubs"],
    .leftdiv nav.dropbutton[data-key="activity"],
    .leftdiv .sidebar-shortcuts,
    .leftdiv .sidebar-auth { display: none; }
    .leftdiv nav.dropbutton-more { display: flex; }
    /* Five in the bar: play, studies, shop, forum, more. Search, compose
       and the admin entry were making it eight for an admin and seven for
       anyone signed in, with labels the width of a fingernail. All three
       are in the "more" sheet, one tap away; search leads it as a bar of
       its own. Compose is un-hidden by the signed-in rule further up, so it
       takes one more class to win. */
    .leftdiv nav.dropbutton[data-key="admin"],
    body.is-logged-in .leftdiv nav.dropbutton-compose { display: none; }
    /* The search item is restyled as a bar item much further down the
       file, at the same specificity, so hiding it here needs the element
       name to win the tie. */
    .leftdiv button.sidebar-search { display: none; }
    /* The donate pill floats above the bar's stacking context, so an open
       sheet cannot rise over it: while a sheet is up, the pill steps out. */
    body:has(.leftdiv .dropbutton.expanded) .donate-pill { display: none; }
    /* The reader's picture as the "more" icon. */
    .leftdiv .dropbutton-more-avatar {
        display: block;
        width: 20px;
        height: 20px;
        border-radius: 50%;
        object-fit: cover;
        flex: 0 0 24px;
    }
    .leftdiv .dropbutton-more-avatar[hidden] { display: none; }
    /* Only the bar button's own glyph gives way to the picture. Written
       without the .dropbutton-link scope this took every icon in the
       sheet with it, for exactly the signed-in readers who have a picture. */
    .leftdiv nav.dropbutton-more.has-avatar .dropbutton-link > .nav-icon { display: none; }
    .leftdiv nav.dropbutton-more.has-avatar.expanded .dropbutton-more-avatar,
    .leftdiv nav.dropbutton-more.has-avatar.is-current .dropbutton-more-avatar {
        box-shadow: 0 0 0 2px var(--c-accent);
    }
    /* The blanket display rule above also un-hid compose, which is
       `.logged-in-only`. Put the gate back, pinned to the element. */
    body:not(.is-logged-in) .leftdiv nav.dropbutton-compose { display: none; }
    .leftdiv .dropbutton-row {
        border-radius: var(--radius-md);
        width: 100%;
        height: 100%;
        align-items: stretch;
        justify-content: center;
    }
    .leftdiv .dropbutton-row:hover { background-color: transparent; }

    /* Icon above a small label - the Material bottom-nav shape. */
    .leftdiv .dropbutton-link {
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        width: 100%;
        min-width: 0;
        height: 100%;
        box-sizing: border-box;
        padding: 4px 2px;
        border-radius: var(--radius-md);
        font-size: 0.7rem;
        font-weight: 500;
        line-height: 1.2;
        text-align: center;
        color: var(--c-font-dim);
        overflow: visible;
    }
    /* Room for descenders: the label is a block of its own, not a squeezed
       line clipped by the icon's box. */
    .leftdiv .dropbutton-link > span {
        display: block;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        padding-bottom: 1px;
    }
    .leftdiv .dropbutton-link .nav-icon {
        width: 20px;
        height: 20px;
        flex: 0 0 20px;
        opacity: 1;
    }
    /* The bar's mask-image pseudo-icons would double the markup ones. */
    .leftdiv .dropbutton-link::before { content: none; }
    .leftdiv .nav-tag { display: none; }
    .leftdiv .dropbutton-arrow { display: none; }

    .leftdiv .dropbutton.is-current > .dropbutton-row { background-color: transparent; }
    .leftdiv .dropbutton.is-current .dropbutton-link {
        color: var(--c-accent-on-soft);
        background-color: var(--c-accent-soft);
        font-weight: 600;
    }
    .leftdiv .dropbutton.expanded .dropbutton-link { background-color: var(--c-hover); }

    /* ---- The popup sheet ---- */
    .leftdiv .subitems,
    body.dark-mode .leftdiv .subitems {
        background-color: var(--c-box);
        color: var(--c-font);
        border: 1px solid var(--c-border);
        border-radius: var(--radius-lg);
        box-shadow: var(--elev-2);
        padding: 8px;
        bottom: calc(78px + var(--inset-b));
    }
    /* One entry per line, glyph at the left, in every sheet. */
    .leftdiv .subitems a,
    .leftdiv .subitems .subitem-button {
        display: flex;
        align-items: center;
        gap: 14px;
        width: 100%;
        min-height: 44px;
        box-sizing: border-box;
        padding: 10px 14px;
        margin: 0;
        border: none;
        border-radius: var(--radius-md);
        background: none;
        color: var(--c-font);
        font: inherit;
        font-size: 0.95rem;
        text-align: left;
        white-space: normal;
        line-height: 1.2;
        cursor: pointer;
    }
    .leftdiv .subitems .nav-icon {
        display: block;
        width: 22px;
        height: 22px;
        flex: 0 0 22px;
        opacity: 0.85;
    }
    .leftdiv .subitems a::before,
    .leftdiv .subitems .subitem-button::before { content: none; }
    .leftdiv .subitems a:active,
    .leftdiv .subitems .subitem-button:active { background-color: var(--c-hover); }

    /* The gates, put back. The sheet's display rules just above are two
       classes deep and the role gates (body .wiki-editor-only and friends)
       are one, so on a phone the sheet won every time: a signed-out
       visitor was offered the review queue, "my submissions", the
       maintenance page and "my studies", and the bar carried an admin
       item for everyone. Same fix as compose further up: pinned to the
       element, after the rule that un-hid it. */
    body:not(.is-logged-in) .leftdiv .subitems .logged-in-only,
    body.is-logged-in .leftdiv .subitems .logged-out-only,
    body:not(.is-wiki-editor) .leftdiv .subitems .wiki-editor-only,
    body:not(.is-logged-in) .leftdiv .subitems .wiki-submitter-only,
    body.is-wiki-editor .leftdiv .subitems .wiki-submitter-only,
    body:not(.is-admin) .leftdiv .subitems .admin-nav,
    body:not(.is-admin) .leftdiv nav.dropbutton.admin-nav { display: none; }

    /* The sheet was capped at 500px by the desktop drawer's max-height
       (three classes deep, which beat the phone block's "none"), and its
       overflow is visible: with fourteen entries the "more" sheet stopped
       at its own rounded corner and the rest of the list went on behind the
       bar, where preferences and support could be seen but not tapped.
       A cap the screen can actually hold, and a scroll inside it if a
       list ever needs one. */
    .leftdiv .dropbutton.expanded .subitems {
        max-height: calc(100vh - 94px - var(--inset-b));
        max-height: calc(100dvh - 94px - var(--inset-b));
        overflow-y: auto;
        overscroll-behavior: contain;
    }
    /* ---- The "more" sheet ----
       One entry per line, icon at the left, the rows sharing whatever
       height the screen has above the bar so the sheet reads as a screen
       of its own rather than a list poking up from the bottom. Search is
       the first row, shaped like the field it opens. A list longer than
       the screen scrolls inside the sheet. */
    .leftdiv nav[data-key="more"].expanded .subitems {
        display: flex;
        flex-direction: column;
        gap: 2px;
        min-height: calc(100vh - 114px - var(--inset-b));
        min-height: calc(100dvh - 114px - var(--inset-b));
        padding: 10px;
    }
    .leftdiv nav[data-key="more"] .subitems a,
    .leftdiv nav[data-key="more"] .subitems .subitem-button {
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: flex-start;
        gap: 14px;
        flex: 1 1 auto;
        min-height: 42px;
        width: 100%;
        box-sizing: border-box;
        padding: 6px 12px;
        text-align: left;
        white-space: nowrap;
        line-height: 1.2;
        font-size: 0.95rem;
        border-radius: var(--radius-md);
    }
    .leftdiv nav[data-key="more"] .subitems .nav-icon {
        display: block;
        width: 22px;
        height: 22px;
        flex: 0 0 22px;
        opacity: 0.85;
    }
    /* The reader's card: picture, name, handle, kakera. Shown only through
       the signed-in selector, so it can never out-rank the gate that hides
       every .logged-in-only entry from a visitor. */
    body.is-logged-in .leftdiv nav[data-key="more"] .subitems .subitem-me {
        display: flex;
        align-items: center;
        gap: 12px;
        flex: 0 0 auto;
        padding: 4px 4px 12px;
        margin-bottom: 6px;
        border-bottom: 1px solid var(--c-border-soft);
    }
    .subitem-me-link {
        display: flex;
        align-items: center;
        gap: 12px;
        flex: 1 1 auto;
        min-width: 0;
        color: inherit;
        text-decoration: none;
    }
    .subitem-me-avatar, .subitem-me-link .avatar-frame > img {
        width: 44px;
        height: 44px;
        border-radius: 50%;
        object-fit: cover;
        display: block;
    }
    .subitem-me-link .avatar-frame { flex: 0 0 auto; margin: 4px; }
    .subitem-me-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
    .subitem-me-name { font-weight: 600; font-size: 1rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .subitem-me-handle { font-size: 0.82rem; color: var(--c-font-dim); }
    .subitem-me-kakera {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        flex: 0 0 auto;
        padding: 6px 12px;
        border-radius: var(--radius-pill);
        background-color: var(--c-box-alt);
        color: var(--c-font-strong);
        font-size: 0.85rem;
        font-weight: 600;
        text-decoration: none;
    }
    .subitem-me-kakera .nav-icon { width: 18px; height: 18px; flex-basis: 18px; }
    .leftdiv nav[data-key="more"] .subitems .subitem-search {
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: flex-start;
        gap: 10px;
        width: 100%;
        box-sizing: border-box;
        padding: 0 16px;
        text-align: left;
        flex: 0 0 44px;
        margin-bottom: 6px;
        border: 1px solid var(--c-border);
        border-radius: var(--radius-pill);
        background-color: var(--c-box);
        color: var(--c-font-dim);
        font: inherit;
        font-size: 0.95rem;
        cursor: pointer;
    }
    /* The gated tiles are display:none through the gates above; a tile
       that is shown is flex, not the sheet's block. */
    .leftdiv nav[data-key="more"] .subitems .logged-in-only,
    .leftdiv nav[data-key="more"] .subitems .admin-nav { display: flex; }
    body:not(.is-logged-in) .leftdiv nav[data-key="more"] .subitems .logged-in-only,
    body:not(.is-admin) .leftdiv nav[data-key="more"] .subitems .admin-nav { display: none; }

    /* ---- Lobby ----
       The five actions in two equal columns instead of a ragged wrap, the
       odd one out across both. A recent-match row stacks: players on one
       line that truncates, the result under it, instead of the second
       name wrapping beneath the first player's picture. */
    /* The wordmark in place of the lobby's title, as on the home page. The
       <h1> keeps its text for search and screen readers, off-screen. */
    .play-hero-logo { display: block; }
    .play-hero .play-hero-title,
    .home-hero .play-hero-title {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        border: 0;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
    }
    /* Flex, not a grid: every button takes half the row, and whichever is
       left alone on the last line grows to the full width by itself, no
       matter which of them the page has hidden. One height for all of
       them, since the primary and the plain ones came out at three. */
    .play-hero-actions { display: flex; flex-wrap: wrap; gap: 8px; }
    .play-hero-actions .home-cta,
    .play-hero-actions .home-cta-primary {
        flex: 1 1 calc(50% - 4px);
        min-width: 0;
        box-sizing: border-box;
        height: 48px;
        min-height: 48px;
        padding: 0 12px;
        margin: 0;
        justify-content: center;
        white-space: nowrap;
        font-size: 0.95em;
    }
    .play-public-card, .play-recent-card, .profile-match-card {
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
    }
    .play-public-card > .play-recent-players,
    .play-recent-card > .play-recent-players,
    .profile-match-card > .play-recent-players { flex-wrap: nowrap; width: 100%; }
    .play-recent-players .play-recent-name { flex: 0 1 auto; }
    .play-recent-players .play-recent-vs { flex: 0 0 auto; }
    /* A hairline between the rows of every lobby list, the way the live
       list draws them: stacked rows with nothing between them read as one
       run of names, and the eye loses which chips belong to which game. */
    [data-play-admin-live] > .pieces-index-card + .pieces-index-card,
    [data-play-public] > .pieces-index-card + .pieces-index-card,
    [data-play-recent] > .pieces-index-card + .pieces-index-card,
    [data-play-public-kifu] > .pieces-index-card + .pieces-index-card {
        border-top: 1px solid var(--c-border-soft);
        border-radius: 0;
    }
    [data-play-admin-live] > .pieces-index-card,
    [data-play-public] > .pieces-index-card,
    [data-play-recent] > .pieces-index-card,
    [data-play-public-kifu] > .pieces-index-card { padding-top: 12px; padding-bottom: 12px; }
    /* The admin's live list has one more layer: a link holding players and
       meta, with the end button beside it. The link stacks the way the
       other rows do; the button keeps its place at the right. */
    .play-admin-card { flex-direction: row; align-items: center; }
    .play-admin-card-link {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
        flex: 1 1 auto;
        min-width: 0;
    }
    .play-admin-card-link > .play-recent-players { flex-wrap: nowrap; width: 100%; }
    .play-admin-card-link > .play-recent-meta,
    .play-public-card > .play-recent-meta,
    .play-recent-card > .play-recent-meta,
    .profile-match-card > .play-recent-meta {
        flex-wrap: wrap;
        justify-content: flex-start;
        margin-left: 0;
    }

    /* ---- Page shell ---- */
    .content {
        border-left: none;
        border-right: none;
        border-radius: 0;
        margin-top: 0;
        margin-bottom: 0;
        box-shadow: none;
        /* Bottom-bar layout: the page is the scroll container again. dvh
           after vh: with the URL bar down, 100vh is taller than the screen
           and the page always had a band of nothing to scroll into. */
        height: auto;
        min-height: calc(100vh - 60px);
        min-height: calc(100dvh - 60px);
        overflow: visible;
        padding-bottom: calc(68px + var(--inset-b));
    }
    /* The room page trimmed its own padding-bottom to 32px in the base
       layer, at a specificity this block's .content never beat: the chat
       input sat under the fixed bottom bar. The bar's clearance, restated
       at the winning strength. */
    body[data-play-page="room"] .content {
        padding-bottom: calc(68px + var(--inset-b));
    }
    .pieces-index, .feed { padding-left: 4px; padding-right: 4px; }
    /* The board is width:100% plus its own 2px frame, which on a desktop is
       four invisible pixels inside a 540px wrap and on a phone is four
       pixels past the edge of the screen: the rightmost file's frame was
       cut and the whole page could be nudged sideways. The frame goes
       inside the width. The cells are 1fr, so they stay square. */
    .play-board { box-sizing: border-box; }
    /* The count badge hangs 2px past the piece's bottom-right corner, and the
       hand rows run to the edge of the screen, so the badge on the last
       piece was the one thing on the page past the edge: enough for the
       whole page to scroll sideways by a pixel. */
    .play-hand { padding-right: 2px; }

    /* ---- The game on a phone ----
       The room used to run the board edge to edge with the two player rows
       pressed against it, and on a tall-but-narrow viewport the bottom hand
       fell below the fold: you scrolled to find your own pieces. Two things
       fix that. The board is capped by the height left over after the
       header, both side rows and the bottom bar, so header, both hands and
       the whole board share the screen; and everything gets a gutter and a
       little more air between rows. The side rows take the board's width,
       whichever of the two limits set it, so they stay flush with its
       frame rather than the screen. The height cap is gentle on purpose -
       it never takes the board under 88% of the width - because a board
       you can read beats a board that fits. */
    .play-room {
        gap: 14px;
        margin-top: 10px;
        padding: 0 12px;
    }
    .play-room > .play-side,
    .play-room > .play-board-wrap {
        width: min(100%, max(88%, calc(100vh - 224px - var(--inset-b))));
        width: min(100%, max(88%, calc(100svh - 224px - var(--inset-b))));
        max-width: 540px;
    }
    .play-side { gap: 10px; }
    /* The player block gives way before the hand does: a long name gets an
       ellipsis instead of pushing the pieces into a third row. */
    .play-side .play-player { flex: 0 1 auto; min-width: 0; max-width: 60%; }
    .play-side .play-player-info { min-width: 0; }
    .play-side .play-player-name,
    .play-side .play-player-role {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .play-side .play-player-avatar { width: 34px; height: 34px; }
    .play-side .play-hand { gap: 8px; padding-top: 2px; padding-bottom: 2px; }
    /* A phone board's cells are around 40px, and the room's board is the
       widest one the site draws: the glyph gets the same lift the base rule
       just took, with a little more of it, because there is more square to
       fill here than anywhere else. */
    .play-room .play-piece { font-size: clamp(1.3rem, 8vw, 2.4rem); }
    .play-room .play-piece-western { font-size: clamp(1.4rem, 8.6vw, 2.55rem); }
    .play-back-float { top: 6px; left: 6px; }
    .play-room-chips { padding: 0 48px; }
    /* The floating arrow sits where the top player's row begins on a
       phone; the row slides right just enough to clear it - inside its
       own width, or the page grows sideways by exactly this much. */
    .play-side-top { padding-left: 44px; box-sizing: border-box; }
    /* The move list and the chat used to be pushed to the foot of the page
       by the base margin-top: auto, which on a tall screen opened a band of
       dead space under the board: the game's own chat looked like a footer.
       It sits right under the board now and grows to the bottom itself. */
    .content-play .play-history-section {
        margin-top: 0;
        padding-top: 12px;
        flex: 1 0 auto;
    }
    /* The action row: one gap between the buttons whether the row shares
       its line with the title or wraps under it, and against the right
       edge in both cases rather than wherever the wrap left it. */
    .play-history-head { row-gap: 8px; }
    .play-history-actions { gap: 8px; margin-left: auto; }
    /* The donate pill is fixed to the top-right corner here, which is where a
       page header puts its action button - it was landing on top of the wiki's
       "new page" button and the forum's "new thread" one. Reserve the corner
       only while the pill is actually up. */
    body.has-donate-pill .page-header { padding-right: 148px; }
    /* The hero pages have no .page-header: their title is the first thing
       under the pill, and on /estudos it was running straight beneath it.
       Only the title gives way, not the whole hero, so the tagline and the
       buttons below keep the full width. */
    body.has-donate-pill .home-hero .home-hero-title { padding-right: 132px; }
    /* The article toolbar keeps its actions at the right edge, which is
       where the pill is: the like, translate and edit buttons were under
       it, and a tap on any of them opened the donation panel instead. The
       row gives the pill its corner and lets the actions wrap below the
       back link when they no longer fit beside it. */
    body.has-donate-pill .wiki-toolbar-row {
        padding-right: 148px;
        flex-wrap: wrap;
        row-gap: 8px;
    }

    .page-header, .home-hero, .pieces-section-title, .wiki-filter, .play-lead,
    .play-bot-setup,
    .settings-page, .draft-form.wiki-editor, .wiki-body, .wiki-title, .wiki-kanji,
    .wiki-movement, .wiki-tags, .wiki-toolbar-row, .play-history-section,
    .profile-header, .profile-tabs, .forum-footer, .forum-lead, .thread-title,
    .tsume-lengths, .tsume-layout {
        padding-left: 16px;
        padding-right: 16px;
    }
    .wiki-social { padding-left: 16px; padding-right: 16px; }
    /* A phone has no room for the 96px avatar beside the name: 80px, with
       the same centring arithmetic (40 - 22 = 18 = 3 + 15). */
    .profile-banner.has-banner + .profile-header .profile-avatar-wrap,
    .profile-banner.has-banner + .profile-header .profile-avatar { width: 80px; height: 80px; }
    .profile-banner.has-banner + .profile-header .profile-avatar-wrap { margin-top: -22px; }
    .profile-banner.has-banner + .profile-header .profile-meta { padding-top: 3px; }

    /* ---- Profile header ----
       Name and role on the first line; the badges on a line of their own,
       wrapping, instead of a strip cut at the screen's edge; follow and
       challenge side by side on one full row, equal halves; and the stats
       in two columns with the icon centred on its text, where the taller
       tap box had left the icon sitting under the words. */
    /* The header was two columns all the way down: the picture's column
       stayed empty under the picture while handle, badges and stats stood
       in the other. The meta block dissolves into the header's own flex
       row, so only the name row sits beside the picture and every row
       after it takes the full width. */
    .profile-header { flex-wrap: wrap; align-items: center; row-gap: 10px; }
    .profile-meta { display: contents; }
    .profile-name-row { flex: 1 1 0; min-width: 0; gap: 0 10px; }
    .profile-name-row .user-flair { margin-top: -2px; }
    /* The badge picker as a modal. A popover hanging off the pill is fine
       beside a desktop's name row and hopeless on a phone, where it opened
       over the tabs and ran off the bottom. Centred, one column, its own
       scroll, and the dimmed page behind it is the pill's giant shadow: a
       tap there lands on the page, which is what closes it. */
    /* Two classes deep on purpose: the picker's own rule sits further down
       the file than this block and would otherwise win every tie. */
    .profile-header .badge-picker {
        position: fixed;
        top: 50%;
        left: 16px;
        right: 16px;
        bottom: auto;
        transform: translateY(-50%);
        z-index: 95;
        width: auto;
        max-width: none;
        max-height: min(80vh, 560px);
        overflow-y: auto;
        overscroll-behavior: contain;
        padding: 14px 12px;
        border-radius: var(--radius-lg);
        box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.45), var(--elev-2);
    }
    .profile-header .badge-picker-head { padding: 0 6px 10px; }
    .profile-header .badge-picker-list { grid-template-columns: 1fr; gap: 2px; }
    .profile-header .badge-picker-option { min-height: 44px; padding-left: 6px; padding-right: 12px; }
    .profile-name { min-width: 0; overflow-wrap: anywhere; }
    .profile-handle-row, .profile-description, .profile-stats,
    .profile-header .profile-badges { flex: 1 1 100%; min-width: 0; }
    .profile-header .profile-badges,
    .profile-header .profile-badge-rest { flex-wrap: wrap; }
    .profile-name-row .profile-follow,
    .profile-name-row .profile-follow:not([hidden]) ~ .profile-follow {
        flex: 1 1 42%;
        margin-left: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
    /* Three numbers, one line. Eleven figures in the header was a wall on
       a phone: pages and likes are already the counts on the tabs right
       below, edits is a wiki detail, and the streaks and favourites are
       for the desktop's wider header. Followers, following and games are
       what a visitor to a profile is actually after. */
    .profile-stats {
        display: flex;
        flex-wrap: wrap;
        gap: 0 18px;
        margin-top: 0;
    }
    .profile-stats > .profile-stat:not([data-profile-people]):not([data-profile-games]),
    .profile-stats .profile-streaks,
    .profile-stats .profile-favourites { display: none; }
    .profile-stat { align-items: center; min-height: 40px; }
    .profile-stat strong { margin-left: 2px; }
    .forum-rules, .forum-guest, .forum-composer, .thread-comment-guest,
    .draft-kind, .play-result-banner, .profile-banner,
    .play-replay-controls, .wiki-footer {
        margin-left: 16px;
        margin-right: 16px;
    }
    /* After the group above on purpose: the result banner must clear the
       floating arrow, not hug the 16px edge the rest of these do. */
    .play-result-banner { margin-left: 52px; margin-right: 52px; }

    /* Seven segments do not fit a phone in one row, and the labels do not
       wrap, so the row was growing past the edge and taking the page with
       it: the document became as wide as the row and the viewport zoomed
       out to fit. A strip that scrolls sideways instead, scrollbar hidden,
       the way tab rows do on a phone. The dark-mode variants are repeated
       because the segmented-control rules above are declared that way and
       would otherwise win on flex. */
    .profile-tabs,
    body.dark-mode .profile-tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .profile-tabs::-webkit-scrollbar { display: none; }
    .profile-tab,
    body.dark-mode .profile-tab { flex: 0 0 auto; }

    /* ---- Comfortable targets ---- */
    .home-cta, .forum-more, .profile-tab, .draft-tag, .wiki-icon-btn,
    .play-icon-btn, .pages-create-btn, .profile-follow,
    .tsume-length, .tsume-actions .home-cta {
        min-height: 44px;
    }
    .home-cta { padding: 11px 20px; }
    .settings-toggle { min-height: 44px; }
    .wiki-icon-btn, .play-icon-btn, .pages-create-btn { min-width: 44px; }
    .feed-item-pin-hide { width: 40px; height: 40px; }

    /* Standalone links that read as buttons need a button-sized box. */
    .wiki-back, .home-showcase-players, .support-card-link,
    .auth-tab, .auth-submit, .thread-board-link, .forum-crumb, .forum-guest-cta,
    .settings-redo {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
    }
    /* The profile's stat rows, the flair pill and the "and N more" badge
       link are all tappable and were 20 to 28px tall: fine under a pointer,
       a coin toss under a thumb. Taller rows, same text. */
    .profile-stat, .profile-badge-rest { min-height: 40px; }
    /* The flair pill next to the name: its own 20px badge plus 3px of
       padding is a 28px pill, and forcing it to 40 just added air around
       a small thing. It stays the size the desktop draws it. */
    .user-flair { min-height: 0; padding: 2px 10px 2px 2px; gap: 6px; font-size: 0.92em; }
    /* The diagram's copy button and the move-list arrows. The copy button
       also stops hiding at 45% opacity: that was a hover reveal, and a
       thumb never hovers. */
    .wiki-diagram-copy { width: 40px; height: 40px; opacity: 0.8; }
    .wiki-moves-btn { min-height: 40px; min-width: 40px; }
    .home-showcase-players { justify-content: center; }
    .support-card-link { justify-content: center; min-width: 44px; }
    .auth-tab, .auth-submit { justify-content: center; }

    /* ---- Home hero: the doors, stacked ----
       On a phone the hero's pills sat side by side and wrapped. Full-width
       rows read as what they are, the page's menu: play, study and (for a
       visitor, via .logged-out-only) sign in. */
    .home-hero-actions {
        flex-direction: column;
        align-items: stretch;
    }
    .home-hero-actions .home-cta {
        width: 100%;
        box-sizing: border-box;
        justify-content: center;
    }
}


/* ---- Training matches -------------------------------------------------
 * Only the seat label is new. The board keeps its own markup and rules
 * untouched, which is why none of this reaches inside .play-board. */
.play-player-bot {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    align-self: flex-start;
    box-sizing: border-box;
    margin-top: 2px;
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--c-box-alt);
    color: var(--c-text-dim, inherit);
    font-size: 0.72rem;
    line-height: 1.5;
    letter-spacing: 0.02em;
    text-transform: lowercase;
}
.play-player-bot-thinking {
    background: var(--c-accent, #272424);
    color: var(--c-on-accent, #fff);
}
.play-player-bot-thinking::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    animation: play-bot-pulse 1s ease-in-out infinite;
}
@keyframes play-bot-pulse {
    0%, 100% { opacity: 0.25; }
    50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .play-player-bot-thinking::before { animation: none; opacity: 0.9; }
}

.play-bot-field { margin-bottom: 14px; }
.play-bot-field-label {
    display: block;
    margin-bottom: 6px;
    font-size: 0.82rem;
    color: var(--c-text-dim, inherit);
}
.play-bot-levels {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 6px;
}
.play-bot-seats {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
/* The label is the control; the input is kept focusable but invisible. It has
 * to be positioned against its own label - without this it escapes to the
 * nearest positioned ancestor, which is the modal. */
.play-bot-level,
.play-bot-seat { position: relative; display: block; }
.play-bot-level input,
.play-bot-seat input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}
.play-bot-level-face,
.play-bot-seat span {
    display: flex;
    box-sizing: border-box;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border: 1px solid var(--c-border, rgba(127, 127, 127, 0.35));
    border-radius: 12px;
    background: var(--c-box);
    text-align: center;
}
.play-bot-level-face {
    flex-direction: column;
    gap: 2px;
    min-height: 58px;
    padding: 7px 4px;
}
.play-bot-seat span { padding: 7px 14px; font-size: 0.86rem; }
.play-bot-level-num { font-size: 1.05rem; font-weight: 600; }
.play-bot-level-name { font-size: 0.66rem; line-height: 1.2; color: var(--c-text-dim, inherit); }
.play-bot-level input:checked + .play-bot-level-face,
.play-bot-seat input:checked + span {
    border-color: var(--c-accent, #272424);
    background: var(--c-accent, #272424);
    color: var(--c-on-accent, #fff);
}
.play-bot-level input:checked + .play-bot-level-face .play-bot-level-name { color: inherit; }
.play-bot-level input:focus-visible + .play-bot-level-face,
.play-bot-seat input:focus-visible + span { outline: 2px solid var(--c-accent, #272424); outline-offset: 2px; }
.play-bot-status:empty { display: none; }
.play-bot-status {
    margin: 10px 0 0;
    color: var(--c-danger, #b3261e);
    font-size: 0.85rem;
}

@media (max-width: 560px) {
    .play-bot-levels { grid-template-columns: repeat(3, 1fr); }
}


/* ---- Studies ----------------------------------------------------------
 * The board reuses .play-board/.play-cell/.play-piece unchanged; everything
 * here is the frame around it. */
.study-header {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: flex-start;
    justify-content: space-between;
    padding: 24px 24px 8px;
}
.study-header-main { min-width: 0; flex: 1 1 340px; }
.study-title { margin: 0 0 6px; font-size: 1.6rem; line-height: 1.2; }
.study-description { margin: 0 0 8px; color: var(--c-font-dim, inherit); }
.study-byline { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.study-header-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.study-visibility-tag {
    box-sizing: border-box;
    padding: 2px 9px;
    border-radius: var(--radius-pill, 999px);
    background: var(--c-box-alt, rgba(127, 127, 127, 0.16));
    font-size: 0.74rem;
}
.study-like.active { border-color: var(--c-accent); }

.study-chapters {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 8px 24px 0;
}
.study-chapter {
    box-sizing: border-box;
    padding: 6px 14px;
    border: 1px solid var(--c-border, rgba(127, 127, 127, 0.35));
    border-radius: var(--radius-pill, 999px);
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}
.study-chapter.active {
    background: var(--c-accent);
    border-color: var(--c-accent);
    color: var(--c-on-accent, #fff);
}

.study-layout {
    display: grid;
    grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
    gap: 24px;
    align-items: start;
    padding: 16px 24px 8px;
}
.study-board-col { min-width: 0; }
.study-side-col { min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.study-hand {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    min-height: 30px;
    align-items: center;
}
.study-controls { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.study-nav-btn {
    box-sizing: border-box;
    min-width: 42px;
    padding: 6px 12px;
    border: 1px solid var(--c-border, rgba(127, 127, 127, 0.35));
    border-radius: var(--radius-pill, 999px);
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}
.study-nav-mainline { min-width: 0; font-size: 0.82rem; }

.study-status { margin: 0; min-height: 1.2em; font-size: 0.86rem; color: var(--c-font-dim, inherit); }
.study-status.is-error { color: var(--c-danger, #b3261e); }
.study-comment-view {
    padding: 10px 14px;
    border-radius: var(--radius-md, 14px);
    background: var(--c-box-alt, rgba(127, 127, 127, 0.10));
    white-space: pre-wrap;
}
.study-comment-edit {
    box-sizing: border-box;
    width: 100%;
    padding: 10px 14px;
    border: 1px solid var(--c-border, rgba(127, 127, 127, 0.35));
    border-radius: var(--radius-md, 14px);
    background: var(--c-box, transparent);
    color: inherit;
    font: inherit;
    resize: vertical;
}
.study-tree {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 340px;
    overflow-y: auto;
}
.study-tree-empty { margin: 0; color: var(--c-font-dim, inherit); font-size: 0.9rem; }
.study-line { display: flex; flex-wrap: wrap; gap: 4px; align-items: baseline; }
.study-line-variation {
    padding-left: 12px;
    border-left: 2px solid var(--c-border, rgba(127, 127, 127, 0.35));
}
.study-move {
    box-sizing: border-box;
    padding: 3px 8px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 8px);
    background: var(--c-box-alt, rgba(127, 127, 127, 0.10));
    color: inherit;
    font: inherit;
    font-size: 0.88rem;
    cursor: pointer;
}
.study-move.active { background: var(--c-accent); color: var(--c-on-accent, #fff); }
.study-variation-chip {
    box-sizing: border-box;
    padding: 2px 8px;
    border: 1px dashed var(--c-border, rgba(127, 127, 127, 0.45));
    border-radius: var(--radius-pill, 999px);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 0.78rem;
    cursor: pointer;
}
.study-promotion {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 10px;
}
.study-promotion p { margin: 0; font-size: 0.88rem; }
.study-edit-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.study-social { padding: 8px 24px 32px; }

.studies-study-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.studies-study-face { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; }
.studies-study-owner { font-size: 0.86rem; }
.studies-study-chapters { font-size: 0.78rem; color: var(--c-font-dim, inherit); }

@media (max-width: 900px) {
    .study-header,
    .study-chapters,
    .study-layout,
    .study-social { padding-left: 14px; padding-right: 14px; }
    .study-layout { grid-template-columns: minmax(0, 1fr); }
    .study-tree { max-height: 260px; }
}


/* Study details panel - only visible while editing. */
.study-settings {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: flex-end;
    padding: 12px 24px 0;
}
.study-setting {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 220px;
    min-width: 0;
}
.study-setting-narrow { flex: 0 1 200px; }
.study-setting-label { font-size: 0.78rem; color: var(--c-font-dim, inherit); }
.study-settings .draft-input,
.study-settings .study-visibility-select {
    box-sizing: border-box;
    width: 100%;
}
.study-settings-status { font-size: 0.82rem; color: var(--c-font-dim, inherit); }
/* Delete sits at the far end of the row, away from save: dim until the pointer
 * is on it, like the other destructive actions on the site. */
.study-settings-delete {
    margin-left: auto;
    background: none;
    border: 0;
    padding: 8px 2px;
    font: inherit;
    font-size: 0.84rem;
    color: var(--c-font-dim, inherit);
    opacity: 0.75;
    cursor: pointer;
}
.study-settings-delete:hover { color: var(--c-danger, #b3261e); opacity: 1; }
.study-settings-delete[disabled] { opacity: 0.4; cursor: default; }

@media (max-width: 900px) {
    .study-settings { padding-left: 14px; padding-right: 14px; }
}


/* ---- Support page: donation lives here now, not behind a rail button ---- */
.support-card-monogram {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    background: var(--c-box-alt, rgba(127, 127, 127, 0.16));
    color: var(--c-font, inherit);
    font-size: 1.2rem;
    font-weight: 600;
}
.donate-panel { padding: 8px 24px 32px; }
.donate-panel-why { margin: 0 0 14px; max-width: 60ch; color: var(--c-font-dim, inherit); }
.donate-panel-body {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
    align-items: flex-start;
}
.donate-panel-qr {
    box-sizing: border-box;
    width: 190px;
    height: 190px;
    flex: 0 0 auto;
    padding: 10px;
    border-radius: var(--radius-md, 14px);
    background: #fff;
}
.donate-panel-side {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    min-width: 0;
    flex: 1 1 260px;
}
.donate-panel-scan { margin: 0; font-size: 0.9rem; color: var(--c-font-dim, inherit); }
.donate-panel-side .donate-key {
    box-sizing: border-box;
    display: block;
    width: 100%;
    max-width: 100%;
    padding: 10px 12px;
    border-radius: var(--radius-md, 14px);
    background: var(--c-box-alt, rgba(127, 127, 127, 0.12));
    font-size: 0.74rem;
    line-height: 1.45;
    /* The base .donate-key clips to one ellipsised line, which suits the
       dialog's cramped row but hides most of the payload here. The page has
       room to show all of it, so all three of those have to be undone - not
       just the wrapping. */
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    word-break: break-all;
    overflow-wrap: anywhere;
}
.donate-panel-thanks { margin: 4px 0 0; font-size: 0.88rem; color: var(--c-font-dim, inherit); }

@media (max-width: 900px) {
    .donate-panel { padding-left: 14px; padding-right: 14px; }
    .donate-panel-qr { width: 160px; height: 160px; }
}


/* A hairline between the wiki categories and the studies entries below them,
   so the rail reads as two groups instead of one long list. */
.leftdiv .subitems .subitem-divider {
    display: block;
    height: 1px;
    margin: 6px 10px;
    background: var(--c-border, rgba(127, 127, 127, 0.3));
}


/* --- Home hero: wordmark + headline ----------------------------------
   The <h1> used to be the logo image and nothing else, so the page had a
   picture where its headline should be. The wordmark keeps the top slot and
   the heading below it is the sentence that says what the site is. */
/* Off-screen but read: lets the <h1> carry text when what is drawn in it
   is the wordmark image. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}
.home-hero-h1 {
    margin: 0;
    font-size: 1.5em;
    font-weight: 500;
    line-height: 1.25;
    letter-spacing: -0.01em;
    color: var(--c-font-strong);
}
.rules-hero .home-hero-h1 { font-size: 1.7em; max-width: 20ch; }

/* --- Prose blocks (home, lobby, rules) -------------------------------
   One reading column, the same measure the wiki article uses, so the text
   sections read as part of the site rather than as an SEO appendix. */
.home-prose { padding-bottom: 4px; }
.home-prose-body {
    max-width: var(--prose);
    padding: 0 24px;
    color: var(--c-font);
    font-size: 0.95em;
    line-height: 1.62;
}
.home-prose-body p { margin: 0 0 12px; }
.home-prose-body p:last-child { margin-bottom: 0; }
.home-prose-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 14px;
    font-size: 0.92em;
}
.home-prose-links a { color: var(--c-font-strong); text-underline-offset: 3px; }
.home-prose-links span { color: var(--c-font-dim); opacity: 0.6; }

/* --- Home: the four steps ------------------------------------------- */
.home-steps-list {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 12px;
    margin: 0;
    padding: 0 12px 8px;
    counter-reset: home-step;
}
.home-step {
    position: relative;
    padding: 16px 16px 14px 44px;
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-md);
    background-color: var(--c-box);
    counter-increment: home-step;
}
.home-step::before {
    content: counter(home-step);
    position: absolute;
    top: 16px;
    left: 16px;
    width: 18px;
    font-variant-numeric: tabular-nums;
    font-size: 0.85em;
    font-weight: 600;
    color: var(--c-font-dim);
}
.home-step-title {
    margin: 0 0 6px;
    font-size: 0.98em;
    font-weight: 500;
    color: var(--c-font-strong);
}
.home-step-text {
    margin: 0 0 10px;
    font-size: 0.88em;
    line-height: 1.55;
    color: var(--c-font-dim);
}
.home-step-link {
    font-size: 0.86em;
    color: var(--c-font-strong);
    text-underline-offset: 3px;
}

/* --- FAQ (home + rules) --------------------------------------------- */
.home-faq-list {
    display: flex;
    flex-direction: column;
    padding: 0 12px 8px;
}
.home-faq-item {
    border-bottom: 1px solid var(--c-border-soft);
    padding: 0 12px;
}
.home-faq-item:first-child { border-top: 1px solid var(--c-border-soft); }
.home-faq-q {
    list-style: none;
    cursor: pointer;
    padding: 13px 26px 13px 0;
    position: relative;
    font-size: 0.95em;
    color: var(--c-font-strong);
}
.home-faq-q::-webkit-details-marker { display: none; }
.home-faq-q::after {
    content: '+';
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--c-font-dim);
    font-size: 1.1em;
    line-height: 1;
}
.home-faq-item[open] .home-faq-q::after { content: '\2212'; }
.home-faq-a {
    margin: 0;
    padding: 0 26px 14px 0;
    max-width: var(--prose);
    font-size: 0.9em;
    line-height: 1.6;
    color: var(--c-font-dim);
}

/* --- Rules page (the one-page summary at /como-jogar-shogi) ----------
   The page is an index like /pieces or /estudos: a hero, then labelled
   sections of the same borderless rows the rest of the site lists things
   in. Almost nothing is needed here - only the two things the shared
   vocabulary has no word for yet. */

/* A prose section ends in its "open the lesson" link, and the next section's
   label follows immediately. Without this the two sit the same distance
   apart as a paragraph and its own link, and the label reads as if it
   belonged to the link above it. */
.home-prose-body + .pieces-section-title { padding-top: 30px; }

/* The numbered list inside a prose section (the four drop restrictions). */
.rules-list {
    margin: 12px 0 12px 18px;
    padding: 0;
    font-size: 0.95em;
    line-height: 1.6;
}
.rules-list li { margin-bottom: 8px; }

/* A row that states a fact instead of linking somewhere (the chess/shogi
   comparison). It keeps the list's rhythm but must not offer a hover it
   cannot honour. */
.pieces-index-card.is-static { cursor: default; }
.pieces-index-card.is-static:hover,
body.dark-mode .pieces-index-card.is-static:hover { background-color: transparent; }

/* A description that is a sentence rather than a label. The single-line
   ellipsis is right for a wiki row whose title carries the meaning; here
   the sentence IS the content, so it wraps. Only inside these lists, so
   /pieces and /estudos keep their one-line rows. */
.rules-index .pieces-index-bottom .pieces-index-move {
    margin-top: 2px;
    line-height: 1.5;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}

/* --- Badges -----------------------------------------------------------
   A badge is a coin: round, coloured by family, with the kanji cut into it.
   Round matters at this size - a rounded rectangle with a glyph in it reads
   as a keyboard key, and the whole point is that it should read as something
   you were given. One hue per family, so a row of them reads as a collection
   and the family is legible before the name is. */
.user-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    margin-left: 5px;
    border-radius: 50%;
    background-color: var(--c-accent-soft);
    color: var(--c-accent-on-soft);
    font-family: var(--font-kanji);
    font-size: 0.72em;
    line-height: 1;
    vertical-align: middle;
    cursor: help;
}
.user-badge-course { background-color: var(--badge-course-bg); color: var(--badge-course-fg); }
.user-badge-time   { background-color: var(--badge-time-bg);   color: var(--badge-time-fg); }
.user-badge-play   { background-color: var(--badge-play-bg);   color: var(--badge-play-fg); }
.user-badge-streak { background-color: var(--badge-streak-bg); color: var(--badge-streak-fg); }
.user-badge-tsume  { background-color: var(--badge-tsume-bg);  color: var(--badge-tsume-fg); }
.user-badge-wiki   { background-color: var(--badge-wiki-bg);   color: var(--badge-wiki-fg); }
.user-badge-social { background-color: var(--badge-social-bg); color: var(--badge-social-fg); }
/* The rarest tier gets a ring, so "hard to get" is visible across a row
   without a second colour axis nobody would decode. */
.user-badge-t3 { box-shadow: 0 0 0 1.5px currentColor inset; }
.user-badge-lg { width: 30px; height: 30px; margin: 0; font-size: 1.02em; }

/* --- The flair: a coin with its name beside it ------------------------ */
.user-flair {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    max-width: 100%;
    padding: 3px 12px 3px 3px;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    background-color: var(--c-box-alt);
    color: inherit;
    font: inherit;
    text-decoration: none;
    vertical-align: middle;
}
.user-flair .user-badge { margin-left: 0; }
.user-flair-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.82em;
    font-weight: 500;
    color: var(--c-font-strong);
}
/* Only your own is a control, so only your own looks like one. */
.user-flair.is-editable { cursor: pointer; }
.user-flair.is-editable:hover,
.user-flair.is-editable:focus-visible {
    border-color: var(--c-border);
    background-color: var(--c-hover);
    outline: none;
}

/* --- The block in the profile header ---------------------------------- */
.profile-badges {
    position: relative;
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    text-decoration: none;
}
.profile-badges:hover { text-decoration: none; }
/* The rest of the collection: plain coins, tucked close so they read as one
   group beside the flair rather than as five loose marks. */
.profile-badge-rest {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    text-decoration: none;
}
.profile-badge-rest:hover { text-decoration: none; opacity: 0.75; }
.profile-badge-rest .user-badge { margin-left: 0; }

/* --- The picker ------------------------------------------------------- */
.badge-picker {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    z-index: 40;
    width: max-content;
    max-width: min(420px, 88vw);
    padding: 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-md);
    background-color: var(--c-box);
    box-shadow: var(--elev-2);
}
.badge-picker-head {
    padding: 2px 4px 8px;
    font-size: 0.75em;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.badge-picker-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 4px;
}
.badge-picker-option {
    justify-content: flex-start;
    width: 100%;
    border: 1px solid transparent;
    background: none;
    cursor: pointer;
    text-align: left;
}
.badge-picker-option:hover { background-color: var(--c-hover); }
.badge-picker-option.is-current {
    border-color: var(--c-border);
    background-color: var(--c-accent-soft);
}

/* The streaks and the favourites live inside the stats block, as further
   stats, but each group is a row of its own: the counts, then the streaks, then the
   favourite castle and opening. Left to wrap as one run, the three groups
   broke lines in the middle of a group and the header read as eleven loose
   pills; as rows they read as three short sentences. A row that is empty is
   hidden by the script, so a quiet profile does not carry blank lines. */
.profile-streaks,
.profile-favourites {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 18px;
    flex-basis: 100%;
}
/* Words in the same muted ink as the counts above them, not pills: the icon
   and the bold number are all the emphasis a row of these needs. */
.profile-streak {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    padding: 2px 0;
    border-radius: var(--radius-pill);
    line-height: 1.4;
}
.profile-streak strong { color: var(--c-font-strong); font-weight: 600; }
/* The favourite castle and opening: drawn as the streaks above them, but
   links, since each one names a wiki article. The hover pill grows outwards
   so the text does not move. */
.profile-favourite {
    /* Inline, not inline-flex: a long title then wraps like a sentence
       ("Double Wing Attack abertura mais / usada") instead of the title and
       its unit breaking into two side-by-side columns on a phone. */
    display: inline;
    line-height: 1.6;
    color: inherit;
    text-decoration: none;
    transition: background-color 0.12s ease;
    padding: 2px 8px;
    margin: 0 -8px;
}
.profile-favourite .streak-icon { margin-right: 5px; vertical-align: -0.15em; }
.profile-favourite:hover { background-color: var(--c-hover); }
.profile-favourite .streak-icon { margin-right: 1px; align-self: center; }

/* The achievements page. A locked badge is dimmed rather than hidden - the
   page is a menu of things to go and do. */
.badge-coin { display: flex; align-items: center; justify-content: center; }
/* A locked badge keeps its shape and loses its colour: the page is a menu of
   things to go and do, so you should be able to see what is on offer. */
.badge-row.is-locked .user-badge {
    background-color: var(--c-box-alt);
    color: var(--c-font-dim);
    box-shadow: none;
    opacity: 0.75;
}
.badge-row.is-locked .pieces-index-name { color: var(--c-font-dim); }
.badge-row.is-earned .badge-state {
    background-color: transparent;
    border: 1px solid var(--c-good);
    color: var(--c-good);
}
.badge-holders { opacity: 0.75; }

/* Source attribution at the foot of a course. Quieter than body prose and
   set off by the same hairline the FAQ rows use. */
.rules-credit {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--c-border-soft);
    font-size: 0.85em;
    color: var(--c-font-dim);
}

@media (max-width: 900px) {
    .home-prose-body { padding: 0 16px; }
    .home-steps-list, .home-faq-list { padding-left: 6px; padding-right: 6px; }
    .rules-hero .home-hero-h1 { font-size: 1.45em; max-width: none; }
}


/* The grade sits with the name, not in the stats row: it is identity, not a
   counter. */
.profile-rank {
    display: inline-flex;
    align-items: center;
    box-sizing: border-box;
    padding: 2px 10px;
    border-radius: var(--radius-pill, 999px);
    background: var(--c-accent, #272424);
    color: var(--c-on-accent, #fff);
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
}
/* A grade that is still settling reads as an outline rather than a claim. */
.profile-rank-provisional {
    background: transparent;
    color: var(--c-font-dim, inherit);
    border: 1px dashed var(--c-border, rgba(127, 127, 127, 0.5));
}

/* The tsume grade, in the same slot as the playing one and deliberately not
   the same colour: they are two independent ladders, and two identical pills
   reading "5k" and "7k" side by side would look like one of them was wrong.
   It borrows the tsume badge family's hue so the ladder, the coins on
   /conquistas and the chip here all read as one thing. */
.profile-rank-tsume {
    background: var(--badge-tsume-bg);
    color: var(--badge-tsume-fg);
}

/* The defender's komadai when it holds the whole rest of the set. Seven big
   glyphs carrying "17" and "4" were the loudest thing on the page and said
   the same thing in almost every problem; this says it once, quietly, and
   keeps the pieces in the tooltip. */
.tsume-hand.tsume-hand-rest {
    justify-content: flex-start;
    /* The base min-height is kept rather than dropped, and no padding is added
       on top of it. A komadai that is 44px with pieces in it and 20px with a
       caption in it moves the board between one problem and the next, and it
       moves the panel beside it out of line with the board it is paired to -
       and there is no box-sizing reset in this stylesheet, so 2px of padding
       here is 4px of drift there. */
    padding: 0;
}
.tsume-hand-note {
    font-size: 0.82rem;
    color: var(--c-font-dim, inherit);
    border-bottom: 1px dotted var(--c-border, rgba(127, 127, 127, 0.45));
    cursor: help;
}
.profile-rank-tsume.profile-rank-provisional {
    background: transparent;
    color: var(--c-font-dim, inherit);
}


/* --- O curso interativo (/como-jogar-shogi) ---------------------------
   Nine lesson pages plus the hub. Everything here is built by learn.js at
   runtime except the hub cards and the trail, which are server-rendered so
   the course is readable and crawlable with scripting off. The boards reuse
   .play-board / .play-cell / .play-piece: a lesson board and a match board
   are the same board. */

/* Hub: the course list is a .pieces-index of ordinary rows, so the only
   thing left to describe is the tick a finished lesson carries. */
.learn-done-chip {
    background-color: transparent;
    border: 1px solid var(--c-good);
    color: var(--c-good);
}

/* Lesson: the trail of nine dots, the header, the practice block. */
.learn-trail {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    padding: 14px 24px 10px;
    border-bottom: 1px solid var(--c-border-soft);
}
.learn-trail-home {
    font-size: 0.72em;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-font-dim);
    text-decoration: none;
}
.learn-trail-home:hover { color: var(--c-font-strong); }
.learn-trail-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.learn-trail-step {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: 1px solid var(--c-border-soft);
    border-radius: 50%;
    font-size: 0.78em;
    font-variant-numeric: tabular-nums;
    color: var(--c-font-dim);
    text-decoration: none;
}
.learn-trail-step:hover { border-color: var(--c-border); text-decoration: none; }
.learn-trail-step.is-done { border-color: var(--c-good); color: var(--c-good); }
.learn-trail-step.is-current {
    background-color: var(--c-accent);
    border-color: var(--c-accent);
    color: var(--c-on-accent);
}
.learn-eyebrow {
    margin: 0 0 8px;
    font-size: 0.72em;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.learn-practice { padding: 8px 0 4px; }

/* The stage: task line, board, feedback, buttons. */
.learn-stage {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    margin: 0 12px;
    padding: 16px 12px 18px;
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-md);
    background-color: var(--c-box);
}
.learn-stage.is-solved { border-color: var(--c-good); }
.learn-task {
    max-width: 46ch;
    margin: 0;
    text-align: center;
    font-size: 0.95em;
    line-height: 1.5;
    color: var(--c-font-strong);
}
.learn-stage-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    width: 100%;
    max-width: 460px;
}
.learn-feedback {
    min-height: 1.4em;
    margin: 0;
    max-width: 46ch;
    text-align: center;
    font-size: 0.9em;
    line-height: 1.5;
    color: var(--c-font-dim);
}
.learn-feedback.is-good { color: var(--c-good); }
.learn-feedback.is-bad { color: var(--c-bad); }
.learn-feedback.is-info { color: var(--c-font); }
/* With nothing to say it keeps no line: the reserved height was leaving a
   hole between the board and the buttons. */
.learn-feedback:empty { min-height: 0; }
.learn-stage-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.learn-btn {
    border-radius: var(--radius-pill);
    border: 1px solid var(--c-border);
    background-color: transparent;
    color: var(--c-accent);
    padding: 7px 16px;
    font-size: 0.88em;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
.learn-btn:hover:not(:disabled) { background-color: var(--c-accent-soft); }
.learn-btn:disabled { opacity: 0.45; cursor: default; }
.learn-btn-primary {
    background-color: var(--c-accent);
    border-color: var(--c-accent);
    color: var(--c-on-accent);
}

/* Board with coordinates: files across the top, ranks down the right, in one
   grid so the labels cannot drift out of line with the squares. */
.learn-frame {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 1.5em;
    grid-template-rows: 1.4em minmax(0, 1fr);
    width: 100%;
    max-width: 420px;
}
/* No coordinates: one cell, one board. The labels are not rendered at all in
   this mode - hiding them with display:none frees their grid cells, and the
   board then auto-places itself into the zero-width label column. */
.learn-frame-bare { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }
.learn-files {
    display: grid;
    grid-template-columns: repeat(9, 1fr);
    align-items: center;
    text-align: center;
    font-size: 0.68em;
    color: var(--c-font-dim);
}
.learn-ranks {
    display: grid;
    grid-template-rows: repeat(9, 1fr);
    align-items: center;
    justify-items: center;
    font-size: 0.68em;
    color: var(--c-font-dim);
}
.learn-board { touch-action: manipulation; }
/* The promotion zone, shown on request in lesson 1 and always in lesson 4. */
.learn-cell-zone { background: rgba(185, 28, 28, 0.10); }
body.dark-mode .learn-cell-zone { background: rgba(248, 113, 113, 0.14); }
.learn-cell-mark { box-shadow: inset 0 0 0 2px var(--c-good); }

/* Komadai. Gote's is above the board, sente's below, the way the two sides sit
   at a real board. */
.learn-hand {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    max-width: 420px;
    min-height: 34px;
}
.learn-hand-label {
    flex: 0 0 auto;
    font-size: 0.7em;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.learn-hand-list { display: flex; flex-wrap: wrap; gap: 6px; }
.learn-hand-piece {
    display: inline-flex;
    align-items: baseline;
    gap: 2px;
    padding: 3px 8px;
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-sm);
    background-color: var(--c-box-alt);
    cursor: pointer;
}
.learn-hand-piece:disabled { cursor: default; opacity: 0.6; }
.learn-hand-piece.is-selected { border-color: var(--c-accent); background-color: var(--c-accent-soft); }
.learn-hand-kanji { font-family: var(--font-kanji); font-size: 1.1em; color: var(--c-font-strong); }
.learn-hand-count { font-size: 0.75em; color: var(--c-font-dim); }
.learn-hand-empty { font-size: 0.8em; color: var(--c-font-dim); }

.learn-promote {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-md);
    background-color: var(--c-box-alt);
}
.learn-promote-q { font-size: 0.88em; color: var(--c-font-strong); }
/* display:flex beats the hidden attribute on its own, and the box would keep
   its space in the stage while the question is not being asked. */
.learn-promote[hidden] { display: none; }

/* Lesson 2: the piece picker and the note under the diagram. */
.learn-picker { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; }
.learn-picker-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 6px 10px;
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-sm);
    background-color: var(--c-box-alt);
    cursor: pointer;
}
.learn-picker-btn.is-selected { border-color: var(--c-accent); background-color: var(--c-accent-soft); }
.learn-picker-kanji { font-family: var(--font-kanji); font-size: 1.15em; color: var(--c-font-strong); }
.learn-picker-name { font-size: 0.7em; color: var(--c-font-dim); }
.learn-piece-note {
    margin: 0;
    max-width: 46ch;
    font-size: 0.88em;
    line-height: 1.55;
    color: var(--c-font-dim);
}
.learn-piece-note-name { display: block; margin-bottom: 4px; color: var(--c-font-strong); }

/* --- Lição 2: o diagrama de movimento -------------------------------
   The shape a shogi book uses: the piece in the middle of a 3x3 square, a dot
   on every square it steps to, an arrow down every direction it ranges along.
   The knight is the one piece that does not fit - its squares are two ranks
   away - so its diagram gets a fourth rank and a dashed leap over the square
   it skips, rather than a lie drawn one square closer. Both diagrams are
   generated from the same engine the boards use. */
.learn-diagrams {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: center;
    gap: 18px;
}
.learn-diagram { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.learn-diagram-caption {
    font-size: 0.8em;
    color: var(--c-font-dim);
    text-align: center;
}
.learn-diagram-none {
    justify-content: center;
}
.learn-diagram-none-text {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 138px;
    height: 138px;
    border: 1px dashed var(--c-border);
    border-radius: var(--radius-sm);
    font-size: 0.82em;
    text-align: center;
    color: var(--c-font-dim);
}
.learn-dia { max-width: 100%; height: auto; overflow: visible; }
.learn-dia-cell {
    fill: transparent;
    stroke: var(--c-border);
    stroke-width: 0.025;
}
.learn-dia-home { fill: var(--c-box-alt); stroke: var(--c-font-dim); stroke-width: 0.045; }
.learn-dia-kanji {
    font-family: var(--font-kanji);
    font-weight: 700;
    fill: var(--c-font-strong);
}
.learn-dia-kanji.is-promoted { fill: #b91c1c; }
body.dark-mode .learn-dia-kanji.is-promoted { fill: #f87171; }
.learn-dia-dot { fill: var(--c-accent); }
.learn-dia-shaft {
    stroke: var(--c-accent);
    stroke-width: 0.075;
    stroke-linecap: round;
}
.learn-dia-head { fill: var(--c-accent); }
.learn-dia-leap {
    fill: none;
    stroke: var(--c-accent);
    stroke-width: 0.055;
    stroke-linecap: round;
    stroke-dasharray: 0.13 0.11;
    opacity: 0.75;
}
.learn-dia-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px 16px;
    margin: 0;
    font-size: 0.82em;
    color: var(--c-font-dim);
}
.learn-dia-legend-item { display: inline-flex; align-items: center; gap: 5px; }
.learn-dia-swatch { flex: 0 0 auto; }
.learn-piece-note-text { display: block; }
.learn-piece-note-text + .learn-piece-note-text { margin-top: 8px; }

@media (max-width: 480px) {
    .learn-diagrams { gap: 12px; }
    .learn-dia { width: 132px; height: auto; }
    .learn-diagram-none-text { width: 118px; height: 118px; }
}

/* Lessons 8 and 9: the move list, in both notations. */
.learn-log-wrap { width: 100%; }
.learn-log-title {
    margin: 0 0 6px;
    font-size: 0.72em;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.learn-log {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 190px;
    overflow-y: auto;
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-sm);
}
.learn-log-row {
    display: grid;
    grid-template-columns: 2.2em 5em 1fr;
    gap: 8px;
    align-items: baseline;
    padding: 5px 10px;
    font-size: 0.85em;
}
.learn-log-row:nth-child(odd) { background-color: var(--c-box-alt); }
.learn-log-n { color: var(--c-font-dim); font-variant-numeric: tabular-nums; }
.learn-log-usi { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--c-font-strong); }
.learn-log-jp { font-family: var(--font-kanji); color: var(--c-font); }
.learn-log-empty { padding: 8px 10px; font-size: 0.85em; color: var(--c-font-dim); }

/* The two questions at the end of every lesson. */
.learn-quiz { list-style: none; margin: 0; padding: 0 12px; display: flex; flex-direction: column; gap: 12px; }
.learn-quiz-item {
    padding: 14px 16px;
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-md);
    background-color: var(--c-box);
}
.learn-quiz-q { margin: 0 0 10px; font-size: 0.95em; color: var(--c-font-strong); }
.learn-quiz-options { display: flex; flex-direction: column; gap: 6px; }
.learn-quiz-option {
    text-align: left;
    padding: 8px 12px;
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-sm);
    background-color: transparent;
    color: var(--c-font);
    font-size: 0.9em;
    cursor: pointer;
}
.learn-quiz-option:hover { background-color: var(--c-hover); }
.learn-quiz-item.is-answered .learn-quiz-option { cursor: default; }
.learn-quiz-item.is-answered .learn-quiz-option:hover { background-color: transparent; }
.learn-quiz-option.is-right { border-color: var(--c-good); color: var(--c-good); }
.learn-quiz-option.is-wrong { border-color: var(--c-bad); color: var(--c-bad); }
.learn-quiz-why {
    margin: 10px 0 0;
    font-size: 0.88em;
    line-height: 1.55;
    color: var(--c-font-dim);
}

/* Bottom of a lesson: back, mark as read, on to the next one. */
.learn-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin: 8px 12px 24px;
    padding-top: 14px;
    border-top: 1px solid var(--c-border-soft);
}
.learn-nav-link {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-width: 40%;
    color: inherit;
    text-decoration: none;
}
.learn-nav-next { text-align: right; align-items: flex-end; }
.learn-nav-dir {
    font-size: 0.7em;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.learn-nav-title { font-size: 0.9em; color: var(--c-font-strong); }
.learn-nav-link:hover .learn-nav-title { text-decoration: underline; text-underline-offset: 3px; }
.learn-done-btn.is-done {
    border-color: var(--c-good);
    color: var(--c-good);
}

/* --- O curso com o layout da wiki ------------------------------------
   A lesson is an article with a board in it, so it uses the article shell:
   the toolbar row with the back link, a centred title, a centred lead, and a
   body whose prose sits in one reading column.

   That column has to be the SAME column for every block on the page, and it
   was not: .wiki-body is content-box, so its 24px of padding made it 48px
   wider than the article, and everything centred inside it landed 24px off
   the axis the title, the lead and the footer were centred on. Three left
   edges on one page. Scoped to the course rather than changed globally,
   because the wiki's own articles are laid out against the old measure. */
.learn-page .wiki-body { box-sizing: border-box; }

/* Everything the course adds to the body gets the reading column, so it lines
   up with the headings and paragraphs the wiki rule already places there. */
.learn-body > .learn-mount,
.learn-body > .learn-quiz-section,
.learn-page .wiki-movement,
.learn-stage,
.learn-quiz,
.learn-quiz-section > h2,
.learn-foot {
    max-width: var(--prose);
    margin-left: auto;
    margin-right: auto;
    box-sizing: border-box;
}
.learn-page .wiki-movement { padding-left: 0; padding-right: 0; }
/* The wiki indents a list with margin-left, and that beats the auto margins
   that centre the column - a list would hang 21px to the left of every
   paragraph around it. The indent becomes padding, inside the column. */
.learn-body .learn-quiz,
.learn-body > ul,
.learn-body > ol {
    max-width: var(--prose);
    margin-left: auto;
    margin-right: auto;
    box-sizing: border-box;
}
.learn-body .learn-quiz { padding-left: 0; padding-right: 0; }
.learn-body > ul,
.learn-body > ol { padding-left: 1.5em; }
.learn-quiz-section > h2 { display: block; }
/* The body opens on the board, so its heading does not need the full gap a
   mid-article heading gets. */
.learn-body > h2:first-child { margin-top: 0; }
/* A panel needs more air above it than a paragraph does. */
.learn-body .learn-stage { margin-top: 16px; margin-bottom: 10px; }

/* The board block is the one thing on the page that is not prose, so it reads
   as a panel inside the article rather than as more of the text. */
.learn-page .learn-stage,
.learn-page .learn-quiz-item { background-color: var(--c-box-alt); }
.learn-page .learn-stage { padding: 18px 16px 20px; }

/* --- O teste no fim da lição -----------------------------------------
   The question and its options were packed too tight to read as a group, and
   a plain row of boxes gave no sign of which one you picked. Each option now
   carries its letter, which becomes the tick or the cross once answered - the
   result does not depend on colour alone. */
.learn-quiz { gap: 14px; }
.learn-quiz-item { padding: 16px 18px; }
.learn-quiz-q { margin: 0 0 12px; font-size: 0.98em; line-height: 1.45; }
.learn-quiz-options { gap: 8px; }
.learn-quiz-option {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    font-size: 0.92em;
    line-height: 1.4;
}
.learn-quiz-mark {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--c-border);
    border-radius: 50%;
    font-size: 0.75em;
    font-weight: 600;
    color: var(--c-font-dim);
}
.learn-quiz-option.is-right {
    border-color: var(--c-good);
    color: var(--c-good);
    background-color: rgba(24, 128, 56, 0.08);
}
.learn-quiz-option.is-right .learn-quiz-mark { border-color: var(--c-good); color: var(--c-good); }
.learn-quiz-option.is-wrong {
    border-color: var(--c-bad);
    color: var(--c-bad);
    background-color: rgba(217, 48, 37, 0.08);
}
.learn-quiz-option.is-wrong .learn-quiz-mark { border-color: var(--c-bad); color: var(--c-bad); }
.learn-quiz-why {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--c-border-soft);
}

/* The lesson number is a kicker over the centred title. */
.learn-page .learn-eyebrow {
    text-align: center;
    margin: 16px 0 10px;
    padding: 0 24px;
}
/* The dots live in the toolbar row, which already has the page padding. */
.wiki-toolbar-row .learn-trail { padding: 0; border: none; }
/* Narrow: the dots take a line of their own rather than fighting the back
   link and whatever floats over that corner. */
@media (max-width: 700px) {
    .learn-page .wiki-toolbar-row { flex-wrap: wrap; row-gap: 10px; }
    .learn-page .wiki-toolbar-row .learn-trail { width: 100%; }
    .learn-page .learn-trail-list { justify-content: flex-start; }
}

/* --- Fim da lição ----------------------------------------------------
   Three things crammed into one row - back, done, forward - read as a jumble
   at the width of a reading column, and the two titles had nowhere to go. The
   button gets its own line; the two links become a pair of cards. */
.learn-foot {
    margin-top: 36px;
    margin-bottom: 44px;
    padding-top: 20px;
    border-top: 1px solid var(--c-border-soft);
}
.learn-foot-done { display: flex; justify-content: center; margin-bottom: 14px; }
.learn-nav {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin: 0;
    padding: 0;
    border: none;
}
.learn-nav-link {
    display: flex;
    flex-direction: column;
    gap: 3px;
    max-width: none;
    padding: 12px 14px;
    border: 1px solid var(--c-border-soft);
    border-radius: var(--radius-md);
    background-color: var(--c-box);
    color: inherit;
    text-decoration: none;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.learn-nav-link:hover {
    border-color: var(--c-border);
    background-color: var(--c-box-alt);
    text-decoration: none;
}
.learn-nav-next { text-align: right; align-items: flex-end; }
.learn-nav-dir {
    font-size: 0.7em;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.learn-nav-title { font-size: 0.92em; line-height: 1.4; color: var(--c-font-strong); }
.learn-nav-link:hover .learn-nav-title { text-decoration: none; }
.learn-done-btn { padding: 9px 22px; }
.learn-done-btn.is-done { border-color: var(--c-good); color: var(--c-good); }

@media (max-width: 560px) {
    .learn-nav { grid-template-columns: 1fr; }
    .learn-nav-next { text-align: left; align-items: flex-start; }
}

/* Narrow screens: the lesson page's own blocks. The hubs are .pieces-index
   lists now and already carry the site's responsive padding. */
@media (max-width: 900px) {
    .learn-quiz { padding-left: 6px; padding-right: 6px; }
    .learn-trail { padding: 12px 16px 8px; }
    .learn-stage { margin: 0 6px; padding: 14px 8px 16px; }
    .learn-log-row { grid-template-columns: 2em 4.5em 1fr; }
}

/* --- The notification soft ask ---------------------------------------
   A card in the corner, not a modal: it is a suggestion, and blocking the
   page to make a suggestion is how you teach people to dismiss things
   without reading them. Slides in once, and never comes back for a week if
   turned down. */
.push-ask {
    position: fixed;
    z-index: 90;
    left: 16px;
    bottom: 16px;
    width: min(360px, calc(100vw - 32px));
    padding: 16px 18px 14px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-lg);
    background-color: var(--c-box);
    box-shadow: var(--elev-2);
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.push-ask.is-in { opacity: 1; transform: translateY(0); }
.push-ask-title {
    margin-bottom: 6px;
    font-size: 1em;
    font-weight: 600;
    color: var(--c-font-strong);
}
.push-ask-body {
    margin: 0 0 14px;
    font-size: 0.88em;
    line-height: 1.55;
    color: var(--c-font-dim);
}
.push-ask-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
}

/* The donate bar already owns the bottom-right corner on wide screens, and
   the mobile tab bar owns the bottom edge on narrow ones. */
@media (max-width: 900px) {
    .push-ask { left: 12px; right: 12px; bottom: calc(var(--tabbar-h, 64px) + 12px); width: auto; }
}


/* --- Streak icons -----------------------------------------------------
   One glyph per streak - a calendar for visits, a piece for games - drawn
   like the nav icons rather than like an emoji. The caption underneath
   already names the streak, so the icon's job is to say which one at a
   glance and whether it is still running. */
.streak-icon {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    line-height: 0;
}
.streak-icon svg { display: block; }
/* Gone out: same shape, no weight. Used where a best-ever streak is shown
   next to a current one of zero. */
.streak-icon.is-cold { color: var(--c-font-dim); opacity: 0.5; }

/* In the profile stats rows the icon sits tight to its number rather than
   spaced like a separate word - the flame of a streak and the line icon of
   a count alike. */
.profile-streak .streak-icon,
.profile-stat .streak-icon { margin-right: 1px; align-self: center; }
/* The likes count keeps the site's mark for a like, the 金 on every "curtir"
   button, drawn to the same 14px slot as the line icons beside it. */
.profile-stat-kanji {
    width: 14px;
    justify-content: center;
    font-family: var(--font-kanji);
    font-size: 0.95em;
    font-weight: 600;
    line-height: 1;
}
/* On the achievements page it takes the slot the kanji had, so it lines up
   with the badge coins in the lists above it. */
.streak-glyph { display: flex; align-items: center; justify-content: center; }
.streak-glyph .streak-icon svg { width: 22px; height: 22px; }

/* --- Board effects ----------------------------------------------------
   The band that crosses the board when a castle closes, when an opening is
   complete, or when a king is in check, and the impact of a piece coming
   down from hand.

   The whole layer is inert: it sits over a board people are trying to click
   on, and an announcement that swallows a move would be worse than no
   announcement at all. */
.board-fx-layer {
    position: absolute;
    inset: 0;
    z-index: 6;
    overflow: hidden;
    pointer-events: none;
}

/* The band itself. Anchored on the middle row of the board and full width,
   the way Shogi Wars runs it - a shape crossing the position, not a toast in
   a corner. */
.board-fx-band {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 10px 16px;
    transform: translateY(-50%) scaleX(0.55);
    opacity: 0;
    transform-origin: center;
    transition: transform 0.26s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.2s ease;
    color: #fff;
    /* Angled edges, so it reads as a stamp rather than a bar. */
    clip-path: polygon(0 12%, 100% 0, 100% 88%, 0 100%);
    box-shadow: 0 6px 22px rgba(0, 0, 0, 0.35);
}
.board-fx-band.is-in { transform: translateY(-50%) scaleX(1); opacity: 1; }
.board-fx-band.is-out {
    transform: translateY(-50%) scaleX(1.06);
    opacity: 0;
    transition: transform 0.3s ease-in, opacity 0.3s ease-in;
}

/* Check has two colours because it is two different pieces of news. Red is
   the one against you, which is the urgent one and keeps the original
   treatment; green is the one you just delivered. */
.board-fx-band-check   { background: linear-gradient(90deg, #7f1d1d, #dc2626 55%, #7f1d1d); }
.board-fx-band-check-good { background: linear-gradient(90deg, #14532d, #16a34a 55%, #14532d); }
.board-fx-band-castle  { background: linear-gradient(90deg, #1e3a8a, #2563eb 55%, #1e3a8a); }
.board-fx-band-opening { background: linear-gradient(90deg, #78350f, #d97706 55%, #78350f); }
.board-fx-band-promote { background: linear-gradient(90deg, #3f1d5c, #7c3aed 55%, #3f1d5c); }
/* Checkmate. Richer than the in-game bands and held longer, because this one
   is the end of the game rather than a note about it - the win carries a gold
   edge, the loss goes darker than an ordinary check. */
.board-fx-band-mate-win  { background: linear-gradient(90deg, #14532d, #15803d 40%, #ca8a04); }
.board-fx-band-mate-loss { background: linear-gradient(90deg, #450a0a, #991b1b 55%, #450a0a); }
.board-fx-band-mate-draw { background: linear-gradient(90deg, #1f2937, #4b5563 55%, #1f2937); }
.board-fx-band-mate-win .board-fx-kanji,
.board-fx-band-mate-loss .board-fx-kanji { font-size: clamp(1.9rem, 8vw, 2.8rem); }
.board-fx-band-neutral { background: linear-gradient(90deg, #262626, #4b5563 55%, #262626); }

.board-fx-kanji {
    font-family: var(--font-kanji);
    font-size: clamp(1.6rem, 7vw, 2.4rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.08em;
    text-shadow: 0 2px 6px rgba(0, 0, 0, 0.45);
    /* Lands a beat after the band, which is what gives it the punch. */
    animation: board-fx-pop 0.42s cubic-bezier(0.2, 1.6, 0.4, 1) 0.08s both;
}
.board-fx-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: clamp(0.8rem, 2.8vw, 1rem);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
    animation: board-fx-fade 0.3s ease 0.18s both;
}
@keyframes board-fx-pop {
    from { transform: scale(0.4); opacity: 0; }
    to   { transform: scale(1);   opacity: 1; }
}
@keyframes board-fx-fade {
    from { opacity: 0; transform: translateX(-6px); }
    to   { opacity: 1; transform: none; }
}

/* --- A piece landing from hand --------------------------------------- */
.play-cell { position: relative; }

.board-fx-slam {
    /* Comes in oversized and settles, so a drop reads as placed rather than
       as having quietly appeared between renders. */
    animation: board-fx-slam 0.34s cubic-bezier(0.2, 1.4, 0.35, 1) both;
}
@keyframes board-fx-slam {
    0%   { transform: scale(1.75); opacity: 0.25; }
    60%  { transform: scale(0.94); opacity: 1; }
    100% { transform: none; opacity: 1; }
}
/* Gote pieces are drawn rotated, so the slam has to keep the rotation or the
   piece spins upright for a third of a second. */
.play-piece-flipped.board-fx-slam { animation-name: board-fx-slam-flipped; }

/* The promotion: the front folds away around its vertical axis, the glyph
   is swapped by the script at the fold, and the back comes up. Gote's pieces
   carry their 180-degree turn inside the same keyframes, since one
   `transform` cannot hold two animations. */
.board-fx-flip-out { animation: board-fx-flip-out 0.17s ease-in both; backface-visibility: hidden; }
.board-fx-flip-in { animation: board-fx-flip-in 0.26s cubic-bezier(0.2, 1.4, 0.35, 1) both; backface-visibility: hidden; }
@keyframes board-fx-flip-out { from { transform: rotateY(0deg); } to { transform: rotateY(90deg); } }
@keyframes board-fx-flip-in { from { transform: rotateY(-90deg); } to { transform: rotateY(0deg); } }
.play-piece-flipped.board-fx-flip-out { animation-name: board-fx-flip-out-flipped; }
.play-piece-flipped.board-fx-flip-in { animation-name: board-fx-flip-in-flipped; }
@keyframes board-fx-flip-out-flipped { from { transform: rotate(180deg) rotateY(0deg); } to { transform: rotate(180deg) rotateY(90deg); } }
@keyframes board-fx-flip-in-flipped { from { transform: rotate(180deg) rotateY(-90deg); } to { transform: rotate(180deg) rotateY(0deg); } }

/* The capture: a ghost of the taken piece, lifted off its square and carried
   to the komadai. Sized by the script to the square it left. */
.board-fx-fly {
    position: fixed;
    z-index: 60;
    pointer-events: none;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0.95;
    transition: transform 0.46s cubic-bezier(0.3, 0.7, 0.3, 1), opacity 0.46s ease-in;
    will-change: transform, opacity;
}
.board-fx-fly-piece { width: 100%; height: 100%; }
.board-fx-fly-piece .play-piece { font-size: clamp(1.2rem, 7.2vw, 2.2rem); }
/* The hand piece the ghost lands on. */
.board-fx-pop { animation: board-fx-pop 0.42s cubic-bezier(0.2, 1.6, 0.4, 1) both; }
@keyframes board-fx-pop {
    0%   { transform: scale(1); }
    45%  { transform: scale(1.22); }
    100% { transform: scale(1); }
}

/* The king in check beats until the check is answered. Pure CSS, so it
   obeys the preference through the class board-fx.js keeps on <html>. */
html:not(.board-fx-off) .play-cell-check .play-piece {
    animation: board-fx-king 1.1s ease-in-out infinite;
}
html:not(.board-fx-off) .play-cell-check .play-piece-flipped {
    animation-name: board-fx-king-flipped;
}
@keyframes board-fx-king {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.09); }
}
@keyframes board-fx-king-flipped {
    0%, 100% { transform: rotate(180deg) scale(1); }
    50%      { transform: rotate(180deg) scale(1.09); }
}

/* The clock under ten seconds: red already, now beating once a second. */
html:not(.board-fx-off) .play-player-clock-critical {
    animation: board-fx-clock 1s ease-in-out infinite;
}
@keyframes board-fx-clock {
    0%, 100% { transform: scale(1); opacity: 1; }
    50%      { transform: scale(1.12); opacity: 0.75; }
}

/* Coordinates, when asked for: the file in the top-left corner of the top
   row and the rank in the top-right corner of the right column, inside the
   squares so the board's own geometry does not move. */
.play-coord {
    position: absolute;
    top: 1px;
    font-size: 0.5em;
    line-height: 1;
    opacity: 0.55;
    pointer-events: none;
    font-family: var(--font-ui);
    font-weight: 600;
}
.play-coord-file { left: 3px; }
.play-coord-rank { right: 3px; font-family: var(--font-kanji); font-weight: 500; }
@keyframes board-fx-slam-flipped {
    0%   { transform: rotate(180deg) scale(1.75); opacity: 0.25; }
    60%  { transform: rotate(180deg) scale(0.94); opacity: 1; }
    100% { transform: rotate(180deg); opacity: 1; }
}

.board-fx-ring {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 70%;
    height: 70%;
    border: 2px solid var(--c-accent);
    border-radius: 50%;
    pointer-events: none;
    animation: board-fx-ring 0.5s ease-out both;
}
body.dark-mode .board-fx-ring { border-color: rgba(255, 255, 255, 0.75); }
@keyframes board-fx-ring {
    from { transform: scale(0.35); opacity: 0.85; }
    to   { transform: scale(1.9);  opacity: 0; }
}

/* Someone who has asked for less motion gets the information without the
   movement: the band still appears and still says what happened. */
@media (prefers-reduced-motion: reduce) {
    .board-fx-band,
    .board-fx-kanji,
    .board-fx-label,
    .board-fx-slam,
    .board-fx-flip-out,
    .board-fx-flip-in,
    .board-fx-fly,
    .board-fx-pop,
    .play-cell-check .play-piece,
    .play-player-clock-critical,
    .board-fx-ring { animation: none; transition: none; }
}

/* --- The opponent's card, after the game ------------------------------
   Rises from the bottom edge of the board once the result has been
   announced: the face and the name of the person you just played, and the
   one social action that belongs to that moment. Interactive, so it lives
   outside the pointer-events:none effects layer; over the bottom rows only,
   so the final position stays readable; and it stays until closed - a
   button that vanishes while you reach for it is worse than one you have
   to dismiss. Its own dark surface, so it reads the same on every board
   and every theme. */
.play-endcard {
    position: absolute;
    left: 5%;
    right: 5%;
    bottom: 4%;
    z-index: 7;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 40px 12px 14px;
    border-radius: 14px;
    background: rgba(17, 17, 20, 0.93);
    color: #fff;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
    transform: translateY(130%);
    opacity: 0;
    transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease;
}
.play-endcard.is-in { transform: none; opacity: 1; }
.play-endcard.is-out {
    transform: translateY(130%);
    opacity: 0;
    transition: transform 0.3s ease-in, opacity 0.2s ease;
}
.play-endcard-avatar {
    flex: 0 0 auto;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    object-fit: cover;
    background: #111;
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.28);
    transform: scale(0.4);
    opacity: 0;
    transition: transform 0.45s cubic-bezier(0.2, 1.6, 0.4, 1) 0.18s, opacity 0.2s ease 0.18s;
}
.play-endcard.is-in .play-endcard-avatar { transform: none; opacity: 1; }
/* The ring says who won: gold when it was you, red when it was them. */
.play-endcard-win .play-endcard-avatar { box-shadow: 0 0 0 3px #eab308; }
.play-endcard-loss .play-endcard-avatar { box-shadow: 0 0 0 3px #dc2626; }
.play-endcard-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.play-endcard-kicker {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #cbd5e1;
}
.play-endcard-name {
    font-size: clamp(1rem, 3.6vw, 1.25rem);
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.play-endcard-result { font-size: 0.8rem; color: #e5e7eb; }
.play-endcard-actions {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
}
/* The site accent is near-black on the light themes, which would vanish on
   this dark card, so the button carries its own inks here. */
.play-endcard .profile-follow {
    background-color: #fff;
    border-color: #fff;
    color: #111;
    white-space: nowrap;
}
.play-endcard .profile-follow:hover { background-color: #e5e7eb; border-color: #e5e7eb; }
.play-endcard .profile-follow.is-following {
    background-color: transparent;
    border-color: rgba(255, 255, 255, 0.45);
    color: #fff;
}
.play-endcard .profile-follow.is-following:hover { background-color: rgba(255, 255, 255, 0.12); }
.play-endcard .profile-follow[disabled] { opacity: 0.6; cursor: default; }
.play-endcard-profile {
    font-size: 0.78rem;
    text-align: center;
    color: #cbd5e1;
    text-decoration: underline;
    white-space: nowrap;
}
.play-endcard-profile:hover { color: #fff; }
.play-endcard-close {
    position: absolute;
    top: 4px;
    right: 6px;
    padding: 4px 8px;
    border: none;
    background: none;
    color: #cbd5e1;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
}
.play-endcard-close:hover { color: #fff; }

/* Your own card, shown before the opponent's: the number the game moved,
   counted up from where it was, with the change in a chip that pops once
   the count lands. A click skips ahead. */
.play-endcard-rating { cursor: pointer; padding-right: 14px; }
.play-endcard-figure {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
}
.play-endcard-number {
    font-size: clamp(1.6rem, 6.5vw, 2.1rem);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    transition: transform 0.28s cubic-bezier(0.2, 1.6, 0.4, 1);
}
.play-endcard-number.is-landed { transform: scale(1.08); }
.play-endcard-delta {
    padding: 2px 9px;
    border-radius: var(--radius-pill);
    font-size: 0.8rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    opacity: 0;
    transform: scale(0.6);
    transition: opacity 0.2s ease, transform 0.36s cubic-bezier(0.2, 1.6, 0.4, 1);
}
.play-endcard-delta.is-in { opacity: 1; transform: none; }
.play-endcard-delta.is-up   { background: rgba(74, 222, 128, 0.18); color: #4ade80; }
.play-endcard-delta.is-down { background: rgba(248, 113, 113, 0.18); color: #f87171; }
.play-endcard-delta.is-flat { background: rgba(255, 255, 255, 0.12); color: #e5e7eb; }
@media (max-width: 480px) {
    .play-endcard { left: 3%; right: 3%; gap: 8px; padding: 10px 34px 10px 10px; }
    .play-endcard-rating { padding-right: 10px; }
    .play-endcard-avatar { width: 44px; height: 44px; }
    .play-endcard-result { display: none; }
}
@media (prefers-reduced-motion: reduce) {
    .play-endcard, .play-endcard-avatar, .play-endcard-number, .play-endcard-delta { transition: none; }
}

/* --- The opening presentation ----------------------------------------
   Both players crossing the board from opposite sides before the first
   move. Allowed to cover the board because at this moment the board is
   still the starting position and there is nothing to hide. */
.board-fx-vs {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    gap: 6px;
    background: rgba(12, 12, 14, 0.72);
    backdrop-filter: blur(2px);
    opacity: 0;
    transition: opacity 0.22s ease;
}
.board-fx-vs.is-in { opacity: 1; }
.board-fx-vs.is-out { opacity: 0; transition: opacity 0.34s ease; }

.board-fx-vs-side {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 18px;
    background: linear-gradient(90deg, rgba(31, 41, 55, 0.96), rgba(17, 24, 39, 0.72));
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.4);
    transition: transform 0.42s cubic-bezier(0.16, 1, 0.3, 1);
}
/* Opposite sides, so the two of them meet in the middle. */
.board-fx-vs-top { transform: translateX(-115%); }
.board-fx-vs-bottom { transform: translateX(115%); flex-direction: row-reverse; }
.board-fx-vs.is-in .board-fx-vs-top,
.board-fx-vs.is-in .board-fx-vs-bottom { transform: none; }

.board-fx-vs-avatar {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    object-fit: cover;
    background: #111;
}
.board-fx-vs-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: clamp(0.9rem, 3.2vw, 1.15rem);
    font-weight: 700;
    color: #fff;
}
.board-fx-vs-sub {
    flex: 0 0 auto;
    padding: 2px 9px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.14);
    font-size: 0.75em;
    font-weight: 600;
    color: #e5e7eb;
}
.board-fx-vs-mark {
    align-self: center;
    font-family: var(--font-kanji);
    font-size: clamp(1.6rem, 6vw, 2.2rem);
    font-weight: 700;
    color: #fff;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.6);
    opacity: 0;
    transform: scale(0.5);
    transition: opacity 0.24s ease 0.22s, transform 0.34s cubic-bezier(0.2, 1.6, 0.4, 1) 0.22s;
}
.board-fx-vs.is-in .board-fx-vs-mark { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    .board-fx-vs,
    .board-fx-vs-side,
    .board-fx-vs-mark { transition: none; }
    .board-fx-vs-top, .board-fx-vs-bottom { transform: none; }
}


/* --- Tsume trainer ----------------------------------------------------
   The solving page is the study page's sibling and is built out of the
   same parts: the studies hero, the two-column frame, .play-board between
   two komadai, a panel beside it. Someone arriving from /estudos should
   find the board where they left it, so the measurements here are the
   study's measurements and only what a solving page has and a study page
   does not - the prompt, the verdict, the trail of moves - is new.

   Nothing below reaches inside the board. It stays .play-board /
   .play-cell / .play-piece exactly as the match room draws it. */

/* The facts strip under the lead. .studies-counts already gives it the
   size, the dim colour and the tabular figures; the height is the one
   thing it cannot give. The strip is server-rendered empty and filled by
   the dashboard fetch, and without a line held for it the whole page -
   board included - drops a row a beat after it settled. */
/* The kanji as a kicker over the headline. It used to sit inside the title in
   brackets, which made one line do the work of three; up here it is a mark
   rather than a word, so it gets the kanji face and none of the weight. */
.tsume-kicker {
    margin: 0 0 4px;
    font-family: var(--font-kanji);
    font-size: 1.05em;
    letter-spacing: 0.28em;
    color: var(--c-font-dim);
    line-height: 1;
}

/* The header's four numbers, opposite the text the way the contributor faces
   sit on the studies hub. They were a grey run of middots where every figure
   weighed the same as every label and none could be picked out at a glance;
   stacking the figure over its label is what makes them scannable, and giving
   the hero a right-hand block is what stops it reading as unfinished.

   Sized off the tallest plausible value (a four-character grade like "10k?")
   so the row does not reflow as the numbers change under it. */
/* MINIMAL ON PURPOSE.

   These were five bordered tiles, and then one divided panel with the grade
   toned inside it, and both were a scoreboard bolted to a hero: the figures
   are worth a glance, not a frame. They are now the same quiet pairs the rest
   of the site sets small print in, and the signed-out state - one pair - is
   simply this with less in it rather than a different treatment.

   The height is held before the fetch answers, because the strip is
   server-rendered empty and without a line kept for it the board below drops
   a row a beat after it settled. */
.tsume-stats {
    flex: 0 1 auto;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    align-content: flex-start;
    gap: 4px 18px;
    min-height: 40px;
    font-size: 0.85rem;
}
.tsume-stat { display: inline-flex; align-items: baseline; gap: 5px; }
.tsume-stat-value {
    font-weight: 600;
    color: var(--c-font-strong);
    font-variant-numeric: tabular-nums;
}
.tsume-stat-label { color: var(--c-font-dim); }

/* ---- Choosing a length ---- */
/* Length is the difficulty dial, so this is the one control on the page
   and it sits directly under the hero. It wraps rather than scrolls:
   pills that run off the right edge of a phone are pills nobody knows
   are there. */
.tsume-lengths {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 10px 24px 0;
}
/* Tighter than the default .home-cta, because six of these share a row.
   The tap target does not shrink with the padding - the mobile layer
   names .tsume-length in its 44px list for exactly this reason. */
.tsume-length {
    display: inline-flex;
    align-items: baseline;
    gap: 7px;
    padding: 7px 16px;
    font-size: 0.9em;
    cursor: pointer;
}
/* How far through that shelf you are. The counts already came down with the
   dashboard and were being thrown away; a pill reading "5 lances 3/38" is the
   difference between a filter and a set of shelves somebody is working
   through. Tabular so the pills do not twitch as the numbers change. */
.tsume-length-count {
    font-size: 0.82em;
    font-variant-numeric: tabular-nums;
    opacity: 0.6;
}
.tsume-length-count[hidden] { display: none; }
.tsume-lengths .tsume-length.is-current .tsume-length-count { opacity: 0.75; }
/* Filled, the way an active chapter tab is on a study. An outlined pill
   that only darkens its border does not survive being one of six in a
   row: which length you are solving has to be readable at a glance. */
/* Scoped through the container purely for weight. The Theme layer carries a
   `body.dark-mode .home-cta` rule that forces a transparent background, and at
   two classes plus an element it outranks a bare `.tsume-length.is-current` -
   so in dark mode the selected length was drawn exactly like the four that
   were not. Three classes beats it without writing a theme rule of our own,
   which is what the tokens exist to avoid. */
.tsume-lengths .tsume-length.is-current {
    background-color: var(--c-accent);
    border-color: var(--c-accent);
    color: var(--c-on-accent);
}
.tsume-lengths .tsume-length.is-current:hover {
    background-color: var(--c-accent-hover);
    border-color: var(--c-accent-hover);
    color: var(--c-on-accent);
}

/* ---- The frame ---- */
.tsume-layout {
    display: grid;
    grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
    gap: 24px;
    align-items: start;
    padding: 16px 24px 8px;
}
/* 420px is the study board's measure, and the column carries the same cap
   rather than the board alone: the komadai are siblings of the board, and
   board-fx stretches its banner across the whole of .play-board-wrap. A
   board narrower than its own column would be crossed by a band, and
   flanked by two hands, wider than the position they belong to. */
.tsume-board,
.tsume-board-col { max-width: 100%; }
.tsume-board-col {
    min-width: 0;
    /* A DEFINITE width, not just a cap.
     *
     * The board is `width: 100%` over `aspect-ratio: 1/1`, so it has no
     * intrinsic width of its own to give the grid track - which meant the
     * track sized itself from the widest thing that DID, and that turned out
     * to be the line of text above the board saying the defender holds the
     * rest of the set. The board was 288px because of a caption. Stating the
     * width here is what stops the layout being decided by a sentence. */
    width: 420px;
    /* Centred, because below the breakpoint the column is the page. */
    margin-left: auto;
    margin-right: auto;
}
.tsume-side-col {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
    /* STARTS WHERE THE BOARD STARTS.
       Without this the panel's first card lines up with the top komadai, a
       hand's height above the board it is about, and the two columns read as
       two unrelated stacks. 44px of komadai plus its 6px margins is exactly
       what sits above the board in the other column - and the komadai's
       height is fixed in both of its states for this reason as much as for
       keeping the board still between problems. */
    padding-top: 56px;
}

/* Both komadai. The floor is a whole hand piece rather than .study-hand's
   30px because here pieces arrive in hand mid-solve: a row that grows
   from nothing to 42px moves the board out from under the pointer
   between one move and the next. */
.tsume-hand {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-items: center;
    min-height: 44px;
    margin: 6px 0;
}
/* The top komadai is the defender's - a readout, not a control. The hand
   piece is a <button> and took a pointer cursor from the editor whose
   renderer draws it, which is a promise this side of the board cannot
   keep. */
.tsume-hand[data-tsume-hand="top"] .play-hand-piece { cursor: default; }

/* ---- The panel beside the board ---- */
/* THE BRIEF, as a card rather than as a sentence.

   It used to be one line that rewrote itself after every move - "Sente to
   play and mate in 3", then "...in 1" - so the loudest thing on the page kept
   changing its wording and still never showed how far in you were. Here the
   length is a figure that stays put for the whole problem, and the row of
   marks on the right is the part that moves: one per check the problem needs,
   lit as they are found.

   The tone follows the outcome, because this card is also where the problem
   ends: green when it is solved, grey when the answer was handed over. */
.tsume-goal {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border: 1px solid var(--c-border-soft, rgba(127, 127, 127, 0.2));
    border-radius: var(--radius-md, 12px);
    background: var(--c-box-alt);
}
/* The outcome is carried by the kanji and by the marks beside it, which are
   the two things already in the card. A coloured edge as well was a third
   voice saying the same word. */
.tsume-goal-mark {
    flex: 0 0 auto;
    font-family: var(--font-kanji);
    font-size: 1.9rem;
    line-height: 1;
    color: var(--badge-tsume-fg);
    opacity: 0.8;
}
.tsume-goal.is-solved .tsume-goal-mark { color: var(--c-good); opacity: 1; }
/* Handed over rather than found: neutral, because this is not an achievement
   and the card should not congratulate anybody for pressing the button. */
.tsume-goal.is-shown .tsume-goal-mark { color: var(--c-font-dim); }
.tsume-goal-text { min-width: 0; flex: 1 1 auto; }
.tsume-goal-title {
    margin: 0;
    color: var(--c-font-strong);
    font-size: 1.15rem;
    font-weight: 600;
    line-height: 1.25;
}
.tsume-goal-sub {
    margin: 2px 0 0;
    font-size: 0.8rem;
    line-height: 1.35;
    color: var(--c-font-dim);
}

/* One mark per check the problem needs. Vertical, because the card is a row
   and a second row inside it would make the panel taller than the brief is
   worth; five is the most a nine-ply problem can ask for. */
.tsume-goal-dots {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 5px;
    cursor: help;
}
.tsume-goal-dots:empty { display: none; }
.tsume-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    /* Solid rather than an outline. A ring at 10px in --c-border was invisible
       against --c-box-alt, so a meter showing "none of three found" showed
       nothing at all. */
    border: none;
    background: var(--c-border);
    transition: background-color 0.2s ease;
}
.tsume-dot.is-on { background: var(--c-accent); }
.tsume-goal.is-solved .tsume-dot.is-on { background: var(--c-good); }
/* Only the mark that just landed animates. Popping the whole row on every
   redraw would turn a progress meter into a light show. */
.tsume-dot.is-fresh { animation: tsume-dot-pop 0.34s cubic-bezier(0.2, 1.6, 0.4, 1) both; }
@keyframes tsume-dot-pop {
    0%   { transform: scale(0.2); }
    60%  { transform: scale(1.45); }
    100% { transform: scale(1); }
}
/* The verdict on the move just played. Its line is held even while empty:
   this is the moment the reader is looking at the board, and a panel that
   grows a row here shifts everything under it. */
.tsume-status {
    margin: 0;
    min-height: 1.3em;
    font-size: 0.86rem;
    color: var(--c-font-dim);
}
.tsume-status.is-error { color: var(--c-bad); }
.tsume-status.is-good { color: var(--c-good); font-weight: 600; }

/* Shown only for problems mined out of a real game. */
.tsume-origin {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
/* The row is hidden by attribute between problems, and the display above
   would otherwise beat the UA rule that honours `hidden`. */
.tsume-origin[hidden] { display: none; }
/* Toned rather than grey: "somebody here had this and did not see it" is
   the reason these problems exist, and the chip is what says so. */
.tsume-origin-chip {
    background-color: var(--c-accent-soft);
    color: var(--c-accent-on-soft);
}
.tsume-origin-link { color: var(--c-font-dim); font-size: 0.84em; }
.tsume-origin-link:hover { color: var(--c-accent); }
/* The problem's own grade. Quiet on purpose: it is context for the position,
   not a claim about the reader, and the two numbers on this page must not be
   mistaken for each other. */
.tsume-grade-chip { color: var(--c-font-dim); cursor: help; }

/* The line as it was played, both sides. */
.tsume-moves {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}
/* Empty until the first move of every problem, and the panel's own gap
   would hold a 10px hole open under the status line while it is. */
.tsume-moves:empty { display: none; }
.tsume-move {
    box-sizing: border-box;
    padding: 3px 8px;
    border-radius: var(--radius-sm);
    background-color: var(--c-box-alt);
    color: var(--c-font-dim);
    font-family: var(--font-mono);
    font-size: 0.78rem;
    line-height: 1.5;
}
/* Attack and defence alternate, and they are read differently: yours is
   the line you are building, the replies are what it has to beat. The
   tonal fill is the one the site marks a current thing with everywhere
   else, so the trail reads as yours-theirs without a legend. */
.tsume-move.is-mine {
    background-color: var(--c-accent-soft);
    color: var(--c-accent-on-soft);
    font-weight: 600;
}

.tsume-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 2px;
}
.tsume-actions .home-cta { cursor: pointer; }

/* Inserted between the board and the bottom komadai, in the flow rather
   than over the board: the position is exactly what is being read at the
   moment the question is asked. Same treatment as .study-promotion. */
.tsume-promotion {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
}
.tsume-promotion p { margin: 0; font-size: 0.88rem; }
.tsume-promotion .home-cta { cursor: pointer; }

/* ---- The square the defence got out to ----
   `lastTo` already tints it the way any move's destination is tinted, and
   that is exactly the problem: the one square on the board that the solver
   has to look at was drawn like every other. The ring keeps going for as
   long as the retry screen is up, which is the whole time it is being
   talked about. Drawn on ::before because .play-cell-legal owns ::after. */
.tsume-cell-out::before {
    content: '';
    position: absolute;
    inset: 6%;
    border: 2.5px solid #ef4444;
    border-radius: 50%;
    pointer-events: none;
    z-index: 2;
    animation: tsume-out-pulse 1.15s ease-in-out infinite;
}
body.dark-mode .tsume-cell-out::before { border-color: #f87171; }
@keyframes tsume-out-pulse {
    0%, 100% { transform: scale(1);    opacity: 0.95; }
    50%      { transform: scale(1.12); opacity: 0.5; }
}

/* ---- The screen over the board ----
   The retry screen and the win screen are one component with three tones, on
   purpose: a solve and a miss are the same moment of a trainer - here is what
   your move did - and celebrating in one place while scolding somewhere else
   would make the miss read as a different and worse kind of event than it is.

   It borrows its look from board-fx's announcement bands, which is what the
   match room uses to say a game ended, so the trainer and the game announce
   things in one voice. It is NOT part of board-fx: those bands are decoration
   a reader can switch off, and this one carries the way back to the board. */
.tsume-verdict {
    position: absolute;
    inset: 0;
    z-index: 8;
    display: flex;
    /* ANCHORED AT THE BOTTOM, and this is the whole point of the screen.
       A composed tsume is set in the top corner of the board, so that is
       where the king just walked out to and where the ring is pulsing - and
       a card centred over the board covers exactly the squares it is talking
       about. Sitting on the floor of the board it explains the position
       instead of hiding it, which is also how a game puts a result panel up. */
    align-items: flex-end;
    justify-content: center;
    padding: 8px;
    /* A flat wash, and a light one. The panel keeps off the half of the board
       the move happened on, so the position does not also need to be dimmed
       to make the panel readable - it only needs to stop competing. */
    background: rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: opacity 0.22s ease;
}
.tsume-verdict.is-in { opacity: 1; }
/* The other end, for a problem whose action is at the bottom of the board -
   which is every problem mined out of a real game where Gote had the mate. */
.tsume-verdict.is-top { align-items: flex-start; }
.tsume-verdict.is-top .tsume-verdict-card { transform: translateY(-16px); }
.tsume-verdict.is-top.is-in .tsume-verdict-card { transform: none; }

.tsume-verdict-card {
    width: 100%;
    max-width: 380px;
    padding: 12px 16px 14px;
    text-align: center;
    color: #fff;
    border-radius: var(--radius-md, 12px);
    box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
    transform: translateY(16px);
    opacity: 0;
    transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.24s ease;
}
.tsume-verdict.is-in .tsume-verdict-card { transform: none; opacity: 1; }

/* Kanji and headline on one line. Stacked they made the panel tall enough to
   reach back over the position it is a verdict on. */
.tsume-verdict-head {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

/* Flat, in the three colours the mate bands are built out of, so the colour
   says the same thing here as it does at the end of a game. The bands sweep
   and can afford a gradient; this one sits still, and a still panel with a
   gradient across it is just a panel somebody could not leave alone. */
.tsume-verdict-retry .tsume-verdict-card { background: #991b1b; }
.tsume-verdict-win   .tsume-verdict-card { background: #15803d; }
.tsume-verdict-shown .tsume-verdict-card { background: #3f4652; }

.tsume-verdict-kanji {
    flex: 0 0 auto;
    font-family: var(--font-kanji);
    font-size: clamp(1.7rem, 7vw, 2.1rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.06em;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
    /* Lands a beat after the panel, which is what gives it the punch. */
    animation: tsume-verdict-pop 0.42s cubic-bezier(0.2, 1.6, 0.4, 1) 0.1s both;
}
.tsume-verdict-title {
    margin: 0;
    font-size: clamp(1rem, 4.2vw, 1.2rem);
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.01em;
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}
.tsume-verdict-note {
    margin: 7px 0 0;
    font-size: 0.85rem;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.9);
}
/* Bookkeeping - "this one was a repeat" - under the card rather than instead
   of it, and quiet enough that it never outranks the result it is a footnote
   to. */
.tsume-verdict-foot {
    margin: 8px 0 0;
    font-size: 0.74rem;
    line-height: 1.35;
    color: rgba(255, 255, 255, 0.65);
}

/* The one or two numbers that actually moved on this solve. Anything that did
   not move is left off entirely rather than shown at zero: this card exists
   to say what just happened. */
.tsume-verdict-tags {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    margin-top: 12px;
}
.tsume-verdict-tag {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    min-width: 66px;
    padding: 6px 10px;
    border-radius: var(--radius-sm, 8px);
    background: rgba(255, 255, 255, 0.14);
}
.tsume-verdict-tag strong {
    font-size: 1.05rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}
.tsume-verdict-tag span {
    font-size: 0.68rem;
    letter-spacing: 0.02em;
    color: rgba(255, 255, 255, 0.82);
}

.tsume-verdict-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    margin-top: 12px;
}
/* The site's buttons are themed against the page, and this panel is not the
   page - the outlined variant on a dark red gradient is unreadable. Restated
   against the panel, which is why these carry !important: the Theme layer
   sets .home-cta colours from body.dark-mode and at two classes plus an
   element it outranks anything written here without it.

   The secondary fill is DARK rather than a white wash: the win gradient ends
   in gold, and a translucent white button on gold is a button nobody can
   read. Dark holds against all three tones. */
.tsume-verdict .home-cta {
    cursor: pointer;
    border-color: rgba(255, 255, 255, 0.5) !important;
    background-color: rgba(0, 0, 0, 0.28) !important;
    color: #fff !important;
}
.tsume-verdict .home-cta:hover {
    border-color: #fff !important;
    background-color: rgba(0, 0, 0, 0.42) !important;
}
.tsume-verdict .home-cta-primary {
    border-color: #fff !important;
    background-color: #fff !important;
    color: #1a1a1a !important;
}
.tsume-verdict .home-cta-primary:hover {
    background-color: rgba(255, 255, 255, 0.88) !important;
    color: #1a1a1a !important;
}

/* pieces.js autolinks piece names anywhere on the page, and this panel is on
   its skip list - a screen whose only way out is one button must not contain
   a link that navigates off it. Restated here so a link that ever does slip
   in is at least readable rather than dark red on dark red. */
.tsume-verdict .piece-link,
.tsume-verdict .wiki-link {
    color: inherit !important;
    border-bottom-color: rgba(255, 255, 255, 0.5);
}

@keyframes tsume-verdict-pop {
    from { transform: scale(0.4); opacity: 0; }
    to   { transform: scale(1);   opacity: 1; }
}

/* Someone who has asked for less motion still gets the screen and still gets
   the ring: they are the explanation, not the decoration. */
@media (prefers-reduced-motion: reduce) {
    .tsume-verdict,
    .tsume-verdict-card { transition: none; }
    .tsume-verdict-card,
    .tsume-verdict.is-top .tsume-verdict-card { transform: none; }
    .tsume-verdict-kanji,
    .tsume-dot.is-fresh { animation: none; }
    .tsume-cell-out::before { animation: none; opacity: 0.95; }
}

/* ---- The ladder ---- */
.tsume-ranking { padding-top: 4px; }
/* The place takes the glyph slot, which is 52px wide and set in the
   mincho face so that 成銀 and 王/玉 line up under each other. A number
   of at most three digits needs neither, and a "1" alone in that column
   left the names of the whole list marooned. */
.pieces-index-card.tsume-rank-row > .tsume-place {
    width: 34px;
    margin-right: 12px;
}
.tsume-place {
    font-family: var(--font-ui);
    font-size: 1.05em;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--c-font-dim);
    opacity: 1;
}
/* Every row carries a rating, one under the other. */
.tsume-rank-row .wiki-tag-chip { font-variant-numeric: tabular-nums; }

@media (max-width: 900px) {
    /* The shared list in the mobile layer names these two as well, but
       this block is appended after that layer and would win the tie on
       order alone. Restated here so the page is not flush against the
       edge of a phone. */
    .tsume-lengths,
    .tsume-layout { padding-left: 16px; padding-right: 16px; }
    /* One column, board first - which is the source order already, and the
       panel follows the board rather than sitting beside it, so the offset
       that lined the two up goes away. */
    .tsume-layout { grid-template-columns: minmax(0, 1fr); }
    .tsume-side-col { padding-top: 0; }
}

/* ===================== The wiki, beyond one article ===================== */

/* --- Heading anchors -------------------------------------------------- */
/* The anchor is furniture, not content: it appears when the heading is
   pointed at, and never in a copied selection of the title. */
.wiki-anchor {
    margin-left: 8px;
    font-size: 0.7em;
    color: var(--c-font-dim);
    text-decoration: none;
    opacity: 0;
    transition: opacity 0.12s ease;
}
.wiki-body-rendered h1:hover .wiki-anchor,
.wiki-body-rendered h2:hover .wiki-anchor,
.wiki-body-rendered h3:hover .wiki-anchor,
.wiki-body-rendered h4:hover .wiki-anchor,
.wiki-anchor:focus-visible { opacity: 1; }
/* An anchored jump must not land under a sticky header or flush with the top. */
.wiki-body-rendered :is(h1, h2, h3, h4, h5, h6)[id] { scroll-margin-top: 20px; }

/* A link to a page nobody has written yet. Same convention every wiki uses,
   because it is the one readers already know. */
/* Beats .wiki-body-rendered a, which is where an article link gets its
   colour from - a single class would lose the tie and the link would look
   exactly like one that goes somewhere. */
.wiki-body-rendered a.wiki-link-new,
.wiki-comment-body a.wiki-link-new,
a.wiki-link-new,
body.dark-mode .wiki-body-rendered a.wiki-link-new,
body.dark-mode a.wiki-link-new {
    color: var(--c-bad);
    border-bottom: 1px dotted currentColor;
}

/* --- Tables ----------------------------------------------------------- */
.wiki-table-wrap {
    max-width: var(--prose);
    margin: 18px auto;
    overflow-x: auto;
}
.wiki-table {
    border-collapse: collapse;
    width: 100%;
    font-size: 0.95em;
}
.wiki-table th,
.wiki-table td {
    border: 1px solid var(--c-border);
    padding: 8px 12px;
    text-align: left;
    vertical-align: top;
}
.wiki-table th {
    background-color: var(--c-box-alt);
    font-weight: 600;
    color: var(--c-font-strong);
}
.wiki-table tbody tr:nth-child(even) { background-color: var(--c-box-alt); }

.wiki-code {
    max-width: var(--prose);
    margin: 16px auto;
    padding: 12px 14px;
    overflow-x: auto;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background-color: var(--c-box-alt);
    font-family: var(--font-mono);
    font-size: 0.85em;
    line-height: 1.5;
}

/* --- The move player -------------------------------------------------- */
.wiki-moves {
    max-width: var(--prose);
    margin: 22px auto;
}
.wiki-moves-fallback {
    margin: 0;
    padding-left: 22px;
    font-family: var(--font-mono);
    font-size: 0.85em;
    color: var(--c-font-dim);
}
.wiki-moves-live { outline: none; }
.wiki-moves-live:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 4px;
    border-radius: var(--radius-sm);
}
.wiki-moves-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    gap: 18px;
    align-items: start;
}
.wiki-moves-board-col { display: flex; flex-direction: column; gap: 6px; }
.wiki-moves-board { width: 100%; box-sizing: border-box; aspect-ratio: 1 / 1; }
.wiki-moves-board .play-cell { cursor: default; }
.wiki-moves-board .play-piece { font-size: clamp(0.65rem, 2.4vw, 1.2rem); }
/* The move that got here: where it came from, and where it landed. */
.wiki-moves-board .wiki-moves-from { background-color: rgba(255, 152, 0, 0.18); }
.wiki-moves-board .wiki-moves-to { background-color: rgba(255, 152, 0, 0.35); }

.wiki-moves-hand { display: flex; flex-wrap: wrap; gap: 4px; min-height: 0; }
.wiki-moves-hand-piece {
    padding: 1px 6px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    font-family: var(--font-kanji);
    font-size: 0.85em;
    color: var(--c-font-strong);
}
.wiki-moves-hand-gote { transform: rotate(180deg); }

.wiki-moves-controls { display: flex; align-items: center; gap: 6px; justify-content: center; }
.wiki-moves-btn {
    min-width: 34px;
    padding: 4px 8px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--c-font);
    font: inherit;
    cursor: pointer;
}
.wiki-moves-btn:hover:not(:disabled) { background-color: var(--c-hover); }
.wiki-moves-btn:disabled { opacity: 0.35; cursor: default; }
.wiki-moves-counter {
    min-width: 62px;
    text-align: center;
    font-size: 0.85em;
    font-variant-numeric: tabular-nums;
    color: var(--c-font-dim);
}
.wiki-moves-side { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.wiki-moves-comment {
    margin: 0;
    font-size: 0.9em;
    color: var(--c-font);
    min-height: 1.2em;
}
.wiki-moves-list {
    margin: 0;
    padding: 0;
    list-style: none;
    max-height: 260px;
    overflow-y: auto;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
}
.wiki-moves-item {
    display: flex;
    gap: 8px;
    align-items: baseline;
    padding: 5px 10px;
    cursor: pointer;
    font-size: 0.9em;
}
.wiki-moves-item:hover { background-color: var(--c-hover); }
.wiki-moves-item.is-current { background-color: var(--c-accent-soft); color: var(--c-accent-on-soft); }
.wiki-moves-num {
    min-width: 24px;
    text-align: right;
    color: var(--c-font-dim);
    font-variant-numeric: tabular-nums;
}
/* "歩76" is one token; breaking it after the kanji reads as two moves. */
.wiki-moves-label { font-family: var(--font-kanji); white-space: nowrap; flex: 0 0 auto; }
.wiki-moves-note { color: var(--c-font-dim); font-size: 0.9em; min-width: 0; }
.wiki-moves-broken { margin: 8px 0 0; font-size: 0.85em; color: var(--c-bad); }

@media (max-width: 720px) {
    .wiki-moves-layout { grid-template-columns: minmax(0, 1fr); }
    .wiki-moves-list { max-height: 180px; }
}

/* --- The editor preview ----------------------------------------------- */
.wiki-editor-preview {
    /* The grid gives this column a share of the width; the padding has to come
       out of that share rather than be added to it, or the preview hangs 18px
       past the editor and clips whatever is widest. */
    box-sizing: border-box;
    border-top: 1px solid var(--c-border);
    padding: 14px 0 4px;
    max-height: 460px;
    overflow-y: auto;
}
.inline-md-editor.has-preview { display: flex; flex-direction: column; }
/* The preview column is narrower than the article it is previewing, and
   everything the body can hold has to fit in it rather than run off the
   side - an image sized for the prose column is wider than this. */
.wiki-editor-preview img,
.wiki-editor-preview .wiki-figure,
.wiki-editor-preview .wiki-table-wrap,
.wiki-editor-preview .wiki-moves,
.wiki-editor-preview .wiki-code { max-width: 100%; }
.wiki-editor-preview img { height: auto; }
.wiki-editor-preview .wiki-moves-layout { grid-template-columns: minmax(0, 1fr); }
.wiki-tool-btn.active {
    background-color: var(--c-accent-soft);
    color: var(--c-accent-on-soft);
}
@media (min-width: 900px) {
    /* Wide enough for both at once: the toolbar spans the top, the text and
       the result sit side by side under it. */
    .inline-md-editor.has-preview {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 0 18px;
    }
    .inline-md-editor.has-preview > .wiki-editor-toolbar { grid-column: 1 / -1; }
    .inline-md-editor.has-preview > .wiki-editor-preview {
        border-top: none;
        border-left: 1px solid var(--c-border);
        padding: 0 0 0 18px;
        margin: 0;
    }
}

/* --- Diff -------------------------------------------------------------- */
.wiki-diff { margin: 10px 0; }
.wiki-diff-summary { margin: 0 0 8px; font-size: 0.85em; color: var(--c-font-dim); }
.wiki-diff-empty { margin: 0; font-size: 0.9em; color: var(--c-font-dim); }
.wiki-diff-body {
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    overflow-x: auto;
    font-family: var(--font-mono);
    font-size: 0.8rem;
    line-height: 1.5;
}
.wiki-diff-line { display: flex; gap: 0; white-space: pre-wrap; word-break: break-word; }
.wiki-diff-num {
    flex: 0 0 auto;
    width: 42px;
    padding: 0 6px;
    text-align: right;
    color: var(--c-font-dim);
    opacity: 0.7;
    user-select: none;
    font-variant-numeric: tabular-nums;
}
.wiki-diff-sign { flex: 0 0 auto; width: 18px; text-align: center; user-select: none; }
.wiki-diff-text { flex: 1 1 auto; min-width: 0; padding-right: 8px; }
.wiki-diff-add { background-color: rgba(24, 128, 56, 0.14); }
.wiki-diff-del { background-color: rgba(217, 48, 37, 0.14); }
.wiki-diff-add .wiki-diff-sign { color: var(--c-good); }
.wiki-diff-del .wiki-diff-sign { color: var(--c-bad); }
.wiki-diff-gap {
    padding: 2px 8px;
    background-color: var(--c-box-alt);
    color: var(--c-font-dim);
    font-size: 0.9em;
    text-align: center;
}
.review-detail-diff { margin: 18px 0; }
.review-detail-diff-title {
    cursor: pointer;
    font-size: 0.8em;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}

/* --- The panels under an article -------------------------------------- */
.wiki-meta-panels {
    max-width: var(--prose);
    margin: 26px auto 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.wiki-panel {
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background-color: var(--c-box);
}
.wiki-panel-summary {
    cursor: pointer;
    padding: 9px 14px;
    font-size: 0.8em;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--c-font-dim);
    display: flex;
    align-items: center;
    gap: 8px;
}
.wiki-panel[open] > .wiki-panel-summary { border-bottom: 1px solid var(--c-border); }
.wiki-panel-count {
    padding: 0 7px;
    border-radius: var(--radius-pill);
    background-color: var(--c-box-alt);
    font-variant-numeric: tabular-nums;
}
.wiki-panel-count:empty { display: none; }
.wiki-panel-body { padding: 12px 14px; }
.wiki-panel-hint,
.wiki-panel-empty,
.wiki-panel-loading { margin: 0 0 8px; font-size: 0.85em; color: var(--c-font-dim); }
.wiki-panel-links { margin: 0; padding-left: 20px; }
.wiki-panel-links li { margin: 3px 0; }
.wiki-panel-actions { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.wiki-panel-status { flex: 1 1 auto; font-size: 0.85em; color: var(--c-font-dim); }

.wiki-history-rows { margin: 0; padding: 0; list-style: none; }
.wiki-history-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 0;
    border-top: 1px solid var(--c-border-soft);
}
.wiki-history-row:first-child { border-top: none; }
.wiki-history-row.is-picked { background-color: var(--c-accent-soft); }
.wiki-history-pick { flex: 0 0 auto; }
.wiki-history-main { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.wiki-history-when { font-size: 0.9em; color: var(--c-font-strong); }
.wiki-history-meta { font-size: 0.8em; color: var(--c-font-dim); }
.wiki-history-restore {
    flex: 0 0 auto;
    padding: 4px 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--c-font);
    font: inherit;
    font-size: 0.8em;
    cursor: pointer;
}
.wiki-history-restore:hover:not(:disabled) { background-color: var(--c-hover); }
.wiki-history-diff { margin-top: 12px; }
.wiki-history-diff-head { margin: 0 0 6px; font-size: 0.85em; color: var(--c-font-dim); }

/* The history and the names are dialogs opened from the toolbar now, beside
   the castle and opening editors this page already opens that way. */
.wiki-history-dialog { width: min(720px, 100%); }
.wiki-aliases-dialog { width: min(520px, 100%); }
.wiki-meta-modal .modal-body { gap: 10px; }
.wiki-meta-modal .modal-footer { align-items: center; }
.wiki-meta-modal .wiki-panel-status { flex: 1 1 auto; text-align: left; }

/* --- Games that reached this shape ------------------------------------ */
.wiki-matches { max-width: var(--prose); margin: 26px auto 0; }
/* The shared section title carries the padding the wide pages want; here it
   would leave the heading indented from its own list. */
.wiki-matches .pieces-section-title { padding-left: 0; margin-left: 0; }
.wiki-matches-count { margin: 0 0 10px; font-size: 0.9em; color: var(--c-font-dim); }
.wiki-matches-list { display: flex; flex-direction: column; gap: 4px; }
.wiki-match-row {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 8px 12px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    color: var(--c-font);
    text-decoration: none;
}
.wiki-match-row:hover { background-color: var(--c-hover); }
.wiki-match-players { flex: 1 1 auto; min-width: 0; }
.wiki-match-at,
.wiki-match-when { flex: 0 0 auto; font-size: 0.82em; color: var(--c-font-dim); }

/* The castle and opening names in a game's move list are links now. */
.play-history-link { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.play-history-link:hover { color: var(--c-accent); }

/* --- Diagrams in posts ------------------------------------------------- */
.post-text-run { display: block; white-space: pre-wrap; }
.composer-action-diagram {
    border: none;
    background: transparent;
    color: inherit;
    cursor: pointer;
    padding: 0;
    display: inline-flex;
    align-items: center;
}
.forum-composer-tools { display: flex; gap: 8px; margin-top: 6px; }
.wiki-comment-tools { display: flex; gap: 8px; margin-right: auto; }
.wiki-comment-body { margin: 0; white-space: pre-wrap; }
.wiki-comment-body .wiki-diagram { margin: 12px 0; }

/* --- Importing a game record ------------------------------------------ */
/* A KIF is a column-aligned table; in a proportional font it stops looking
   like the thing the person copied. */
.kifu-import-dialog { max-width: 560px; width: 100%; }
.kifu-import-body { display: flex; flex-direction: column; gap: 12px; }
.kifu-import-hint { margin: 0; font-size: 0.85em; color: var(--c-font-dim); }
.kifu-import-input {
    font-family: var(--font-mono);
    font-size: 0.82rem;
    line-height: 1.5;
    resize: vertical;
    white-space: pre;
    overflow: auto;
}
.kifu-import-load { align-self: flex-start; margin-top: 8px; }

/* The builder: a board on the left, the line being built on the right. */
.kifu-import-dialog { max-width: 820px; width: 100%; }
.kifu-build-body { display: flex; flex-direction: column; gap: 10px; }
.kifu-build-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    gap: 18px;
    align-items: start;
}
.kifu-build-board-col { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.kifu-build-board {
    width: 100%;
    box-sizing: border-box;
    aspect-ratio: 1 / 1;
    grid-template-columns: repeat(9, 1fr);
    grid-template-rows: repeat(9, 1fr);
}
.kifu-build-board .play-cell { cursor: pointer; }
.kifu-build-board .play-piece { font-size: clamp(0.6rem, 2vw, 1.05rem); }
/* The piece you picked up, and where the rules let it go. */
.kifu-build-board .is-selected { background-color: rgba(255, 152, 0, 0.4); }
.kifu-build-board .is-target::after {
    content: "";
    display: block;
    width: 26%;
    height: 26%;
    border-radius: 50%;
    background-color: rgba(0, 0, 0, 0.35);
}
body.dark-mode .kifu-build-board .is-target::after { background-color: rgba(255, 255, 255, 0.4); }
.kifu-build-hand { display: flex; flex-wrap: wrap; gap: 4px; min-height: 0; }
.kifu-build-hand-piece {
    padding: 2px 7px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--c-font-strong);
    font-family: var(--font-kanji);
    font-size: 0.85em;
    cursor: pointer;
}
.kifu-build-hand-piece:disabled { opacity: 0.4; cursor: default; }
.kifu-build-hand-piece.is-selected { border-color: var(--c-accent); box-shadow: 0 0 0 1px var(--c-accent); }
.kifu-build-turn { margin: 0; font-size: 0.82em; color: var(--c-font-dim); text-align: center; }
.kifu-build-controls { display: flex; gap: 6px; justify-content: center; }
/* Asked where the move landed, not in a dialog on top of a dialog. */
.kifu-build-promote {
    display: flex;
    gap: 6px;
    justify-content: center;
    padding: 6px;
    border: 1px solid var(--c-accent);
    border-radius: var(--radius-sm);
}

.kifu-build-side { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.kifu-build-hint { margin: 0; font-size: 0.82em; color: var(--c-font-dim); }
.kifu-build-list {
    margin: 0;
    padding: 0;
    list-style: none;
    min-height: 120px;
    max-height: 240px;
    overflow-y: auto;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
}
.kifu-build-item {
    display: flex;
    gap: 8px;
    align-items: baseline;
    padding: 5px 10px;
    font-size: 0.9em;
    cursor: pointer;
}
.kifu-build-item:hover { background-color: var(--c-hover); }
.kifu-build-item.is-current { background-color: var(--c-accent-soft); color: var(--c-accent-on-soft); }
.kifu-build-comment-label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.78em;
    color: var(--c-font-dim);
}
.kifu-build-comment { font-size: 0.9em; }
.kifu-build-paste > summary {
    cursor: pointer;
    font-size: 0.8em;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.kifu-build-paste[open] { display: flex; flex-direction: column; gap: 8px; }

@media (max-width: 760px) {
    .kifu-build-layout { grid-template-columns: minmax(0, 1fr); }
}

.kifu-import-status { margin: 0; min-height: 1.2em; font-size: 0.85em; color: var(--c-font-dim); }
.kifu-import-status.is-bad { color: var(--c-bad); }
.kifu-import [data-kif-insert]:disabled { opacity: 0.45; cursor: default; }

/* --- Site search ------------------------------------------------------- */
.sidebar-search {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    margin-bottom: 6px;
    padding: 8px 12px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--c-font-dim);
    font: inherit;
    font-size: 0.9em;
    cursor: pointer;
    text-align: left;
}
.sidebar-search:hover { background-color: var(--c-hover); color: var(--c-font-strong); }
.sidebar-search-label { flex: 1 1 auto; }
.sidebar-search-key {
    flex: 0 0 auto;
    font-size: 0.75em;
    padding: 1px 6px;
    border: 1px solid var(--c-border);
    border-radius: 4px;
    opacity: 0.8;
}

/* The command palette. It is a dialog rather than a field in the rail
   because the results need room the rail does not have - so the dialog has
   to look like somewhere you type, not like a box that appeared. */
.site-search { align-items: flex-start; padding-top: 11vh; }
.site-search .modal-backdrop { background-color: rgba(0, 0, 0, 0.55); }
.site-search-dialog {
    width: min(640px, 100%);
    max-height: min(72vh, 660px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.45);
}
.site-search-field {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 15px 18px;
    border-bottom: 1px solid var(--c-border);
    color: var(--c-font-dim);
}
.site-search-input {
    flex: 1 1 auto;
    min-width: 0;
    border: none;
    outline: none;
    background: transparent;
    color: var(--c-font-strong);
    font: inherit;
    font-size: 1.1em;
}
.site-search-input::placeholder { color: var(--c-font-dim); opacity: 0.75; }
.site-search-input::-webkit-search-cancel-button { display: none; }
.site-search-esc {
    flex: 0 0 auto;
    padding: 3px 8px;
    border: 1px solid var(--c-border);
    border-radius: 5px;
    background: transparent;
    color: var(--c-font-dim);
    font: inherit;
    font-size: 0.72em;
    cursor: pointer;
}
.site-search-esc:hover { background-color: var(--c-hover); color: var(--c-font-strong); }

.site-search-results { overflow-y: auto; padding: 6px; }
.site-search-group {
    padding: 10px 12px 4px;
    font-size: 0.7em;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--c-font-dim);
}
.site-search-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 12px;
    border-radius: var(--radius-sm);
    color: var(--c-font);
    text-decoration: none;
}
.site-search-item.is-active { background-color: var(--c-accent-soft); color: var(--c-accent-on-soft); }
/* The kind, as the same kanji the rest of the site marks it with. */
.site-search-item-glyph {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    font-family: var(--font-kanji);
    font-size: 0.9rem;
    background-color: var(--c-box-alt);
    color: var(--c-font-dim);
}
.site-search-item-glyph.wiki-cat-piece    { background-color: var(--tone-pieces-bg);   color: var(--tone-pieces-fg); }
.site-search-item-glyph.wiki-cat-castles  { background-color: var(--tone-castles-bg);  color: var(--tone-castles-fg); }
.site-search-item-glyph.wiki-cat-openings { background-color: var(--tone-openings-bg); color: var(--tone-openings-fg); }
.site-search-item-glyph.wiki-cat-culture  { background-color: var(--tone-culture-bg);  color: var(--tone-culture-fg); }
.site-search-item-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.site-search-item-title { font-size: 0.95em; color: var(--c-font-strong); }
.site-search-item.is-active .site-search-item-title { color: inherit; }
.site-search-item-title mark {
    background: transparent;
    color: var(--c-accent);
    font-weight: 600;
}
.site-search-item.is-active .site-search-item-title mark { color: inherit; text-decoration: underline; }
.site-search-item-sub {
    font-size: 0.8em;
    color: var(--c-font-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.site-search-item.is-active .site-search-item-sub { color: inherit; opacity: 0.75; }
/* Only the row you would open shows the key that opens it. */
.site-search-item-enter { flex: 0 0 auto; opacity: 0; font-size: 0.85em; }
.site-search-item.is-active .site-search-item-enter { opacity: 0.8; }

.site-search-status { margin: 0; padding: 22px 18px; font-size: 0.88em; color: var(--c-font-dim); text-align: center; }
.site-search-foot {
    display: flex;
    gap: 16px;
    padding: 9px 18px;
    border-top: 1px solid var(--c-border);
    font-size: 0.74em;
    color: var(--c-font-dim);
}
.site-search-foot kbd {
    display: inline-block;
    min-width: 16px;
    margin-right: 3px;
    padding: 1px 4px;
    border: 1px solid var(--c-border);
    border-radius: 4px;
    font-family: inherit;
    font-size: 0.95em;
    text-align: center;
}
body.has-search-open { overflow: hidden; }

/* --- Activity ---------------------------------------------------------- */
.activity-intro { margin: 0 16px 16px; color: var(--c-font-dim); }
/* The filter row is the shared pill control (.tsume-lengths + .tsume-length);
   only the page gutter is set here. */
.activity-filters { padding: 10px 16px 6px; margin-bottom: 8px; }
.activity-list { margin: 0; padding: 0 0 40px; list-style: none; }
.activity-item {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 10px 0;
    border-top: 1px solid var(--c-border-soft);
}
.activity-item:first-child { border-top: none; }
.activity-glyph {
    flex: 0 0 auto;
    width: 26px;
    text-align: center;
    font-family: var(--font-kanji);
    color: var(--c-font-dim);
}
.activity-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.activity-title { color: var(--c-font-strong); text-decoration: none; }
.activity-title:hover { text-decoration: underline; }
.activity-meta { font-size: 0.8em; color: var(--c-font-dim); }
.activity-when {
    flex: 0 0 auto;
    font-size: 0.8em;
    color: var(--c-font-dim);
    white-space: nowrap;
}
.activity-empty { padding: 20px 0; color: var(--c-font-dim); }

/* --- Wiki upkeep ------------------------------------------------------- */
/* The page keeps the same 16px gutter the rest of the site uses, so the
   headings, the hints and the rows all start on one line - which the first
   version did not, and it read as three separate broken pages. */
.wiki-maint { padding: 0 16px 40px; }
.wiki-maint-intro {
    margin: 16px 0 20px;
    max-width: 62ch;
    color: var(--c-font-dim);
}

/* The three numbers first: the page exists to answer "where is the wiki
   thin", and a count answers that before any list does. */
.wiki-maint-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
    margin-bottom: 34px;
}
.wiki-maint-stat {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 16px 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-md);
    color: var(--c-font);
    text-decoration: none;
    transition: border-color 0.12s ease, background-color 0.12s ease;
}
.wiki-maint-stat:hover { border-color: var(--c-font-dim); background-color: var(--c-hover); }
.wiki-maint-stat-n {
    font-size: 1.7rem;
    font-weight: 600;
    line-height: 1.1;
    color: var(--c-font-strong);
    font-variant-numeric: tabular-nums;
}
.wiki-maint-stat-label {
    font-size: 0.78em;
    text-align: center;
    color: var(--c-font-dim);
}

/* --- The admin page -------------------------------------------------
   Built on the maintenance page's tiles and sections; what it adds is a
   row of bars for the sign-ups per day and a plain table. */
.admin-stats { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
.admin-stat { cursor: default; }
.admin-stat:hover { border-color: var(--c-border); background-color: transparent; }
.admin-stat-sub { font-size: 0.72em; color: var(--c-font-dim); }
.admin-bars { display: flex; flex-direction: column; gap: 3px; }
.admin-bar {
    display: grid;
    grid-template-columns: 6.5em minmax(0, 1fr) 2.5em;
    align-items: center;
    gap: 10px;
    font-size: 0.86em;
    font-variant-numeric: tabular-nums;
    color: var(--c-font-dim);
}
.admin-bar-track { display: block; height: 10px; border-radius: 5px; background: var(--c-box-alt); overflow: hidden; }
/* Spans, so they need saying: an inline fill has no width to be given. */
.admin-bar-fill { display: block; height: 100%; border-radius: 5px; background: var(--c-accent); min-width: 2px; }
.admin-bar-fill.is-zero { display: none; }
.admin-bar-n { text-align: right; color: var(--c-font-strong); font-weight: 600; }
.admin-bar-today .admin-bar-label { color: var(--c-font-strong); font-weight: 600; }
.admin-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px; }
.admin-table { width: 100%; border-collapse: collapse; font-size: 0.9em; }
.admin-table th, .admin-table td { padding: 7px 8px; text-align: left; border-bottom: 1px solid var(--c-border-soft); white-space: nowrap; }
.admin-table th { font-size: 0.78em; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--c-font-dim); }
.admin-table td.is-num { text-align: right; font-variant-numeric: tabular-nums; }
.admin-table a { color: var(--c-font-strong); text-decoration: none; }
.admin-table a:hover { text-decoration: underline; }
.admin-table-wrap { overflow-x: auto; }
.admin-row-actions { display: inline-flex; gap: 6px; }
.admin-btn {
    padding: 4px 12px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--c-font);
    font: inherit;
    font-size: 0.82em;
    cursor: pointer;
}
.admin-btn:hover { background: var(--c-hover); color: var(--c-font-strong); }
.admin-btn-danger { color: var(--c-bad); border-color: var(--c-bad); }
.admin-btn-danger:hover { background: var(--c-bad); color: #fff; }
.admin-btn[disabled] { opacity: 0.5; cursor: default; }
.admin-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 10px; }
.admin-input {
    flex: 1 1 160px;
    min-width: 0;
    padding: 7px 12px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    background: var(--c-box);
    color: var(--c-font-strong);
    font: inherit;
    font-size: 0.9em;
}
.admin-links { display: flex; flex-wrap: wrap; gap: 8px; }
.admin-links a {
    padding: 6px 14px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-pill);
    color: var(--c-font-strong);
    text-decoration: none;
    font-size: 0.9em;
}
.admin-links a:hover { background: var(--c-hover); }
.admin-status { font-size: 0.86em; color: var(--c-font-dim); margin: 6px 0 0; }
.admin-ok { color: var(--c-good); }
.admin-bad { color: var(--c-bad); }

.wiki-maint-section { margin-bottom: 34px; scroll-margin-top: 16px; }
.wiki-maint-title {
    margin: 0 0 4px;
    font-size: 0.95em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--c-font-strong);
}
.wiki-maint-hint {
    margin: 0 0 12px;
    max-width: 62ch;
    font-size: 0.85em;
    color: var(--c-font-dim);
}
.wiki-maint-list { display: flex; flex-direction: column; gap: 6px; }
.wiki-maint-loading { margin: 0; font-size: 0.9em; color: var(--c-font-dim); }

/* Nothing to do is a result, so it gets a box of its own rather than a bare
   sentence floating where a list was expected. */
.wiki-maint-empty {
    margin: 0;
    padding: 18px;
    border: 1px dashed var(--c-border);
    border-radius: var(--radius-md);
    text-align: center;
    font-size: 0.88em;
    color: var(--c-font-dim);
}

.wiki-maint-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 14px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-md);
    color: inherit;
    text-decoration: none;
    transition: border-color 0.12s ease, background-color 0.12s ease;
}
.wiki-maint-item:hover { border-color: var(--c-font-dim); background-color: var(--c-hover); }
.wiki-maint-item-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.wiki-maint-item-title { color: var(--c-font-strong); font-weight: 500; }
.wiki-maint-item-note {
    font-size: 0.78em;
    color: var(--c-font-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wiki-maint-item-metric {
    flex: 0 0 auto;
    font-size: 0.78em;
    color: var(--c-font-dim);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.wiki-maint-item .wiki-cat-chip { flex: 0 0 auto; }

@media (max-width: 900px) {
    .wiki-meta-panels,
    .wiki-matches { padding-left: 16px; padding-right: 16px; }
    .site-search { padding-top: 6vh; }
    .sidebar-search-key { display: none; }

    /* The search, as one more item on the bottom bar.

       It has to be restyled HERE, in a block that comes after the desktop
       rule above, because `.sidebar-search { width: 100% }` is a rail rule:
       on a phone that one declaration turns into a full-width pill that
       shoves every icon off the bar. An earlier fix put the override in the
       first mobile block near the top of the file, where the desktop rule
       quietly won the cascade and nothing changed - which is exactly the
       bug this comment is here to stop happening a third time.

       The shape matches the other bar items: icon over a small label. */
    .leftdiv .sidebar-search {
        flex: 1 1 0;
        min-width: 0;
        width: auto;
        margin: 0;
        padding: 6px 2px;
        border: none;
        border-radius: var(--radius-md);
        background: none;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 4px;
        font-size: 0.7rem;
        font-weight: 500;
        line-height: 1.35;
        text-align: center;
        color: var(--c-font-dim);
    }
    .leftdiv .sidebar-search:hover,
    .leftdiv .sidebar-search:active { background-color: var(--c-hover); color: var(--c-font-dim); }
    .leftdiv .sidebar-search .nav-icon {
        flex: 0 0 22px;
        width: 22px;
        height: 22px;
        opacity: 1;
    }
    .leftdiv .sidebar-search-label {
        flex: 0 0 auto;
        display: block;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        padding-bottom: 1px;
    }
}

/* ======================================================================
   Handicap, TV, ranking, trainer, missions, clubs, weeklies, analysis

   THESE FOLLOW THE HOUSE RULES, which are worth writing down because the
   first draft of this block broke all four of them:

     1. NO BOXES. A list on this site is a flat column of rows with a
        hover tint - see .pieces-index-card, which explicitly sets
        `border: none`. Filled, bordered cards read as a different site.

     2. HIERARCHY COMES FROM OPACITY, not from colour. Secondary text is
        the same ink at 0.55-0.65; there is no grey scale and no tinted
        background to say "this is less important".

     3. CHIPS ARE TEXT. .wiki-tag-chip is a pill with a colour and no
        fill, so a filled chip anywhere else is out of place.

     4. SEPARATORS ARE HAIRLINES at 0.06 alpha, the value
        .pieces-index-popular already uses.

   Everything below reuses the existing tokens, and adds no colour that
   the palette does not already have.
   ====================================================================== */

/* ---- The odds ladder ---------------------------------------------------
   The page is the rules page in a different subject, so the hero, the section
   titles, the index rows and the prose all come from those. The only thing
   needed here is making an index row work as a <button>: the row starts a
   game, which is a POST, so it cannot be the <a> the other indexes use. */

.handicap-row {
    width: 100%;
    border: none;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.handicap-row.is-static { cursor: default; }

/* In the room header, beside the status. Text, not a filled badge. */
.play-handicap-chip,
.play-deadline-chip {
    font-size: 0.82em;
    opacity: 0.6;
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
}
.play-handicap-chip:hover { opacity: 1; }
.play-deadline-chip.is-soon { opacity: 1; color: var(--c-bad); }
.play-handicap-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0; }
.play-handicap-row .play-time-control-select { flex: 1 1 140px; }
.play-bot-field-link {
    margin-left: 8px;
    font-size: 0.82em;
    opacity: 0.55;
    color: inherit;
}
.play-bot-field-link:hover { opacity: 1; }

/* ---- The five opponents ---------------------------------------------- */

.play-bot-personas { flex-wrap: wrap; gap: 6px; }
.play-bot-persona .play-bot-level-face {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    padding: 8px 6px;
    min-width: 84px;
}
.play-bot-persona-face { display: block; border-radius: 8px; opacity: 0.85; }
.play-bot-persona input:checked + .play-bot-level-face .play-bot-persona-face { opacity: 1; }
.play-bot-persona-name { font-size: 0.9em; font-weight: 500; }
.play-bot-persona-style { font-size: 0.75em; opacity: 0.55; }
.play-bot-persona .play-bot-level-name {
    font-size: 0.7em;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    opacity: 0.45;
}
.play-bot-persona-blurb {
    margin: 8px 0 0;
    min-height: 2.6em;
    line-height: 1.5;
    font-size: 0.88em;
    opacity: 0.62;
}
/* /play/bot. The same fields the dialog had, at the dialog's width: a form
 * that spans the whole content column is a form nobody can scan. */
.play-bot-setup {
    max-width: 560px;
    /* The hero above carries the page's 24px at the sides; the form has to
       carry it too, or every field sits against the edge under a heading
       that does not. The section heading inside brings its own padding and
       gives it up here, so it lines up with the fields rather than being
       indented twice. */
    padding: 4px 24px 32px;
}
.play-bot-setup .pieces-section-title { padding-left: 0; padding-right: 0; }
/* The phone margin, here rather than in the shared block further up: this
   rule comes later in the file and its shorthand would win over it. */
@media (max-width: 900px) {
    .play-bot-setup { padding-left: 16px; padding-right: 16px; }
}
.play-bot-setup .play-bot-persona-blurb { margin-bottom: 18px; }
.play-bot-setup .play-bot-status { margin: 0 0 10px; }
.play-bot-setup .home-hero-actions { margin-top: 18px; }

/* ---- Shogi TV --------------------------------------------------------- */

.tv-header { padding: 34px 16px 18px; border-bottom: 1px solid rgba(0, 0, 0, 0.1); }
body.dark-mode .tv-header { border-bottom-color: rgba(255, 255, 255, 0.1); }
.tv-title { display: flex; align-items: center; gap: 9px; margin: 0; font-size: 2em; font-weight: bold; }
/* A small mark rather than a pulsing light: the page already says it is
   live, and a red beacon next to a heading is somebody else's design. */
.tv-dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.45;
}
.tv-sub { margin: 8px 0 0; font-size: 0.92em; opacity: 0.62; }

.tv-stage {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(220px, 300px);
    gap: 24px;
    align-items: start;
    padding: 18px 16px 32px;
}
.tv-screen { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.tv-board-wrap { position: relative; }
.tv-player { display: flex; align-items: center; gap: 9px; padding: 4px 2px; }
.tv-player .play-player-name { font-weight: 500; }
.tv-player .play-player-clock { margin-left: auto; font-family: var(--font-mono); opacity: 0.7; }
.tv-player .play-player-clock.is-low { opacity: 1; color: var(--c-bad); }
.tv-hand { min-height: 32px; display: flex; flex-wrap: wrap; gap: 6px; }
/* The komadai on the channel is a display, not a control. */
.play-hand-piece.is-static { cursor: default; }

.tv-result {
    position: absolute;
    left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    padding: 10px 20px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.72);
    color: #fff;
    font-size: 1em;
    pointer-events: none;
}

.tv-aside { display: flex; flex-direction: column; min-width: 0; }
.tv-aside-title {
    margin: 14px 0 6px;
    font-size: 0.95em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    opacity: 0.6;
}
.tv-aside-title:first-child { margin-top: 0; }
.tv-meta { display: flex; flex-wrap: wrap; gap: 12px; font-size: 0.82em; opacity: 0.6; }
.tv-meta a { color: inherit; }
.tv-meta a:hover { opacity: 1; }
.tv-moves {
    list-style: none;
    margin: 0; padding: 0;
    max-height: 250px;
    overflow-y: auto;
}
.tv-move { display: flex; gap: 10px; padding: 3px 0; font-size: 0.88em; }
.tv-move-num { min-width: 2.2em; text-align: right; opacity: 0.45; }
.tv-move-text { font-family: var(--font-kanji); }
.tv-queue { list-style: none; margin: 0; padding: 0; }
.tv-queue-link {
    display: flex; flex-direction: column; gap: 1px;
    padding: 8px 10px;
    margin: 0 -10px;
    border-radius: var(--radius-md);
    color: inherit;
    text-decoration: none;
}
.tv-queue-link:hover { background-color: var(--c-hover); }
.tv-queue-names { font-size: 0.9em; }
.tv-queue-meta { font-size: 0.8em; opacity: 0.5; }
.tv-queue-empty { font-size: 0.85em; opacity: 0.5; padding: 6px 0; }

.tv-offair { padding: 48px 16px; }
.tv-offair-text { max-width: 46ch; margin: 0; line-height: 1.5; opacity: 0.62; }
.tv-offair .home-hero-actions { margin-top: 18px; }

@media (max-width: 900px) {
    .tv-stage { grid-template-columns: minmax(0, 1fr); }
}

/* ---- Leaderboards ----------------------------------------------------- */

/* The board picker is the shared pill control; only the gutter is set here. */
.ranking-tabs { padding: 14px 16px 4px; }
.ranking-note {
    margin: 16px 16px 40px;
    max-width: 62ch;
    line-height: 1.5;
    font-size: 0.82em;
    opacity: 0.5;
}

.ranking-list { list-style: none; display: flex; flex-direction: column; margin: 8px 0 0; padding: 0 12px 8px; }
.ranking-row {
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 12px;
    padding: 9px 12px;
    border-radius: var(--radius-md);
}
.ranking-row + .ranking-row { border-top: 1px solid rgba(0, 0, 0, 0.06); }
body.dark-mode .ranking-row + .ranking-row { border-top-color: rgba(255, 255, 255, 0.08); }
.ranking-pos { text-align: right; font-variant-numeric: tabular-nums; opacity: 0.45; }
/* The top three are marked by weight alone. No metals: this site has one
   accent and it is the logo grey. */
.ranking-row.is-podium .ranking-pos { opacity: 0.9; font-weight: 600; }
.ranking-who {
    display: flex; align-items: center; gap: 10px;
    min-width: 0;
    color: inherit;
    text-decoration: none;
}
.ranking-who:hover .ranking-name { text-decoration: underline; text-underline-offset: 3px; }
.ranking-avatar { border-radius: 50%; flex: none; }
.ranking-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ranking-value { display: flex; align-items: baseline; gap: 6px; font-variant-numeric: tabular-nums; }
.ranking-grade { font-family: var(--font-kanji); font-size: 0.82em; opacity: 0.55; }
.ranking-sub { font-size: 0.82em; opacity: 0.5; white-space: nowrap; }
.ranking-empty { padding: 22px 12px; opacity: 0.55; font-size: 0.92em; }

@media (max-width: 640px) {
    .ranking-row { grid-template-columns: 26px minmax(0, 1fr) auto; }
    .ranking-sub { display: none; }
}

/* ---- Opening trainer ---------------------------------------------------
   The drill reuses the tsume layout wholesale, so the only rules here are
   the two things tsume has no equivalent for: the "no openings yet" panel
   and the link back to the article being drilled. */

.tsume-done { padding: 40px 16px; }
.tsume-done-text { max-width: 46ch; margin: 0; line-height: 1.5; opacity: 0.62; }
.tsume-done .home-hero-actions { margin-top: 18px; }

.trainer-article-link {
    display: inline-block;
    margin-top: 10px;
    font-size: 0.85em;
    opacity: 0.55;
    color: inherit;
}
.trainer-article-link:hover { opacity: 1; }

/* One neutral lead paragraph, used under a section title on any page. */
.section-lead {
    margin: 0 16px 10px;
    max-width: 56ch;
    font-size: 0.92em;
    opacity: 0.62;
}

/* ---- Daily missions ---------------------------------------------------- */

.mission-card { padding: 0 0 8px; }
/* .pieces-section-title carries the type; this only adds the counter on the
   right of it. */
.mission-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.mission-progress { font-variant-numeric: tabular-nums; text-transform: none; letter-spacing: 0; }
.mission-list { display: flex; flex-direction: column; padding: 0 12px; }
.mission-row {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    color: inherit;
    text-decoration: none;
    transition: background-color 0.12s ease;
}
.mission-row:hover { background-color: var(--c-hover); }
/* A tick, drawn as text, in the same ink as everything else. */
.mission-check {
    display: flex; align-items: center; justify-content: center;
    width: 16px; height: 16px;
    font-size: 0.8em;
    opacity: 0;
}
.mission-row.is-done .mission-check { opacity: 0.7; }
.mission-body { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.mission-text { font-size: 0.92em; }
.mission-row.is-done .mission-text { opacity: 0.5; }
.mission-bar {
    display: block;
    height: 2px;
    border-radius: 1px;
    background: rgba(0, 0, 0, 0.1);
    overflow: hidden;
}
body.dark-mode .mission-bar { background: rgba(255, 255, 255, 0.14); }
.mission-bar-fill {
    display: block;
    height: 100%;
    background: currentColor;
    opacity: 0.55;
    transition: width 0.3s ease;
}
.mission-count { font-size: 0.8em; opacity: 0.45; font-variant-numeric: tabular-nums; }
.mission-note { display: block; margin: 10px 24px 0; font-size: 0.82em; opacity: 0.5; color: inherit; }
.mission-note.is-done { opacity: 0.7; }

/* ---- Clubs -------------------------------------------------------------- */

.club-desc-input {
    width: 100%;
    margin-top: 10px;
    padding: 10px 12px;
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: var(--radius-sm);
    background: transparent;
    color: inherit;
    font: inherit;
    resize: vertical;
}
body.dark-mode .club-desc-input { border-color: rgba(255, 255, 255, 0.22); }
.club-roster { margin-bottom: 40px; }

/* ---- The weekly tournaments --------------------------------------------- */

.weekly-list { display: flex; flex-direction: column; padding: 0 12px 8px; }
.weekly-row {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1.2fr) auto auto;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    color: inherit;
    text-decoration: none;
}
.weekly-row + .weekly-row { border-top: 1px solid rgba(0, 0, 0, 0.06); }
body.dark-mode .weekly-row + .weekly-row { border-top-color: rgba(255, 255, 255, 0.08); }
a.weekly-row:hover { background-color: var(--c-hover); }
.weekly-name { font-size: 0.95em; }
.weekly-row.is-open .weekly-name { font-weight: 500; }
.weekly-when { font-size: 0.88em; opacity: 0.62; }
.weekly-tc, .weekly-state { font-size: 0.8em; opacity: 0.45; white-space: nowrap; }
.weekly-row.is-open .weekly-state { opacity: 0.75; }

@media (max-width: 640px) {
    .weekly-row { grid-template-columns: minmax(0, 1fr) auto; }
    .weekly-tc { display: none; }
}

/* ---- Correspondence: the boards waiting on you -------------------------- */

.play-turns-title { display: flex; align-items: baseline; gap: 8px; }
.play-turns-count { font-variant-numeric: tabular-nums; opacity: 0.5; }
.play-turn-deadline { font-size: 0.82em; opacity: 0.5; }
.play-turn-deadline.is-soon { opacity: 1; color: var(--c-bad); }

/* ---- The analytical profile ---------------------------------------------
 *
 * Cards in a grid, the box the rest of the site keeps things in, each with
 * the small uppercase title the shop and the appearance page use. The
 * charts keep their one-ink drawing; only the furniture round them is the
 * site's now. */
.profile-analysis { padding: 6px 24px 40px; }
/* The cards are appended to the inner box, so the grid lives there. */
[data-profile-analysis] { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
@media (max-width: 760px) { [data-profile-analysis] { grid-template-columns: minmax(0, 1fr); } }
.analysis-card {
    min-width: 0; padding: 16px 18px 18px; border-radius: 12px;
    border: 1px solid var(--c-border); background: var(--c-box);
}
.analysis-card.is-wide { grid-column: 1 / -1; }
.analysis-card-title { margin: 0 0 12px; font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--c-font-dim); }
.analysis-card-body { min-width: 0; }
.analysis-empty { grid-column: 1 / -1; margin: 0; font-size: 0.9rem; color: var(--c-font-dim); }
.analysis-card .analysis-empty { grid-column: auto; }
.analysis-hint { margin: 12px 0 0; max-width: 64ch; font-size: 0.84rem; line-height: 1.5; color: var(--c-font-dim); }

.analysis-chart { padding: 0; }
.analysis-spark { display: block; width: 100%; height: auto; }
/* One ink, at two opacities. currentColor means the chart follows the
   theme without a dark-mode rule of its own. */
.analysis-spark-area { fill: currentColor; opacity: 0.08; stroke: none; }
.analysis-spark-line { stroke: currentColor; stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round; opacity: 0.75; }
.analysis-spark-dot { fill: currentColor; opacity: 0.75; }
.analysis-chart-foot {
    display: flex; justify-content: space-between;
    padding-top: 6px; font-size: 0.78rem; color: var(--c-font-dim);
    font-variant-numeric: tabular-nums;
}
.analysis-chart-now { color: var(--c-font-strong); font-weight: 600; }

.analysis-headline { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; margin: 0 0 14px; font-size: 0.86rem; color: var(--c-font-dim); }
.analysis-headline strong { font-size: 2rem; font-weight: 700; line-height: 1; color: var(--c-font-strong); }
.analysis-phases { display: flex; flex-direction: column; gap: 10px; }
.analysis-phase {
    display: grid;
    grid-template-columns: 92px minmax(0, 1fr) 48px 72px;
    align-items: center;
    gap: 10px;
    font-size: 0.88rem;
}
.analysis-phase-name { color: var(--c-font); }
.analysis-phase-bar { height: 8px; border-radius: 999px; background: var(--c-box-alt); overflow: hidden; }
.analysis-phase-fill { display: block; height: 100%; border-radius: 999px; background: var(--c-accent); }
.analysis-phase-value { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
.analysis-phase-moves { text-align: right; font-size: 0.78rem; color: var(--c-font-dim); }
.analysis-verdict {
    margin: 14px 0 0; padding: 10px 12px;
    border-radius: 10px; background: var(--c-box-alt);
    font-size: 0.88rem; line-height: 1.5; color: var(--c-font);
}

.analysis-seats { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.analysis-seat { display: flex; flex-direction: column; gap: 2px; padding: 12px 14px; border-radius: 10px; background: var(--c-box-alt); }
.analysis-seat-name { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--c-font-dim); }
.analysis-seat-pct { font-size: 1.7rem; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--c-font-strong); }
.analysis-seat-games { font-size: 0.8rem; color: var(--c-font-dim); }

.analysis-openings { display: flex; flex-direction: column; }
.analysis-opening {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto 48px;
    align-items: center;
    gap: 12px;
    padding: 9px 8px;
    margin: 0 -8px;
    border-radius: 8px;
    color: inherit;
    text-decoration: none;
}
.analysis-opening + .analysis-opening { border-top: 1px solid var(--c-border-soft); }
.analysis-opening:hover { background-color: var(--c-hover); }
.analysis-opening-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.92rem; font-weight: 600; }
.analysis-opening-games { font-size: 0.8rem; color: var(--c-font-dim); }
.analysis-opening-pct { text-align: right; font-variant-numeric: tabular-nums; font-size: 0.92rem; font-weight: 600; }

/* The radar. Same ink as the sparkline: rings and axes are hairlines, the
   player's silhouette is the fill-and-line pair, and the labels take the
   seat-name style. currentColor throughout, so dark mode needs no rule. */
.analysis-radar-wrap { display: flex; align-items: center; gap: 28px; padding: 0; }
.analysis-radar { display: block; width: 340px; max-width: 100%; height: auto; flex: 0 0 auto; }
.analysis-radar-grid { fill: none; stroke: currentColor; stroke-width: 1; opacity: 0.12; }
.analysis-radar-axis { stroke: currentColor; stroke-width: 1; opacity: 0.12; }
.analysis-radar-area { fill: currentColor; opacity: 0.1; stroke: none; }
.analysis-radar-line { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linejoin: round; opacity: 0.75; }
.analysis-radar-dot { fill: currentColor; opacity: 0.75; }
.analysis-radar-dot.is-missing { opacity: 0.2; }
.analysis-radar-label {
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    fill: currentColor;
    opacity: 0.55;
}
.analysis-radar-label.is-missing { opacity: 0.25; }
.analysis-radar-legend {
    display: grid;
    grid-template-columns: auto auto;
    gap: 6px 18px;
    margin: 0;
    font-size: 0.88rem;
}
.analysis-radar-legend dt { color: var(--c-font-dim); }
.analysis-radar-legend dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.analysis-radar-legend dd.is-missing { opacity: 0.35; }
@media (max-width: 640px) {
    .analysis-radar-wrap { flex-direction: column; align-items: stretch; gap: 10px; }
    .analysis-radar { width: 100%; }
    .analysis-radar-legend { grid-template-columns: auto auto auto auto; }
}

@media (max-width: 640px) {
    .analysis-phase { grid-template-columns: 76px minmax(0, 1fr) 42px; }
    .analysis-phase-moves { display: none; }
}

/* A machine translation says so louder than a human one does. Not alarming,
   just visible: the reader is looking at text nobody on the project can
   proofread, and the tag is the only place that admits it. */
.wiki-translated-tag.is-machine { cursor: help; opacity: 0.75; }
.wiki-translated-tag.is-machine::before {
    content: '';
    display: inline-block;
    width: 5px;
    height: 5px;
    margin-right: 6px;
    border-radius: 50%;
    background: currentColor;
    vertical-align: middle;
    opacity: 0.6;
}

/* ---- Screen readers, keyboard, the bot's "why", rematch --------------- */

.sr-only {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    border: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
.play-cell:focus { outline: none; }
.play-cell:focus-visible {
    outline: 3px solid var(--c-accent, #c8102e);
    outline-offset: -3px;
    z-index: 3;
}
.play-player-why {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; padding: 0; margin-top: 2px;
    border-radius: 50%;
    border: 1px solid var(--c-border);
    background: var(--c-box);
    color: var(--c-font-strong, #222);
    font: 700 13px/1 var(--font-body, inherit);
    cursor: pointer;
    animation: board-fx-why 600ms ease-out;
}
.play-player-why:hover, .play-player-why:focus-visible { background: var(--c-accent, #c8102e); color: var(--c-on-accent); border-color: transparent; }
@keyframes board-fx-why { from { transform: scale(0.4); opacity: 0; } to { transform: none; opacity: 1; } }
.play-endcard-rematch { text-align: center; }
.play-endcard-offer .play-endcard-body { justify-content: center; }
.play-endcard-offer .play-endcard-name { font-size: 1rem; }

/* ---- The opening editor's KIF import ----------------------------------- */

.opening-editor-import {
    margin: 8px 0 2px;
    border: 1px dashed var(--c-border);
    border-radius: 6px;
    padding: 6px 10px;
}
.opening-editor-import[open] { padding-bottom: 10px; }
.opening-editor-import-summary { cursor: pointer; font-weight: 600; font-size: 0.92rem; }
.opening-editor-kif {
    width: 100%; box-sizing: border-box; resize: vertical;
    margin: 6px 0; padding: 6px 8px;
    border: 1px solid var(--c-border); border-radius: 4px;
    font: 0.82rem/1.35 var(--font-mono, ui-monospace, monospace);
    background: transparent; color: inherit;
}
.opening-editor-check { display: flex; align-items: center; gap: 8px; font-size: 0.9rem; margin: 4px 0 8px; }
.opening-editor-import-status { min-height: 1.2em; margin: 6px 0 0; }
.opening-editor-import-status.opening-status-error { color: var(--c-bad, #b91c1c); }

/* ---- Avatar frames -----------------------------------------------------
 *
 * A ring round the picture, earned or bought. The ring is a pseudo-element
 * on a wrapper (applyAvatarFrame in common.js wraps a bare <img>), which is
 * what lets a frame move: a conic gradient can turn, a glow can breathe, a
 * highlight can sweep. Always round, whatever the picture's own corners
 * were. Sized by two variables so the small avatars in lists get a thinner
 * ring than the one on a profile. */
.avatar-frame {
    --frame-w: 3px;
    --frame-gap: 4px;
    position: relative;
    display: inline-block;
    border-radius: 50%;
    line-height: 0;
    flex: none;
    /* Its own height, never the row's. In a flex row that stretches its
       items (a forum post, a reply) the wrapper was pulled to the height
       of the text beside it, the ring became a tall oval round a picture
       that stayed round, and the piece characters that orbit the koma
       frames swung across the author's name. */
    height: max-content;
    vertical-align: middle;
}
.avatar-frame > img, .avatar-frame > .profile-avatar, .avatar-frame > .play-endcard-avatar { border-radius: 50% !important; display: block; }
.avatar-frame-sm { --frame-w: 2px; --frame-gap: 2px; }
.avatar-frame::after {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap));
    border-radius: 50%;
    pointer-events: none;
    z-index: 2;
    border: var(--frame-w) solid var(--frame-a, transparent);
    box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b, transparent);
}
.avatar-frame-wood { --frame-a: #a0672a; --frame-b: #5b3413; }
.avatar-frame-silver { --frame-a: #d7dbe0; --frame-b: #8a929c; }
.avatar-frame-gold { --frame-a: #f2c14e; --frame-b: #a8771a; }
.avatar-frame-sakura { --frame-a: #f7b6c9; --frame-b: #d9557f; }
.avatar-frame-sumi { --frame-a: #1c1c1c; --frame-b: #7a7a7a; }
.avatar-frame-dragon { --frame-a: #c8102e; --frame-b: #f2c14e; }
.avatar-frame-founder { --frame-a: #111; --frame-b: #f2c14e; }
.avatar-frame-bronze { --frame-a: #b87333; --frame-b: #6e3f14; }
.avatar-frame-jade { --frame-a: #5fb59a; --frame-b: #1f6b52; }
.avatar-frame-indigo { --frame-a: #2b3a8f; --frame-b: #7c8be0; }
.avatar-frame-urushi { --frame-a: #7a0b0b; --frame-b: #111; }
.avatar-frame-kagerou { --frame-a: #e3a35a; --frame-b: #f7d9a8; }
.avatar-frame-ember { --frame-a: #ff7a1a; --frame-b: #ffb347; }
.avatar-frame-kinshine { --frame-a: #f2c14e; --frame-b: #fff3c4; }
.avatar-frame-hanafubuki { --frame-a: #f5a3bd; --frame-b: #fff0f5; }
.avatar-frame-aurora { --frame-a: #7ee8fa; --frame-b: #eec0c6; }
.avatar-frame-ryuranbu { --frame-a: #c8102e; --frame-b: #f2c14e; }
/* The second batch. The three stones are plain rings; obsidian and pearl
   take the founder's shine, moonlit night the haze, and the night blossom
   the petals, so they cost nothing new to draw. */
.avatar-frame-ruby { --frame-a: #d1264a; --frame-b: #7a0b21; }
.avatar-frame-sapphire { --frame-a: #2f6fdb; --frame-b: #123a7a; }
.avatar-frame-matcha { --frame-a: #7fb069; --frame-b: #3f6b2f; }
.avatar-frame-obsidian { --frame-a: #2a2a2e; --frame-b: #8d8d99; }
.avatar-frame-shinju { --frame-a: #f3eee6; --frame-b: #c9b8d8; }
.avatar-frame-tsukiyo { --frame-a: #3b4a8a; --frame-b: #dfe6ff; }
.avatar-frame-sakura-yoru { --frame-a: #e88fb0; --frame-b: #4a2a6a; }
/* The loud batch: eight rings that draw rather than tint. Each one owns a
   motion nothing else uses, so the price is a new keyframe apiece - which is
   the honest cost of a cosmetic somebody is meant to notice from across a
   thread. `--frame-spin` overrides the conic ring where one turns. */
.avatar-frame-kodou { --frame-a: #ff4d6d; --frame-b: #7a0b21; }
.avatar-frame-nami { --frame-a: #38bdf8; --frame-b: #0c4a6e; }
.avatar-frame-wakusei { --frame-a: #c4b5fd; --frame-b: #2e1065; }
.avatar-frame-uzu { --frame-a: #67e8f9; --frame-b: #0e7490; --frame-spin: conic-gradient(#0e7490, #22d3ee, #a5f3fc, #22d3ee, #0e7490); }
.avatar-frame-seiza { --frame-a: #dbe4ff; --frame-b: #1e1b4b; }
.avatar-frame-denkou { --frame-a: #ff2d95; --frame-b: #7df9ff; }
.avatar-frame-ryusei { --frame-a: #e0ecff; --frame-b: #1e3a8a; }
.avatar-frame-nanairo { --frame-a: #ff6b6b; --frame-b: #6bc5ff; --frame-spin: conic-gradient(#ff6b6b, #ffd166, #6bff95, #6bc5ff, #b56bff, #ff6b6b); }
/* The special-effects batch's colours. */
.avatar-frame-halo { --frame-a: #fde68a; --frame-b: #b45309; }
.avatar-frame-awa { --frame-a: #7dd3fc; --frame-b: #0369a1; }
.avatar-frame-hibana { --frame-a: #a5f3fc; --frame-b: #1d4ed8; }
.avatar-frame-gouka { --frame-a: #fb923c; --frame-b: #7f1d1d; }
.avatar-frame-suisei { --frame-a: #e0f2fe; --frame-b: #1e3a8a; --frame-spin: conic-gradient(rgba(30,58,138,0.35) 0 38%, rgba(191,219,254,0.45) 62%, rgba(224,242,254,0.85) 82%, #ffffff 93%, rgba(30,58,138,0.35) 100%); }
.avatar-frame-nisshoku { --frame-a: #fcd34d; --frame-b: #18181b; }
.avatar-frame-kessho { --frame-a: #c4b5fd; --frame-b: #4c1d95; }
.avatar-frame-jigen { --frame-a: #f0abfc; --frame-b: #4a044e; --frame-spin: conic-gradient(#4a044e, #a21caf, #f0abfc, #a21caf, #4a044e); }
/* The 2026 shelf-filling batch: palettes only. The plain half is materials,
   dyes and the four seasons; the moving half re-uses motions declared above,
   so each line here is the whole cost of its frame. */
.avatar-frame-yuki { --frame-a: #f4f6fb; --frame-b: #b9c4d6; }
.avatar-frame-hinoki { --frame-a: #c9a06a; --frame-b: #8a6134; }
.avatar-frame-tsuchi { --frame-a: #9b7653; --frame-b: #5e4228; }
.avatar-frame-mizu { --frame-a: #66b8d6; --frame-b: #2a7a99; }
.avatar-frame-ginnezu { --frame-a: #aeb4bd; --frame-b: #6e747d; }
.avatar-frame-kurocha { --frame-a: #5a4636; --frame-b: #2e2119; }
.avatar-frame-aogane { --frame-a: #3b6e8f; --frame-b: #1d3d54; }
.avatar-frame-momiji { --frame-a: #d0542b; --frame-b: #7e2a12; }
.avatar-frame-ayame { --frame-a: #6b5bb5; --frame-b: #3c2f7a; }
.avatar-frame-sango { --frame-a: #ef6f6c; --frame-b: #a83a38; }
.avatar-frame-kohaku { --frame-a: #d9982f; --frame-b: #8a5a12; }
.avatar-frame-seiji { --frame-a: #a8c5b4; --frame-b: #5f8a72; }
.avatar-frame-take { --frame-a: #74a05c; --frame-b: #3f6b2f; }
.avatar-frame-kaki { --frame-a: #e08a3c; --frame-b: #9e5514; }
.avatar-frame-asagi { --frame-a: #4fa3b8; --frame-b: #1f6b7e; }
.avatar-frame-fuji { --frame-a: #9a8ac9; --frame-b: #5d4d99; }
.avatar-frame-ume { --frame-a: #d16a8a; --frame-b: #8f3a56; }
.avatar-frame-botan { --frame-a: #c65389; --frame-b: #7e2a52; }
.avatar-frame-ruri { --frame-a: #2b4bb5; --frame-b: #14276b; }
.avatar-frame-kiku { --frame-a: #e8c84f; --frame-b: #a8881a; }
.avatar-frame-matsu { --frame-a: #3e6b4f; --frame-b: #1d3d2a; }
/* The seasons pair two colours the season owns rather than two shades of one. */
.avatar-frame-haru { --frame-a: #f2b6c6; --frame-b: #7fbf7f; }
.avatar-frame-natsu { --frame-a: #2e9e6b; --frame-b: #f2c14e; }
.avatar-frame-aki { --frame-a: #c96a2b; --frame-b: #7e3a12; }
.avatar-frame-fuyu { --frame-a: #cfe3f2; --frame-b: #6b8ba6; }
.avatar-frame-doushine { --frame-a: #b87333; --frame-b: #f2d3ae; }
.avatar-frame-gekkou { --frame-a: #dfe6f5; --frame-b: #8a94b8; }
.avatar-frame-ginshine { --frame-a: #d7dbe0; --frame-b: #f7f9fc; }
.avatar-frame-yukigeshiki { --frame-a: #e8f1fb; --frame-b: #9db8d6; }
.avatar-frame-hotarugari { --frame-a: #d8e26b; --frame-b: #7a8a1f; }
.avatar-frame-shimo { --frame-a: #cffafe; --frame-b: #155e75; }
.avatar-frame-kagami { --frame-a: #eef1f5; --frame-b: #b9c2cc; }
.avatar-frame-sakurakaze { --frame-a: #f7b6c9; --frame-b: #fff0f5; }
.avatar-frame-kinmyaku { --frame-a: #f2c14e; --frame-b: #7c5c12; }
.avatar-frame-kagaribi { --frame-a: #fb923c; --frame-b: #9a3412; }
.avatar-frame-amatsubu { --frame-a: #93c5fd; --frame-b: #1e40af; }
.avatar-frame-tama { --frame-a: #8fe3c0; --frame-b: #14532d; }
.avatar-frame-engetsu { --frame-a: #fef3c7; --frame-b: #b45309; }
.avatar-frame-raiden { --frame-a: #ffe45c; --frame-b: #3b3563; }
.avatar-frame-byakko { --frame-a: #f8fafc; --frame-b: #d4af37; }
.avatar-frame-uzushio { --frame-a: #5eead4; --frame-b: #0f766e; --frame-spin: conic-gradient(#0f766e, #2dd4bf, #ccfbf1, #2dd4bf, #0f766e); }
.avatar-frame-meikyuu { --frame-a: #8a94b8; --frame-b: #2e3454; --frame-spin: conic-gradient(#2e3454 0 20%, #8a94b8 25% 45%, #2e3454 50% 70%, #e2e8f5 75% 80%, #2e3454 85%); }
.avatar-frame-suzu { --frame-a: #ffe9a8; --frame-b: #92400e; }
.avatar-frame-genbu { --frame-a: #2dd4bf; --frame-b: #134e4a; }
.avatar-frame-mononoke { --frame-a: #c084fc; --frame-b: #3b0764; }
.avatar-frame-hoshikuzu { --frame-a: #e2e8f0; --frame-b: #0f172a; }
.avatar-frame-raikou { --frame-a: #fef08a; --frame-b: #4338ca; }
.avatar-frame-aobi { --frame-a: #60a5fa; --frame-b: #1e3a8a; }
.avatar-frame-kousai { --frame-a: #fda4af; --frame-b: #a5b4fc; }
.avatar-frame-ginga { --frame-a: #c7d2fe; --frame-b: #1e1b4b; --frame-spin: conic-gradient(#1e1b4b, #6366f1, #e0e7ff, #a5b4fc, #1e1b4b); }
.avatar-frame-suzaku { --frame-a: #fb7185; --frame-b: #7f1d1d; }
.avatar-frame-shinen { --frame-a: #38bdf8; --frame-b: #020617; }
.avatar-frame-hyoketsu { --frame-a: #a5f3fc; --frame-b: #0c4a6e; }
.avatar-frame-seiryu { --frame-a: #38bdf8; --frame-b: #1e3a8a; --frame-spin: conic-gradient(#1e3a8a 0 30%, #7dd3fc 40% 50%, #1e3a8a 60% 90%, #7dd3fc 95%, #1e3a8a); }
.avatar-frame-jikuu { --frame-a: #93c5fd; --frame-b: #172554; }

/* Motion. A gradient ring replaces the border for the ones that turn; a
 * radial mask cuts the disc out of it so only the ring shows. */
.avatar-frame-anim-spin::after, .avatar-frame-anim-dragon::after, .avatar-frame-anim-shine::after {
    border: 0;
    box-shadow: none;
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) - 1px), #000 calc(100% - var(--frame-w)));
    mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) - 1px), #000 calc(100% - var(--frame-w)));
    animation: avatar-frame-spin 3.2s linear infinite;
}
.avatar-frame-anim-spin::after { background: var(--frame-spin, conic-gradient(#7ee8fa, #80ff72, #eec0c6, #b28dff, #7ee8fa)); }
.avatar-frame-anim-dragon::after { background: var(--frame-spin, conic-gradient(#c8102e 0 30%, #f2c14e 40% 50%, #c8102e 60% 90%, #f2c14e 95%, #c8102e)); animation-duration: 2.2s; }
.avatar-frame-anim-shine::after { background: conic-gradient(var(--frame-a) 0 70%, var(--frame-b) 80%, var(--frame-a) 90%); animation-duration: 4s; }
.avatar-frame-anim-pulse::after { animation: avatar-frame-pulse 1.6s ease-in-out infinite; }
.avatar-frame-anim-haze::after { animation: avatar-frame-haze 3s ease-in-out infinite; }
.avatar-frame-anim-petals::after { border-style: dotted; border-width: calc(var(--frame-w) + 1px); animation: avatar-frame-spin 9s linear infinite; }
@keyframes avatar-frame-spin { to { transform: rotate(360deg); } }
@keyframes avatar-frame-pulse {
    0%, 100% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 4px 0 var(--frame-a); }
    50% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 14px 3px var(--frame-a); }
}
@keyframes avatar-frame-haze {
    0%, 100% { filter: blur(0); opacity: 1; }
    50% { filter: blur(1.2px); opacity: 0.75; }
}
/* ---- The loud batch's motions -------------------------------------------
 *
 * Ring effects live on ::after, which the base rule already positions and
 * rounds; anything that needs a SECOND layer takes ::before, which is free on
 * every frame that is not a piece frame (koma owns ::before for its glyph, and
 * no frame has both). Transforms are fine here - a pseudo-element is a
 * positioned box, unlike the inline element a name is printed on.
 */
.avatar-frame-anim-heartbeat::after { animation: avatar-frame-heartbeat 1.5s ease-in-out infinite; }
@keyframes avatar-frame-heartbeat {
    0%, 55%, 100% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 3px 0 var(--frame-a); }
    12% { box-shadow: 0 0 0 calc(var(--frame-w) * 1.1) var(--frame-b), 0 0 13px 2px var(--frame-a); }
    26% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 3px 0 var(--frame-a); }
    40% { box-shadow: 0 0 0 calc(var(--frame-w) * 1.35) var(--frame-b), 0 0 19px 3px var(--frame-a); }
}

/* A ring shed outward, over and over. */
.avatar-frame-anim-ripple::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap));
    border-radius: 50%;
    pointer-events: none;
    border: var(--frame-w) solid var(--frame-a);
    animation: avatar-frame-ripple 2.4s ease-out infinite;
}
@keyframes avatar-frame-ripple {
    0% { transform: scale(1); opacity: 0.85; }
    100% { transform: scale(1.55); opacity: 0; }
}

/* One bright point going round, with its own glow. */
.avatar-frame-anim-orbit::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap) - var(--frame-w) * 1.6);
    border-radius: 50%;
    pointer-events: none;
    background: radial-gradient(circle at 50% 0, var(--frame-a) 0 calc(var(--frame-w) * 1.1), transparent calc(var(--frame-w) * 1.25));
    filter: drop-shadow(0 0 4px var(--frame-a));
    animation: avatar-frame-spin 2.8s linear infinite;
}

/* The spin, but fast and smeared. */
.avatar-frame-anim-vortex::after {
    border: 0;
    box-shadow: none;
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) * 1.7 - 1px), #000 calc(100% - var(--frame-w) * 1.7));
    mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) * 1.7 - 1px), #000 calc(100% - var(--frame-w) * 1.7));
    background: var(--frame-spin, conic-gradient(var(--frame-b), var(--frame-a), var(--frame-b)));
    filter: blur(0.6px);
    animation: avatar-frame-spin 0.9s linear infinite;
}

/* Four fixed stars, twinkling out of step, turning slowly. */
.avatar-frame-anim-sparkle::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap) - var(--frame-w) * 2);
    border-radius: 50%;
    pointer-events: none;
    background:
        radial-gradient(circle at 50% 3%, var(--frame-a) 0 1.5px, transparent 2.1px),
        radial-gradient(circle at 88% 27%, var(--frame-a) 0 1.2px, transparent 1.8px),
        radial-gradient(circle at 12% 68%, var(--frame-a) 0 1.4px, transparent 2px),
        radial-gradient(circle at 68% 93%, var(--frame-a) 0 1.2px, transparent 1.8px);
    filter: drop-shadow(0 0 3px var(--frame-a));
    animation: avatar-frame-sparkle 1.8s steps(1, end) infinite, avatar-frame-spin 12s linear infinite;
}
@keyframes avatar-frame-sparkle {
    0%, 100% { opacity: 1; }
    25% { opacity: 0.3; }
    50% { opacity: 0.9; }
    75% { opacity: 0.5; }
}

/* Two offset copies of the ring, for a few frames at a time. */
.avatar-frame-anim-glitch::after { animation: avatar-frame-glitch 2.6s steps(1, end) infinite; }
@keyframes avatar-frame-glitch {
    0%, 86%, 100% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b); filter: none; }
    88% { box-shadow: -2px 0 0 var(--frame-a), 2px 0 0 var(--frame-b); filter: hue-rotate(70deg); }
    92% { box-shadow: 2px 0 0 var(--frame-a), -2px 0 0 var(--frame-b); filter: hue-rotate(-70deg); }
    96% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b); filter: none; }
}

/* Specks falling past the picture, clipped to the disc. */
.avatar-frame-anim-starfall::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap));
    border-radius: 50%;
    pointer-events: none;
    background-image:
        radial-gradient(circle, var(--frame-a) 0 1px, transparent 1.7px),
        radial-gradient(circle, var(--frame-b) 0 1px, transparent 1.7px);
    background-size: 42% 46%, 56% 62%;
    background-position: 0 0, 22% 0;
    -webkit-mask: radial-gradient(farthest-side, #000 97%, transparent);
    mask: radial-gradient(farthest-side, #000 97%, transparent);
    animation: avatar-frame-starfall 2.2s linear infinite;
}
@keyframes avatar-frame-starfall { to { background-position: 0 200%, 22% 224%; } }

/* The whole ring cycling through the spectrum as it turns. */
.avatar-frame-anim-rainbow::after {
    border: 0;
    box-shadow: none;
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) - 1px), #000 calc(100% - var(--frame-w)));
    mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) - 1px), #000 calc(100% - var(--frame-w)));
    background: var(--frame-spin);
    animation: avatar-frame-spin 4s linear infinite, avatar-frame-rainbow 3s linear infinite;
}
@keyframes avatar-frame-rainbow { to { filter: hue-rotate(360deg); } }

/* ---- Special effects: frames --------------------------------------------
 *
 * Two layers each - the ring on ::after, a drawing on ::before - which is the
 * ceiling without asking the page for another element per avatar.
 */

/* Two rings leaving at different phases, so there is always one in flight. */
.avatar-frame-anim-halo::after { animation: avatar-frame-halo 2.6s ease-out infinite; }
.avatar-frame-anim-halo::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap));
    border-radius: 50%;
    pointer-events: none;
    border: var(--frame-w) solid var(--frame-a);
    animation: avatar-frame-halo 2.6s ease-out infinite;
    animation-delay: 1.3s;
}
@keyframes avatar-frame-halo {
    0% { transform: scale(1); opacity: 0.9; }
    100% { transform: scale(1.6); opacity: 0; }
}

/* Bubbles going up behind the picture, clipped to the disc. */
.avatar-frame-anim-bubble::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap));
    border-radius: 50%;
    pointer-events: none;
    background-image:
        radial-gradient(circle, transparent 0 1.4px, var(--frame-a) 1.5px 2.2px, transparent 2.4px),
        radial-gradient(circle, transparent 0 1px, var(--frame-a) 1.1px 1.7px, transparent 1.9px);
    background-size: 44% 52%, 33% 38%;
    background-position: 10% 100%, 60% 100%;
    opacity: 0.85;
    -webkit-mask: radial-gradient(farthest-side, #000 96%, transparent);
    mask: radial-gradient(farthest-side, #000 96%, transparent);
    animation: avatar-frame-bubble 3s linear infinite;
}
@keyframes avatar-frame-bubble { to { background-position: 10% -120%, 60% -160%; } }

/* Arcs jumping round the rim: a dashed ring spun fast, strobing. */
.avatar-frame-anim-electric::after {
    border-style: dashed;
    border-width: calc(var(--frame-w) + 1px);
    animation: avatar-frame-spin 1.1s linear infinite, avatar-frame-arc 0.5s steps(1, end) infinite;
}
@keyframes avatar-frame-arc {
    0%, 100% { filter: drop-shadow(0 0 3px var(--frame-a)); opacity: 1; }
    45% { filter: drop-shadow(0 0 9px var(--frame-a)) brightness(1.6); opacity: 0.75; }
}

/* Fire: a torn, offset ring on top of a warm glow that breathes. */
.avatar-frame-anim-flame::after { animation: avatar-frame-fire 0.9s steps(1, end) infinite; }
.avatar-frame-anim-flame::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap) - var(--frame-w));
    border-radius: 50%;
    pointer-events: none;
    background: radial-gradient(circle, transparent 58%, var(--frame-a) 78%, transparent 88%);
    filter: blur(2px);
    animation: avatar-frame-fireglow 1.4s ease-in-out infinite;
}
@keyframes avatar-frame-fire {
    0%, 100% { box-shadow: 0 0 6px 1px var(--frame-a); }
    33% { box-shadow: 0 -2px 10px 2px var(--frame-a); }
    66% { box-shadow: 1px 1px 8px 1px var(--frame-b); }
}
@keyframes avatar-frame-fireglow {
    0%, 100% { opacity: 0.55; }
    50% { opacity: 1; }
}

/* A head with a tail behind it, going round. */
.avatar-frame-anim-comet::after {
    border: 0;
    box-shadow: none;
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) * 1.5 - 1px), #000 calc(100% - var(--frame-w) * 1.5));
    mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) * 1.5 - 1px), #000 calc(100% - var(--frame-w) * 1.5));
    background: var(--frame-spin);
    filter: drop-shadow(0 0 4px var(--frame-a));
    animation: avatar-frame-spin 1.8s linear infinite;
}

/* A dark disc crossing a bright ring, and a corona left at totality. */
.avatar-frame-anim-eclipse::after { animation: avatar-frame-eclipse 4s ease-in-out infinite; }
.avatar-frame-anim-eclipse::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap) - var(--frame-w));
    border-radius: 50%;
    pointer-events: none;
    background: radial-gradient(circle, transparent 62%, var(--frame-a) 82%, transparent 92%);
    filter: blur(1.5px);
    opacity: 0;
    animation: avatar-frame-corona 4s ease-in-out infinite;
}
@keyframes avatar-frame-eclipse {
    0%, 100% { border-color: var(--frame-a); box-shadow: 0 0 8px 1px var(--frame-a); }
    50% { border-color: var(--frame-b); box-shadow: 0 0 2px 0 var(--frame-b); }
}
@keyframes avatar-frame-corona {
    0%, 30%, 70%, 100% { opacity: 0; }
    50% { opacity: 1; }
}

/* Broken into segments that counter-rotate and re-seat. */
.avatar-frame-anim-shatter::after {
    border-style: dashed;
    border-width: calc(var(--frame-w) + 1px);
    animation: avatar-frame-spin 5s linear infinite reverse;
}
.avatar-frame-anim-shatter::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap) - var(--frame-w) * 1.4);
    border-radius: 50%;
    pointer-events: none;
    border: var(--frame-w) dotted var(--frame-b);
    animation: avatar-frame-spin 3.2s linear infinite;
}

/* Space bending: the ring turns while the whole thing squeezes and hue-shifts. */
.avatar-frame-anim-warp::after {
    border: 0;
    box-shadow: none;
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) * 1.8 - 1px), #000 calc(100% - var(--frame-w) * 1.8));
    mask: radial-gradient(farthest-side, transparent calc(100% - var(--frame-w) * 1.8 - 1px), #000 calc(100% - var(--frame-w) * 1.8));
    background: var(--frame-spin);
    animation: avatar-frame-spin 1.4s linear infinite, avatar-frame-warp 2.6s ease-in-out infinite;
}
.avatar-frame-anim-warp::before {
    content: '';
    position: absolute;
    inset: calc(-1 * var(--frame-gap) - var(--frame-w) * 2.6);
    border-radius: 50%;
    pointer-events: none;
    border: 1px solid var(--frame-a);
    opacity: 0.5;
    animation: avatar-frame-halo 2.6s ease-out infinite;
}
@keyframes avatar-frame-warp {
    0%, 100% { filter: hue-rotate(0) blur(0); }
    50% { filter: hue-rotate(55deg) blur(1px); }
}

@media (prefers-reduced-motion: reduce) {
    /* ::before as well as ::after: the piece glyph orbits on ::before and was
       never covered here, and every motion added in the loud batch below uses
       it too. A reader who asked for stillness gets stillness. */
    .avatar-frame::after, .avatar-frame::before { animation: none !important; }
}

/* The menu on a profile picture: what you can do with it. */
.profile-avatar-menu {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    z-index: 30;
    min-width: 200px;
    padding: 6px;
    border-radius: 10px;
    background: var(--c-box);
    color: var(--c-font);
    border: 1px solid var(--c-border);
    box-shadow: 0 12px 32px rgba(0,0,0,0.18);
    line-height: 1.3;
}
.profile-avatar-menu[hidden] { display: none; }
.profile-avatar-menu button {
    display: flex; align-items: center; gap: 8px;
    width: 100%; padding: 8px 10px;
    border: 0; border-radius: 6px; background: transparent;
    color: inherit; font: inherit; font-size: 0.9rem; text-align: left; cursor: pointer;
}
.profile-avatar-menu button:hover, .profile-avatar-menu button:focus-visible { background: var(--c-box-alt); }
.profile-avatar-wrap { cursor: pointer; }
.profile-avatar-wrap:focus-visible { outline: 3px solid var(--c-accent, #c8102e); outline-offset: 4px; }

/* kakera: the balance, wherever it is printed. */
.kakera { display: inline-flex; align-items: center; gap: 4px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.kakera-glyph { width: 1em; height: 1em; flex: none; }
.kakera-glyph-wrap { display: inline-flex; line-height: 0; }
.sidebar-kakera { display: flex; margin: 2px 0 0 8px; font-size: 0.8rem; color: var(--c-font-dim); text-decoration: none; }

/* ---- More frames: palettes ---------------------------------------------- */
.avatar-frame-hotaru { --frame-a: #d9f99d; --frame-b: #65a30d; }
.avatar-frame-yukimi { --frame-a: #ffffff; --frame-b: #bfdbfe; }
.avatar-frame-kokuyo { --frame-a: #0b0b0b; --frame-b: #6b7280; }
.avatar-frame-kitsunebi { --frame-a: #2dd4bf; --frame-b: #0f766e; }
.avatar-frame-neon { --frame-a: #ff2d95; --frame-b: #7df9ff; }
.avatar-frame-raijin { --frame-a: #e0f2fe; --frame-b: #38bdf8; }
.avatar-frame-kaen { --frame-a: #ff5a1f; --frame-b: #ffd166; }
.avatar-frame-niji { --frame-a: #ff6b6b; --frame-b: #ffd166; --frame-spin: conic-gradient(#ff6b6b, #ffd166, #6bff95, #6bc5ff, #b56bff, #ff6b6b); }
.avatar-frame-koma-fu, .avatar-frame-koma-kyo, .avatar-frame-koma-kei, .avatar-frame-koma-gin, .avatar-frame-koma-kin,
.avatar-frame-koma-ou, .avatar-frame-koma-kaku, .avatar-frame-koma-hisha { --frame-a: #e8c88a; --frame-b: #7a4a1d; --frame-ink: #1a1a1a; }
.avatar-frame-koma-to, .avatar-frame-koma-uma, .avatar-frame-koma-ryu { --frame-a: #e8c88a; --frame-b: #7a4a1d; --frame-ink: #b91c1c; }
.avatar-frame-tsumi { --frame-a: #c8102e; --frame-b: #1a1a1a; --frame-ink: #ffffff; }
.avatar-frame-koma-fu { --frame-glyph: '歩'; }
.avatar-frame-koma-kyo { --frame-glyph: '香'; }
.avatar-frame-koma-kei { --frame-glyph: '桂'; }
.avatar-frame-koma-gin { --frame-glyph: '銀'; }
.avatar-frame-koma-kin { --frame-glyph: '金'; }
.avatar-frame-koma-to { --frame-glyph: 'と'; }
.avatar-frame-koma-ou { --frame-glyph: '玉'; }
.avatar-frame-koma-kaku { --frame-glyph: '角'; }
.avatar-frame-koma-hisha { --frame-glyph: '飛'; }
.avatar-frame-koma-uma { --frame-glyph: '馬'; }
.avatar-frame-koma-ryu { --frame-glyph: '龍'; }
.avatar-frame-tsumi { --frame-glyph: '詰'; }

/* ---- More frames: motions ------------------------------------------------
 *
 * The piece frames put their character in orbit: a second pseudo-element
 * the size of the ring turns, and the character sits at its top, so it
 * circles the picture like a satellite. The others are variations on the
 * ring itself: blinking dots (fireflies), slow white dots (snow), a flash
 * every few seconds (thunder), a fast unsteady glow (flame). */
.avatar-frame-anim-koma::before {
    content: var(--frame-glyph, '飛');
    position: absolute;
    inset: calc(-1 * var(--frame-gap) - var(--frame-w) * 2.2);
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    font: 700 calc(var(--frame-w) * 4.2) / 1 var(--font-kanji, serif);
    color: var(--frame-ink, #111);
    text-shadow: 0 0 2px var(--frame-a), 0 0 4px var(--frame-a), 0 1px 0 var(--frame-a);
    animation: avatar-frame-spin 7s linear infinite;
    pointer-events: none;
    z-index: 3;
}
.avatar-frame-anim-blink::after { border-style: dotted; border-width: calc(var(--frame-w) + 1px); animation: avatar-frame-blink 1.4s ease-in-out infinite; }
.avatar-frame-anim-snow::after { border-style: dotted; border-width: calc(var(--frame-w) + 1px); animation: avatar-frame-spin 14s linear infinite, avatar-frame-blink 3s ease-in-out infinite; }
.avatar-frame-anim-flash::after { animation: avatar-frame-flash 4s linear infinite; }
.avatar-frame-anim-flicker::after { animation: avatar-frame-flicker 0.55s ease-in-out infinite; }
@keyframes avatar-frame-blink { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }
@keyframes avatar-frame-flash {
    0%, 86%, 100% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b); }
    88% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 18px 6px #ffffff; }
    91% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 4px 1px var(--frame-b); }
    94% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 22px 8px #bae6fd; }
}
@keyframes avatar-frame-flicker {
    0%, 100% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 6px 1px var(--frame-a); transform: scale(1); }
    35% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 14px 4px var(--frame-a); transform: scale(1.02); }
    70% { box-shadow: 0 0 0 calc(var(--frame-w) * 0.6) var(--frame-b), 0 0 9px 2px #ffd166; transform: scale(0.99); }
}
@media (prefers-reduced-motion: reduce) {
    .avatar-frame::before { animation: none !important; }
}

/* ---- Names: colours and faces ------------------------------------------
 *
 * Applied to the element that prints the name, wherever that is. Colours
 * win over link colours (hence !important); the gradient ones paint the
 * text with a background, which is why they must never land on a box that
 * has a background of its own. */
.name-color-crimson { color: #c8102e !important; }
.name-color-jade { color: #1f8a63 !important; }
.name-color-indigo { color: #3949ab !important; }
.name-color-gold { color: #b8860b !important; }
.name-color-sakura { color: #e26b9a !important; }
.name-color-violet { color: #7c3aed !important; }
body.dark-mode .name-color-gold { color: #f2c14e !important; }
body.dark-mode .name-color-indigo { color: #8c9eff !important; }
body.dark-mode .name-color-jade { color: #5fd3a6 !important; }
.name-color-aurora, .name-color-kaen, .name-color-umi, .name-color-niji {
    background-clip: text !important;
    -webkit-background-clip: text !important;
    color: transparent !important;
    -webkit-text-fill-color: transparent;
}
.name-color-aurora { background-image: linear-gradient(90deg, #4fd1c5, #9f7aea, #f687b3); }
.name-color-kaen { background-image: linear-gradient(90deg, #ff3d00, #ff9100, #ffd166); }
.name-color-umi { background-image: linear-gradient(90deg, #0ea5e9, #2563eb, #14b8a6); }
.name-color-niji { background-image: linear-gradient(90deg, #ff6b6b, #ffd166, #6bff95, #6bc5ff, #b56bff, #ff6b6b); background-size: 300% 100%; animation: name-color-slide 4s linear infinite; }
@keyframes name-color-slide { to { background-position: 300% 0; } }
.name-font-junge { font-family: 'Junge', Georgia, serif !important; }
.name-font-mincho { font-family: var(--font-kanji) !important; }
.name-font-mono { font-family: var(--font-mono) !important; }
.name-font-brush { font-family: 'Segoe Script', 'Brush Script MT', 'Snell Roundhand', 'Apple Chancery', cursive !important; }
.name-font-wide { letter-spacing: 0.14em; text-transform: uppercase; font-size: 0.92em; }
/* The second batch of colours: four plain, lifted for the dark ground
   where the plain ones would sink, and four gradients on the same
   clipping the first ones use. Kagayaki sweeps like niji. */
.name-color-copper { color: #a85d2a !important; }
.name-color-ocean { color: #0e7490 !important; }
.name-color-matcha { color: #4f7f2a !important; }
.name-color-sumire { color: #6a4fc4 !important; }
body.dark-mode .name-color-copper { color: #e0925c !important; }
body.dark-mode .name-color-ocean { color: #5fd0e8 !important; }
body.dark-mode .name-color-matcha { color: #9ad07a !important; }
body.dark-mode .name-color-sumire { color: #b39cff !important; }
.name-color-hinode, .name-color-kingin, .name-color-yozora, .name-color-kagayaki {
    background-clip: text !important;
    -webkit-background-clip: text !important;
    color: transparent !important;
    -webkit-text-fill-color: transparent;
}
.name-color-hinode { background-image: linear-gradient(90deg, #ff5e62, #ff9966, #ffd166); }
.name-color-kingin { background-image: linear-gradient(90deg, #f2c14e, #e8e8ee, #b8860b, #f3f3f7); }
.name-color-yozora { background-image: linear-gradient(90deg, #5b86e5, #36d1dc, #a18cd1); }
.name-color-kagayaki { background-image: linear-gradient(90deg, #b8860b, #fff1a8, #f2c14e, #fffbe6, #b8860b); background-size: 300% 100%; animation: name-color-slide 3s linear infinite; }
/* The second batch of faces: a Japanese gothic, a typewriter, a condensed. */
.name-font-gothic { font-family: 'Yu Gothic', 'Meiryo', 'Noto Sans JP', 'Hiragino Kaku Gothic ProN', sans-serif !important; font-weight: 700; }
.name-font-typewriter { font-family: 'Courier New', Courier, 'Liberation Mono', monospace !important; letter-spacing: 0.04em; }
.name-font-narrow { font-family: 'Arial Narrow', 'Roboto Condensed', 'Helvetica Neue Condensed', sans-serif-condensed, sans-serif !important; letter-spacing: 0.02em; }

/* ---- The loud batch ------------------------------------------------------
 *
 * Four more faces, four plain colours, two that glow and ten painted with a
 * moving background.
 *
 * NOTHING HERE MAY REFLOW A LINE. A name is printed inside forum posts, move
 * lists, ladders and the sidebar, so an effect that animates letter-spacing,
 * font-size or margin would shove fifty rows of somebody else's page around
 * once per frame. Every motion below animates only `background-position`,
 * `opacity`, `filter`, `box-shadow` or a transform on a positioned
 * pseudo-element - all of which compose, and none of which lay out.
 *
 * The gradient names also may not use `transform`: they are printed on inline
 * elements, where transform does not apply at all. `filter` does, which is
 * why the glitch and the prism are built out of hue-rotate rather than the
 * offset copies the effect is usually made of.
 */
.name-font-rounded { font-family: 'Nunito', 'Quicksand', 'Segoe UI Rounded', 'Varela Round', system-ui, sans-serif !important; }
.name-font-stencil { font-family: 'Stencil', 'Allerta Stencil', 'Impact', 'Haettenschweiler', sans-serif !important; letter-spacing: 0.06em; }
.name-font-display { font-family: 'Playfair Display', 'Bodoni MT', 'Didot', Georgia, serif !important; font-weight: 700; }
.name-font-smallcaps { font-variant-caps: small-caps; letter-spacing: 0.08em; font-weight: 600; }

.name-color-akane { color: #b7343f !important; }
.name-color-wakaba { color: #5c9a3a !important; }
.name-color-mizuiro { color: #2b90b8 !important; }
.name-color-kohaku { color: #b5751d !important; }
body.dark-mode .name-color-akane { color: #ff7d8a !important; }
body.dark-mode .name-color-wakaba { color: #a5e07d !important; }
body.dark-mode .name-color-mizuiro { color: #7fd8f5 !important; }
body.dark-mode .name-color-kohaku { color: #f0b95c !important; }

/* Solid, but alive. A firefly swells and fades; a heat-haze blurs a little
   and saturates. Both keep a readable colour at every point of the cycle. */
.name-color-hotarubi { color: #c9a227 !important; animation: name-glow 2.4s ease-in-out infinite; }
.name-color-shinkirou { color: #3f9aa0 !important; animation: name-waver 3.6s ease-in-out infinite; }
body.dark-mode .name-color-hotarubi { color: #ffe27a !important; }
body.dark-mode .name-color-shinkirou { color: #7fe3e8 !important; }
@keyframes name-glow {
    0%, 100% { text-shadow: 0 0 2px currentColor; }
    50% { text-shadow: 0 0 10px currentColor, 0 0 20px currentColor; }
}
@keyframes name-waver {
    0%, 100% { filter: none; }
    50% { filter: blur(0.4px) saturate(1.7); }
}

.name-color-oborozuki, .name-color-shinkai, .name-color-koori, .name-color-yugen,
.name-color-magma, .name-color-sakuraarashi, .name-color-ryusei,
.name-color-kaminari, .name-color-denkou, .name-color-gensou {
    background-clip: text !important;
    -webkit-background-clip: text !important;
    color: transparent !important;
    -webkit-text-fill-color: transparent;
    background-size: 300% 100%;
}
/* CONTRAST IS THE HARD PART, not the palette.
 *
 * A name is printed on the page background, and this site has two of them. A
 * gradient tuned to look good on the dark theme - pale silver, ice, a dark sky
 * with a white streak through it - either vanishes into white or vanishes into
 * black, and a name nobody can read is a cosmetic somebody paid for and cannot
 * use. Checked against both themes with the animations paused at their dimmest
 * frame, which is the worst case a reader actually meets.
 *
 * So the rule below is the LIGHT theme, chosen to sit on white, and the ones
 * that would drown there or in the dark get a `body.dark-mode` counterpart.
 * The middle-tone gradients (neon, flame, blossom at full strength) need only
 * one definition and have only one. */
.name-color-oborozuki { background-image: linear-gradient(90deg, #55607e, #97a3c4, #6b7799, #a7b2d0, #55607e); animation: name-color-slide 7s linear infinite; }
.name-color-shinkai { background-image: linear-gradient(90deg, #06304f, #0e7490, #22d3ee, #0e7490, #06304f); animation: name-color-slide 6s linear infinite; }
.name-color-koori { background-image: linear-gradient(90deg, #2b7fb8, #7dd3fc, #1e6fa8, #93ddfb, #2b7fb8); animation: name-color-slide 4.5s linear infinite; }
.name-color-yugen { background-image: linear-gradient(90deg, #4c1d95, #7c3aed, #a78bfa, #7c3aed, #4c1d95); animation: name-color-slide 5s linear infinite, name-breathe 3s ease-in-out infinite; }
.name-color-magma { background-image: linear-gradient(90deg, #5b1206, #b91c1c, #f97316, #fbbf24, #f97316, #b91c1c, #5b1206); animation: name-color-slide 3.4s linear infinite; }
.name-color-sakuraarashi { background-image: linear-gradient(90deg, #c93b74, #ff5d94, #b83268, #ff85b0, #c93b74); animation: name-color-slide 4s linear infinite; }
/* A bright streak crossing a dark sky, rather than a band of colour. */
.name-color-ryusei { background-image: linear-gradient(100deg, #16204d 38%, #7cc4f5 47%, #2f5aa8 53%, #16204d 62%); animation: name-color-slide 2.6s linear infinite; }
.name-color-kaminari { background-image: linear-gradient(90deg, #312e81, #6366f1, #4338ca, #818cf8, #312e81); animation: name-color-slide 2.2s linear infinite, name-flicker 1.7s steps(1, end) infinite; }
.name-color-denkou { background-image: linear-gradient(90deg, #ff2d95, #22b8cf, #ff2d95); animation: name-color-slide 2.4s linear infinite, name-glitch 2.8s steps(1, end) infinite; }
.name-color-gensou { background-image: linear-gradient(90deg, #e11d48, #d97706, #16a34a, #0284c7, #7c3aed, #e11d48); animation: name-color-slide 3s linear infinite, name-hue 6s linear infinite; }
/* The dark theme's half: the pale ones go back to being pale, and the ones
   built out of a night sky are lifted until they read on one. */
body.dark-mode .name-color-oborozuki { background-image: linear-gradient(90deg, #98a4c6, #eef1f9, #bcc6e0, #f7f9fd, #98a4c6); }
body.dark-mode .name-color-koori { background-image: linear-gradient(90deg, #7dd3fc, #ffffff, #38bdf8, #e0f7ff, #7dd3fc); }
body.dark-mode .name-color-sakuraarashi { background-image: linear-gradient(90deg, #f9a8c9, #ff5d94, #fff0f5, #ff8fb6, #f9a8c9); }
body.dark-mode .name-color-yugen { background-image: linear-gradient(90deg, #8b5cf6, #c4b5fd, #ede9fe, #c4b5fd, #8b5cf6); }
body.dark-mode .name-color-shinkai { background-image: linear-gradient(90deg, #2596b4, #67e8f9, #a5f3fc, #38bdf8, #2596b4); }
body.dark-mode .name-color-magma { background-image: linear-gradient(90deg, #c2410c, #ef4444, #fb923c, #fde047, #fb923c, #ef4444, #c2410c); }
body.dark-mode .name-color-ryusei { background-image: linear-gradient(100deg, #7e93c7 38%, #ffffff 47%, #cfe8ff 53%, #7e93c7 62%); }
body.dark-mode .name-color-kaminari { background-image: linear-gradient(90deg, #a5b4fc, #ffffff, #e0e7ff, #c7d2fe, #a5b4fc); }
body.dark-mode .name-color-denkou { background-image: linear-gradient(90deg, #ff2d95, #7df9ff, #ff2d95); }
body.dark-mode .name-color-gensou { background-image: linear-gradient(90deg, #ff6b6b, #ffd166, #6bff95, #6bc5ff, #b56bff, #ff6b6b); }
@keyframes name-breathe { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
@keyframes name-hue { to { filter: hue-rotate(360deg); } }
@keyframes name-flicker {
    0%, 90%, 100% { opacity: 1; }
    91% { opacity: 0.3; }
    93% { opacity: 1; }
    95% { opacity: 0.55; }
    97% { opacity: 1; }
}
@keyframes name-glitch {
    0%, 88%, 100% { filter: none; }
    89% { filter: hue-rotate(90deg) saturate(3); }
    92% { filter: hue-rotate(-70deg) contrast(1.7); }
    95% { filter: none; }
}
/* ---- Special effects: text ----------------------------------------------
 *
 * A different MECHANISM each, not a tenth sliding rainbow. Still bound by the
 * same two rules as everything above: no property that lays out, and no
 * `transform` (a name is an inline box, where it does not apply).
 */
.name-font-blackletter { font-family: 'UnifrakturMaguntia', 'Old English Text MT', 'Blackadder ITC', 'Luminari', fantasy !important; }
.name-font-slab { font-family: 'Rockwell', 'Roboto Slab', 'Bitter', 'Courier New', serif !important; font-weight: 700; }
.name-font-future { font-family: 'Orbitron', 'Eurostile', 'Bank Gothic', 'Trebuchet MS', sans-serif !important; letter-spacing: 0.1em; }
.name-font-script { font-family: 'Segoe Script', 'Lucida Handwriting', 'Apple Chancery', cursive !important; font-style: italic; }
.name-font-heavy { font-weight: 900 !important; letter-spacing: -0.01em; }
/* No web fonts are loaded on this site, so the pixel faces below land only
   for readers who happen to own them; everyone else gets monospace, which is
   what `typewriter` already sells. The weight, the caps and the spacing are
   what make this a different thing to buy rather than the same one twice. */
.name-font-retro {
    font-family: 'Silkscreen', 'Press Start 2P', 'VT323', 'Courier New', monospace !important;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    font-size: 0.92em;
}
/* Two treatments rather than faces: hollow glyphs, and glyphs with a lip.
   `outline` paints the fill away, so it sets its own colour and a worn name
   colour cannot show through - which is the intended look, not a clash. */
.name-font-outline {
    -webkit-text-stroke: 1px currentColor;
    -webkit-text-fill-color: transparent;
    color: currentColor;
    paint-order: stroke fill;
}
.name-font-emboss { text-shadow: 0 1px 0 rgba(255, 255, 255, 0.55), 0 -1px 0 rgba(0, 0, 0, 0.35); }
body.dark-mode .name-font-emboss { text-shadow: 0 1px 0 rgba(255, 255, 255, 0.18), 0 -1px 0 rgba(0, 0, 0, 0.7); }

/* A neon sign that has not been serviced: irregular, with the glow dying with
   the letters rather than a beat behind them. */
.name-color-tenmetsu { color: #ff2d95 !important; animation: name-neon 3.1s steps(1, end) infinite; }
body.dark-mode .name-color-tenmetsu { color: #ff5cae !important; }
@keyframes name-neon {
    0%, 40%, 44%, 62%, 100% { opacity: 1; text-shadow: 0 0 6px currentColor, 0 0 14px currentColor; }
    42%, 58% { opacity: 0.35; text-shadow: none; }
    60% { opacity: 0.8; text-shadow: 0 0 4px currentColor; }
}
/* The red/cyan split of a badly aligned print, breathing in and out. */
.name-color-sanjigen { color: #23233a !important; animation: name-anaglyph 2.8s ease-in-out infinite; }
body.dark-mode .name-color-sanjigen { color: #e6e6f5 !important; }
@keyframes name-anaglyph {
    0%, 100% { text-shadow: 0 0 0 rgba(255, 0, 80, 0.9), 0 0 0 rgba(0, 220, 255, 0.9); }
    50% { text-shadow: -2px 0 0 rgba(255, 0, 80, 0.9), 2px 0 0 rgba(0, 220, 255, 0.9); }
}
/* One solid colour taken all the way round the wheel. */
.name-color-kaiten { color: #e0245e !important; animation: name-hue 4s linear infinite; }
/* A bad signal: brightness and contrast jumping on a hard step. */
.name-color-noizu { color: #3f3f57 !important; animation: name-static 1.4s steps(1, end) infinite; }
body.dark-mode .name-color-noizu { color: #d8d8ea !important; }
@keyframes name-static {
    0%, 100% { filter: none; }
    20% { filter: contrast(2.4) brightness(1.3); }
    40% { filter: contrast(0.7) brightness(0.85); }
    55% { filter: contrast(1.9) saturate(0.2); }
    70% { filter: none; }
}
/* Air over hot ground: the gradient drifts while the glyphs go in and out of
   focus, a beat out of step so it never looks like a single loop. */
.name-color-nekki, .name-color-senkou, .name-color-soukou, .name-color-ougon {
    background-clip: text !important;
    -webkit-background-clip: text !important;
    color: transparent !important;
    -webkit-text-fill-color: transparent;
    background-size: 300% 100%;
}
.name-color-nekki { background-image: linear-gradient(90deg, #b45309, #f59e0b, #fca5a5, #f59e0b, #b45309); animation: name-color-slide 5s linear infinite, name-waver 2.3s ease-in-out infinite; }
/* A specular band: a hard, narrow highlight crossing a flat colour, which is
   what makes a surface look polished rather than merely coloured. */
.name-color-senkou { background-image: linear-gradient(105deg, #1f2937 42%, #ffffff 48%, #e5e7eb 51%, #1f2937 57%); animation: name-color-slide 2.8s linear infinite; }
body.dark-mode .name-color-senkou { background-image: linear-gradient(105deg, #9ca3af 42%, #ffffff 48%, #f3f4f6 51%, #9ca3af 57%); }
/* Scanlines drifting up a phosphor screen. */
.name-color-soukou { background-image: repeating-linear-gradient(0deg, #0f766e 0 2px, #14b8a6 2px 4px); background-size: 100% 300%; animation: name-scan 1.6s linear infinite; }
body.dark-mode .name-color-soukou { background-image: repeating-linear-gradient(0deg, #2dd4bf 0 2px, #99f6e4 2px 4px); }
@keyframes name-scan { to { background-position: 0 300%; } }
/* Molten gold: a dark bed, a wide warm body, and a white specular edge. */
.name-color-ougon { background-image: linear-gradient(100deg, #7c5c12 30%, #f2c14e 44%, #fffbe6 50%, #f2c14e 56%, #7c5c12 70%); animation: name-color-slide 3.2s linear infinite; }
body.dark-mode .name-color-ougon { background-image: linear-gradient(100deg, #b8860b 30%, #f2c14e 44%, #fffbe6 50%, #f2c14e 56%, #b8860b 70%); }

/* ---- The 2026 shelf-filling batch ---------------------------------------
 *
 * Sixty colours and thirty-five faces, and NOT ONE NEW KEYFRAME OR FONT
 * FILE among them: the plain dyes are a colour and its dark-ground lift,
 * the gradients ride the clipping and the slide the loud batch already
 * pays for, the borrowed-motion solids re-use name-glow / name-waver /
 * name-breathe / name-hue / name-flicker, and every face is a stack of
 * things readers plausibly have installed. Same two laws as everything
 * above: nothing lays out, nothing transforms an inline box. */
.name-color-sango { color: #d9565e !important; }
.name-color-fuji { color: #7a68b3 !important; }
.name-color-momiji { color: #c04a2b !important; }
.name-color-yamabuki { color: #c78a00 !important; }
.name-color-shu { color: #cf3a24 !important; }
.name-color-ruri { color: #2f4db3 !important; }
.name-color-hai { color: #6b7280 !important; }
.name-color-kuri { color: #7b4a21 !important; }
.name-color-uguisu { color: #6f6b2a !important; }
.name-color-enji { color: #9d2f45 !important; }
.name-color-nando { color: #3f5b6e !important; }
.name-color-tetsu { color: #43555a !important; }
.name-color-sabi { color: #8a5b3a !important; }
.name-color-take { color: #4a7c46 !important; }
.name-color-tsutsuji { color: #c94f8c !important; }
.name-color-mikan { color: #d1730f !important; }
.name-color-suzume { color: #8c6450 !important; }
.name-color-botan { color: #b1447e !important; }
.name-color-kachiiro { color: #1f2f54 !important; }
.name-color-kikyo { color: #5a4fa0 !important; }
.name-color-asagi { color: #2e7d8c !important; }
.name-color-suou { color: #8e3a4d !important; }
.name-color-budou { color: #6d3f7d !important; }
.name-color-shion { color: #8471b8 !important; }
body.dark-mode .name-color-sango { color: #ff9aa0 !important; }
body.dark-mode .name-color-fuji { color: #b7a8ea !important; }
body.dark-mode .name-color-momiji { color: #ff8f6b !important; }
body.dark-mode .name-color-yamabuki { color: #f5c33b !important; }
body.dark-mode .name-color-shu { color: #ff7a5c !important; }
body.dark-mode .name-color-ruri { color: #8fa8ff !important; }
body.dark-mode .name-color-hai { color: #b7bec9 !important; }
body.dark-mode .name-color-kuri { color: #c68b55 !important; }
body.dark-mode .name-color-uguisu { color: #c3bd6d !important; }
body.dark-mode .name-color-enji { color: #e57d92 !important; }
body.dark-mode .name-color-nando { color: #8fb4c9 !important; }
body.dark-mode .name-color-tetsu { color: #9fb6bc !important; }
body.dark-mode .name-color-sabi { color: #d1a071 !important; }
body.dark-mode .name-color-take { color: #8ecf88 !important; }
body.dark-mode .name-color-tsutsuji { color: #ff96cd !important; }
body.dark-mode .name-color-mikan { color: #ffab4e !important; }
body.dark-mode .name-color-suzume { color: #cfa48c !important; }
body.dark-mode .name-color-botan { color: #f08bc0 !important; }
body.dark-mode .name-color-kachiiro { color: #93a7d6 !important; }
body.dark-mode .name-color-kikyo { color: #a79ef0 !important; }
body.dark-mode .name-color-asagi { color: #7fd0e0 !important; }
body.dark-mode .name-color-suou { color: #dd8496 !important; }
body.dark-mode .name-color-budou { color: #c08ad2 !important; }
body.dark-mode .name-color-shion { color: #beaff0 !important; }
/* The still gradients: mid-tone palettes on purpose, so one definition
   reads on both grounds, the same bargain aurora and kaen strike. */
.name-color-yuuyake, .name-color-shinryoku, .name-color-ajisai, .name-color-kitsune,
.name-color-kujaku, .name-color-momo, .name-color-seiun, .name-color-kohakutou,
.name-color-wasabi, .name-color-tasogare, .name-color-sakurayu, .name-color-gyokuro {
    background-clip: text !important;
    -webkit-background-clip: text !important;
    color: transparent !important;
    -webkit-text-fill-color: transparent;
}
.name-color-yuuyake { background-image: linear-gradient(90deg, #ef4444, #f97316, #eab308); }
.name-color-shinryoku { background-image: linear-gradient(90deg, #15803d, #4ade80, #0d9488); }
.name-color-ajisai { background-image: linear-gradient(90deg, #60a5fa, #a78bfa, #f472b6); }
.name-color-kitsune { background-image: linear-gradient(90deg, #b45309, #f59e0b, #ea580c); }
.name-color-kujaku { background-image: linear-gradient(90deg, #0e7490, #10b981, #6366f1); }
.name-color-momo { background-image: linear-gradient(90deg, #e11d48, #fb923c, #db2777); }
.name-color-seiun { background-image: linear-gradient(90deg, #7c3aed, #db2777, #2563eb); }
.name-color-kohakutou { background-image: linear-gradient(90deg, #92400e, #d97706, #fbbf24); }
.name-color-wasabi { background-image: linear-gradient(90deg, #4d7c0f, #14b8a6, #65a30d); }
.name-color-tasogare { background-image: linear-gradient(90deg, #4338ca, #7c3aed, #be185d); }
.name-color-sakurayu { background-image: linear-gradient(90deg, #be185d, #ec4899, #9d174d); }
.name-color-gyokuro { background-image: linear-gradient(90deg, #166534, #65a30d, #0f766e); }
/* Solids on borrowed motions. */
.name-color-kasumi { color: #5e7290 !important; animation: name-waver 3.2s ease-in-out infinite; }
.name-color-kodama { color: #3d7a52 !important; animation: name-breathe 3.4s ease-in-out infinite; }
.name-color-inori { color: #b07c1f !important; animation: name-glow 3s ease-in-out infinite; }
.name-color-akebono { color: #d16a7e !important; animation: name-glow 2.6s ease-in-out infinite; }
.name-color-keikou { color: #4f9e1f !important; animation: name-glow 2s ease-in-out infinite; }
.name-color-aoibi { color: #2d7dd2 !important; animation: name-glow 2.2s ease-in-out infinite; }
.name-color-yurameki { color: #c2571b !important; animation: name-flicker 2.1s steps(1, end) infinite; }
.name-color-henge { color: #0e8f7e !important; animation: name-hue 5s linear infinite; }
body.dark-mode .name-color-kasumi { color: #aebfd9 !important; }
body.dark-mode .name-color-kodama { color: #8fd0a8 !important; }
body.dark-mode .name-color-inori { color: #ffd97a !important; }
body.dark-mode .name-color-akebono { color: #ff9eb0 !important; }
body.dark-mode .name-color-keikou { color: #86e034 !important; }
body.dark-mode .name-color-aoibi { color: #6db8ff !important; }
body.dark-mode .name-color-yurameki { color: #ff9457 !important; }
/* The sweeps, all on name-color-slide; two borrow a second motion. The
   ones built on a dark bed get lifted for the dark ground, as before. */
.name-color-aozora, .name-color-sazanami, .name-color-kogane, .name-color-ushio,
.name-color-shiranami, .name-color-tsubaki, .name-color-homura, .name-color-akatsuki,
.name-color-yamiyo, .name-color-yuubae, .name-color-gekka, .name-color-kurogane,
.name-color-raiun, .name-color-ginga, .name-color-hanabi, .name-color-byakuya {
    background-clip: text !important;
    -webkit-background-clip: text !important;
    color: transparent !important;
    -webkit-text-fill-color: transparent;
    background-size: 300% 100%;
}
.name-color-aozora { background-image: linear-gradient(90deg, #0284c7, #38bdf8, #60a5fa, #38bdf8, #0284c7); animation: name-color-slide 5s linear infinite; }
.name-color-sazanami { background-image: linear-gradient(90deg, #0e7490, #67e8f9, #0e7490, #22d3ee, #0e7490); animation: name-color-slide 6s linear infinite; }
.name-color-kogane { background-image: linear-gradient(90deg, #a16207, #facc15, #fde68a, #facc15, #a16207); animation: name-color-slide 4s linear infinite; }
.name-color-ushio { background-image: linear-gradient(90deg, #164e63, #0891b2, #67e8f9, #0891b2, #164e63); animation: name-color-slide 5s linear infinite; }
.name-color-shiranami { background-image: linear-gradient(100deg, #155e75 40%, #e0f2fe 48%, #7dd3fc 52%, #155e75 60%); animation: name-color-slide 3s linear infinite; }
.name-color-tsubaki { background-image: linear-gradient(90deg, #9f1239, #e11d48, #fda4af, #e11d48, #9f1239); animation: name-color-slide 4.5s linear infinite; }
.name-color-homura { background-image: linear-gradient(90deg, #7f1d1d, #dc2626, #f97316, #fbbf24, #f97316, #dc2626, #7f1d1d); animation: name-color-slide 3.2s linear infinite; }
.name-color-akatsuki { background-image: linear-gradient(90deg, #312e81, #a855f7, #ec4899, #fbbf24, #ec4899, #a855f7, #312e81); animation: name-color-slide 5s linear infinite; }
.name-color-yamiyo { background-image: linear-gradient(90deg, #0f172a, #4c1d95, #7c3aed, #4c1d95, #0f172a); animation: name-color-slide 6s linear infinite; }
.name-color-yuubae { background-image: linear-gradient(90deg, #b91c1c, #ea580c, #f59e0b, #ea580c, #b91c1c); animation: name-color-slide 4.5s linear infinite; }
.name-color-gekka { background-image: linear-gradient(100deg, #1e293b 38%, #e2e8f0 47%, #94a3b8 53%, #1e293b 62%); animation: name-color-slide 3.4s linear infinite; }
.name-color-kurogane { background-image: linear-gradient(100deg, #18181b 35%, #52525b 45%, #ef4444 50%, #52525b 55%, #18181b 65%); animation: name-color-slide 3s linear infinite; }
.name-color-raiun { background-image: linear-gradient(90deg, #1e293b, #475569, #facc15, #475569, #1e293b); animation: name-color-slide 2.4s linear infinite, name-flicker 1.9s steps(1, end) infinite; }
.name-color-ginga { background-image: linear-gradient(90deg, #1e1b4b, #4338ca, #c7d2fe, #db2777, #1e1b4b); animation: name-color-slide 7s linear infinite; }
.name-color-hanabi { background-image: linear-gradient(90deg, #b91c1c, #f59e0b, #10b981, #3b82f6, #a855f7, #b91c1c); animation: name-color-slide 2.8s linear infinite, name-flicker 2.3s steps(1, end) infinite; }
.name-color-byakuya { background-image: linear-gradient(90deg, #475569, #e2e8f0, #bae6fd, #e2e8f0, #475569); animation: name-color-slide 5s linear infinite; }
body.dark-mode .name-color-ushio { background-image: linear-gradient(90deg, #22d3ee, #a5f3fc, #e0feff, #a5f3fc, #22d3ee); }
body.dark-mode .name-color-shiranami { background-image: linear-gradient(100deg, #7dd3fc 40%, #ffffff 48%, #bae6fd 52%, #7dd3fc 60%); }
body.dark-mode .name-color-tsubaki { background-image: linear-gradient(90deg, #f43f5e, #fda4af, #fff1f2, #fda4af, #f43f5e); }
body.dark-mode .name-color-homura { background-image: linear-gradient(90deg, #dc2626, #f97316, #fde047, #fb923c, #dc2626); }
body.dark-mode .name-color-akatsuki { background-image: linear-gradient(90deg, #818cf8, #d8b4fe, #f9a8d4, #fde68a, #f9a8d4, #d8b4fe, #818cf8); }
body.dark-mode .name-color-yamiyo { background-image: linear-gradient(90deg, #6d28d9, #a78bfa, #ede9fe, #a78bfa, #6d28d9); }
body.dark-mode .name-color-gekka { background-image: linear-gradient(100deg, #94a3b8 38%, #ffffff 47%, #cbd5e1 53%, #94a3b8 62%); }
body.dark-mode .name-color-kurogane { background-image: linear-gradient(100deg, #71717a 35%, #d4d4d8 45%, #f87171 50%, #d4d4d8 55%, #71717a 65%); }
body.dark-mode .name-color-raiun { background-image: linear-gradient(90deg, #94a3b8, #cbd5e1, #fde047, #cbd5e1, #94a3b8); }
body.dark-mode .name-color-ginga { background-image: linear-gradient(90deg, #818cf8, #c7d2fe, #f5f3ff, #f9a8d4, #818cf8); }
body.dark-mode .name-color-byakuya { background-image: linear-gradient(90deg, #94a3b8, #f1f5f9, #e0f2fe, #f1f5f9, #94a3b8); }
/* The batch's faces: stacks, honestly ended. */
.name-font-sysui { font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif !important; }
.name-font-antiqua { font-family: 'Book Antiqua', 'Palatino Linotype', Palatino, 'URW Palladio L', serif !important; }
.name-font-garamond { font-family: Garamond, 'EB Garamond', 'Apple Garamond', 'Times New Roman', serif !important; }
.name-font-baskerville { font-family: Baskerville, 'Baskerville Old Face', 'Libre Baskerville', 'Times New Roman', serif !important; }
.name-font-verdana { font-family: Verdana, Geneva, 'DejaVu Sans', sans-serif !important; }
.name-font-trebuchet { font-family: 'Trebuchet MS', 'Fira Sans', sans-serif !important; }
.name-font-comic { font-family: 'Comic Sans MS', 'Comic Neue', 'Chalkboard SE', cursive !important; }
.name-font-papyrus { font-family: Papyrus, 'Papyrus Std', fantasy !important; }
.name-font-impact { font-family: Impact, Haettenschweiler, 'Arial Black', sans-serif !important; letter-spacing: 0.02em; }
.name-font-copperplate { font-family: Copperplate, 'Copperplate Gothic Light', 'Copperplate Gothic Bold', fantasy !important; letter-spacing: 0.04em; }
.name-font-lucida { font-family: 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', sans-serif !important; }
.name-font-optima { font-family: Optima, 'Noto Sans', 'Segoe UI', sans-serif !important; }
.name-font-avantgarde { font-family: 'Century Gothic', 'Avant Garde', 'ITC Avant Garde Gothic', Futura, sans-serif !important; }
.name-font-bookman { font-family: 'Bookman Old Style', 'ITC Bookman', 'URW Bookman', serif !important; }
.name-font-chalk { font-family: 'Chalkboard SE', Chalkboard, 'Comic Sans MS', cursive !important; }
.name-font-marker { font-family: 'Segoe Print', 'Marker Felt', 'Comic Sans MS', cursive !important; }
.name-font-cambria { font-family: Cambria, Charter, 'Bitstream Charter', Georgia, serif !important; }
.name-font-constantia { font-family: Constantia, 'Hoefler Text', Cochin, Georgia, serif !important; }
.name-font-franklin { font-family: 'Franklin Gothic Medium', 'Libre Franklin', 'Arial Narrow', sans-serif !important; font-weight: 600; }
.name-font-gill { font-family: 'Gill Sans', 'Gill Sans MT', Calibri, sans-serif !important; }
.name-font-perpetua { font-family: Perpetua, 'Goudy Old Style', 'Times New Roman', serif !important; }
.name-font-candara { font-family: Candara, Corbel, 'Segoe UI', sans-serif !important; }
/* And its treatments: pure CSS on whatever face is worn. */
.name-font-italic { font-style: italic !important; }
.name-font-minuscule { text-transform: lowercase; font-weight: 500; }
.name-font-thin { font-weight: 200 !important; letter-spacing: 0.05em; }
.name-font-airy { text-transform: uppercase; font-weight: 300; letter-spacing: 0.22em; font-size: 0.9em; }
.name-font-spaced { letter-spacing: 0.18em; }
.name-font-inked { font-weight: 600; text-shadow: 0.6px 0 0 currentColor; }
.name-font-shadow { text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.28); }
body.dark-mode .name-font-shadow { text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.65); }
.name-font-longshadow { text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.3), 2px 2px 0 rgba(0, 0, 0, 0.24), 3px 3px 0 rgba(0, 0, 0, 0.18), 4px 4px 0 rgba(0, 0, 0, 0.12); }
/* The emboss, cut the other way: light below, dark above, so the glyphs
   read as pressed into the page rather than raised off it. */
.name-font-engrave { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.35), 0 1px 0 rgba(255, 255, 255, 0.55); }
body.dark-mode .name-font-engrave { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.7), 0 1px 0 rgba(255, 255, 255, 0.18); }
/* Japanese emphasis dots over every glyph - the one treatment here that is
   native to the script the site teaches. */
.name-font-bouten { -webkit-text-emphasis: filled sesame currentColor; text-emphasis: filled sesame currentColor; }
.name-font-namisen { text-decoration: underline wavy currentColor 1px; text-underline-offset: 3px; }
.name-font-zenkaku { letter-spacing: 0.38em; font-size: 0.92em; font-weight: 600; }
.name-font-poster { font-weight: 800 !important; text-transform: uppercase; letter-spacing: 0.03em; }

/* Same bargain the frames strike: asked for stillness, given stillness. */
@media (prefers-reduced-motion: reduce) {
    [class*='name-color-'] { animation: none !important; }
}

/* ---- The tournament countdown --------------------------------------------
 *
 * The page's anchor while registration is open. It replaces a screenful of
 * nothing under four names, and it answers the question a reader on a
 * scheduled tournament page actually has.
 *
 * TABULAR FIGURES ARE NOT DECORATION HERE. The seconds cell repaints once a
 * second, and in a proportional face "11" is narrower than "00", so the whole
 * row shifted on every tick. `tabular-nums` plus a min-width on the cell holds
 * the grid still; a fixed width alone would not, because the digits inside
 * would still slide.
 */
.tournament-countdown {
    margin: 18px 16px 8px;
    padding: 22px 20px 18px;
    border: 1px solid var(--c-border);
    border-radius: 16px;
    background: var(--c-box-alt);
    text-align: center;
}
.tournament-countdown-title {
    margin: 0 0 14px;
    font-size: 0.74rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    opacity: 0.6;
}
.tournament-countdown-grid {
    display: flex;
    justify-content: center;
    align-items: stretch;
    gap: 10px;
    flex-wrap: wrap;
}
.tournament-countdown-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    min-width: 76px;
    padding: 12px 10px 10px;
    border-radius: 12px;
    background: var(--c-box);
    border: 1px solid var(--c-border);
}
.tournament-countdown-value {
    font-size: clamp(1.7rem, 5vw, 2.5rem);
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum' 1;
}
.tournament-countdown-label {
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    opacity: 0.6;
}
.tournament-countdown-when {
    margin: 14px 0 0;
    font-size: 0.95rem;
    font-weight: 600;
}
/* toLocaleString lower-cases the weekday in pt-BR and capitalises it in en, so
   the first letter is lifted here rather than in two different strings.
   `capitalize` is the wrong tool: it lifts EVERY word, and "Sábado, 29 De
   Agosto Às 20:00" is not how the date is written in either language. */
.tournament-countdown-when::first-letter { text-transform: uppercase; }
.tournament-countdown-note { margin: 4px 0 0; font-size: 0.85rem; opacity: 0.7; }

/* Past the hour, waiting for the sweep to pick it up. */
.tournament-countdown.is-due { border-color: var(--c-accent); }
.tournament-countdown.is-due .tournament-countdown-title {
    font-size: 1.15rem;
    letter-spacing: 0.04em;
    text-transform: none;
    opacity: 1;
    font-weight: 700;
    margin-bottom: 4px;
    animation: tournament-due-pulse 1.6s ease-in-out infinite;
}
@keyframes tournament-due-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
@media (prefers-reduced-motion: reduce) {
    .tournament-countdown.is-due .tournament-countdown-title { animation: none; }
}
@media (max-width: 520px) {
    .tournament-countdown { padding: 16px 12px 14px; }
    .tournament-countdown-cell { min-width: 62px; padding: 10px 6px 8px; }
}

/* The strip on the shelf. One row, koma behind it, and a door.
 *
 * Gold, not the shop's pink: the tiers are titles - King, Ryuuou, Meijin -
 * and a title is gilded. The strip is the one loud thing on the shelf on
 * purpose: it is what pays for everything below it. */
/* The pass's gold, for the strip and the dialog behind it. */
body {
    --pass-gold: #b8860b;
    --pass-gold-deep: #8a6508;
    --pass-on-gold: #1f1605;
}
body.dark-mode {
    --pass-gold: #e2b449;
    --pass-gold-deep: #f0c65e;
    --pass-on-gold: #1c1607;
}
.shop-pass-banner {
    grid-column: 1 / -1;
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    width: 100%;
    margin-bottom: 18px;
    padding: 20px 22px;
    border: 1px solid color-mix(in srgb, var(--pass-gold) 55%, transparent);
    border-radius: 16px;
    background:
        linear-gradient(100deg,
            color-mix(in srgb, var(--pass-gold) 22%, transparent) 0%,
            color-mix(in srgb, var(--pass-gold) 8%, transparent) 55%,
            transparent 100%),
        var(--c-box, #fff);
    box-shadow: 0 1px 0 color-mix(in srgb, var(--pass-gold) 30%, transparent) inset, var(--elev-1, none);
    color: inherit;
    text-align: left;
    font: inherit;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.shop-pass-banner::before {
    /* A gilded edge along the left, the way a title card is bound. */
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 6px;
    background: linear-gradient(180deg, var(--pass-gold-deep), var(--pass-gold));
}
.shop-pass-banner::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22132%22%20height%3D%22132%22%20viewBox%3D%220%200%20132%20132%22%3E%3Cg%20fill%3D%22%23b8860b%22%3E%3Cpath%20d%3D%22M30%2012%20L46%2020%20L50%2052%20L10%2052%20L14%2020%20Z%22%2F%3E%3Cpath%20d%3D%22M96%2034%20L112%2042%20L116%2074%20L76%2074%20L80%2042%20Z%22%20transform%3D%22rotate%2818%2096%2054%29%22%2F%3E%3Cpath%20d%3D%22M52%2082%20L66%2089%20L70%20116%20L34%20116%20L38%2089%20Z%22%20transform%3D%22rotate%28-13%2052%2099%29%22%2F%3E%3Cpath%20d%3D%22M118%20100%20L130%20106%20L133%20128%20L103%20128%20L106%20106%20Z%22%20transform%3D%22rotate%289%20118%20114%29%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
    background-size: 132px 132px;
    opacity: 0.055;
}
body.dark-mode .shop-pass-banner::after { opacity: 0.08; }
.shop-pass-banner > * { position: relative; z-index: 1; }
.shop-pass-banner:hover {
    border-color: var(--pass-gold);
    transform: translateY(-1px);
    box-shadow: 0 1px 0 color-mix(in srgb, var(--pass-gold) 40%, transparent) inset,
        0 6px 18px color-mix(in srgb, var(--pass-gold) 22%, transparent);
}
.shop-pass-banner:focus-visible { outline: 2px solid var(--pass-gold); outline-offset: 2px; }
.shop-pass-banner-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.shop-pass-banner-title {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-weight: 800;
    font-size: 1.28rem;
    letter-spacing: -0.01em;
    line-height: 1.15;
}
/* The crown that stands for a title. */
.shop-pass-banner-title::before {
    content: '';
    flex: none;
    width: 22px;
    height: 22px;
    background-color: var(--pass-gold);
    -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M3%2018h18v2H3zM3%2016l-1-9%205.5%204L12%204l4.5%207L22%207l-1%209z%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M3%2018h18v2H3zM3%2016l-1-9%205.5%204L12%204l4.5%207L22%207l-1%209z%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
}
.shop-pass-banner-lead { font-size: 0.92rem; color: var(--c-font-dim, inherit); line-height: 1.4; }
.shop-pass-banner-side { display: flex; align-items: center; gap: 16px; flex: none; }
.shop-pass-banner-price {
    font-weight: 800;
    font-size: 1.08rem;
    color: var(--pass-gold-deep);
    white-space: nowrap;
}
body.dark-mode .shop-pass-banner-price { color: var(--pass-gold); }
.shop-pass-banner-cta {
    display: inline-flex;
    align-items: center;
    padding: 11px 18px;
    border-radius: 999px;
    background: linear-gradient(180deg, var(--pass-gold), var(--pass-gold-deep));
    color: var(--pass-on-gold);
    font-size: 0.82rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
body.dark-mode .shop-pass-banner-cta { background: linear-gradient(180deg, var(--pass-gold-deep), var(--pass-gold)); }
.shop-pass-banner:hover .shop-pass-banner-cta { filter: brightness(1.06); }
.shop-pass-modal .modal-dialog { max-width: 760px; width: 100%; overflow: hidden; }
/* The dialog's head is the strip again: the same gilded edge, the same
   crown, so the door and the room behind it are one thing. */
.shop-pass-modal .modal-header {
    position: relative;
    padding-left: 30px;
    background: linear-gradient(100deg,
        color-mix(in srgb, var(--pass-gold) 22%, transparent) 0%,
        color-mix(in srgb, var(--pass-gold) 6%, transparent) 70%,
        transparent 100%);
    border-bottom: 1px solid color-mix(in srgb, var(--pass-gold) 40%, transparent);
}
.shop-pass-modal .modal-header::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 6px;
    background: linear-gradient(180deg, var(--pass-gold-deep), var(--pass-gold));
}
.shop-pass-modal .modal-title {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-weight: 800;
    font-size: 1.3rem;
    letter-spacing: -0.01em;
}
.shop-pass-modal .modal-title::before {
    content: '';
    flex: none;
    width: 24px;
    height: 24px;
    background-color: var(--pass-gold);
    -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M3%2018h18v2H3zM3%2016l-1-9%205.5%204L12%204l4.5%207L22%207l-1%209z%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M3%2018h18v2H3zM3%2016l-1-9%205.5%204L12%204l4.5%207L22%207l-1%209z%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
}
@media (max-width: 560px) {
    .shop-pass-banner { flex-direction: column; align-items: flex-start; gap: 14px; padding: 18px 18px 18px 22px; }
    /* Price on its own line, the button full width beneath it: side by
       side the two did not fit a phone and the button ran off the edge. */
    .shop-pass-banner-side { width: 100%; flex-direction: column; align-items: stretch; gap: 10px; }
    .shop-pass-banner-cta { justify-content: center; padding: 13px 18px; }
}

/* ---- The pass, full screen ------------------------------------------------
 *
 * A takeover rather than a dialog, on every size. The shape is the one used to
 * sell a subscription everywhere it is sold well: one column, one price list,
 * one button pinned to the bottom.
 *
 * It is OPAQUE, not a translucent scrim over the shop. A price list read
 * through a catalogue of 118 items is a price list nobody reads.
 */
body.shop-pass-open { overflow: hidden; }
.shop-pass-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    /* The base .modal centres a dialog inside 20px of padding. A takeover has
       no dialog to centre and no room to give away. */
    padding: 0;
    display: block;
}
.shop-pass-screen {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
    background: var(--c-page);
    color: var(--c-font);
}
/* Koma behind the whole screen, at the opacity of a watermark. */
.shop-pass-screen::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22132%22%20height%3D%22132%22%20viewBox%3D%220%200%20132%20132%22%3E%3Cg%20fill%3D%22%23b8860b%22%3E%3Cpath%20d%3D%22M30%2012%20L46%2020%20L50%2052%20L10%2052%20L14%2020%20Z%22%2F%3E%3Cpath%20d%3D%22M96%2034%20L112%2042%20L116%2074%20L76%2074%20L80%2042%20Z%22%20transform%3D%22rotate%2818%2096%2054%29%22%2F%3E%3Cpath%20d%3D%22M52%2082%20L66%2089%20L70%20116%20L34%20116%20L38%2089%20Z%22%20transform%3D%22rotate%28-13%2052%2099%29%22%2F%3E%3Cpath%20d%3D%22M118%20100%20L130%20106%20L133%20128%20L103%20128%20L106%20106%20Z%22%20transform%3D%22rotate%289%20118%20114%29%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
    background-size: 132px 132px;
    opacity: 0.045;
}
.shop-pass-screen > * { position: relative; z-index: 1; }

.shop-pass-screen-bar {
    flex: none;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--c-border);
}
.shop-pass-screen-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: inherit;
    cursor: pointer;
}
.shop-pass-screen-close:hover { background: var(--c-hover); }
.shop-pass-screen-state { margin-left: auto; font-size: 0.84rem; color: var(--c-font-dim); }
.shop-pass-screen-manage { margin-left: 8px; }
.shop-pass-screen-state + .shop-pass-screen-manage { margin-left: 8px; }
.shop-pass-screen-bar > .shop-pass-screen-manage:only-of-type { margin-left: auto; }

/* The scroller, so the button below never leaves the screen. */
.shop-pass-screen-scroll { flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.shop-pass-screen-inner {
    max-width: 640px;
    margin: 0 auto;
    padding: 28px 18px 24px;
}
.shop-pass-screen-title {
    margin: 0 0 6px;
    font-size: clamp(1.6rem, 5vw, 2.1rem);
    line-height: 1.15;
    letter-spacing: -0.02em;
}
.shop-pass-screen-lead { margin: 0 0 20px; color: var(--c-font-dim); font-size: 0.96rem; }

/* The footer: one button, thumb-height on a phone, and clear of the notch. */
.shop-pass-screen-foot {
    flex: none;
    border-top: 1px solid var(--c-border);
    padding: 12px 18px calc(12px + var(--inset-b));
    background: var(--c-page);
}
.shop-pass-cta {
    display: block;
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
    padding: 13px 18px;
    font-size: 1rem;
    font-weight: 700;
    border-radius: var(--radius-pill, 999px);
}
.shop-pass-screen-note {
    display: block;
    max-width: 640px;
    margin: 8px auto 0;
    text-align: center;
    font-size: 0.84rem;
    color: var(--c-font-dim);
}

/* ---- The pass ------------------------------------------------------------
 *
 * Above the catalogue on every tab, because it is not a kind of item - it is
 * the thing that pays for them. Louder than a shop row on purpose: it is the
 * one thing on this page with a recurring price, and it has to earn the look.
 *
 * The two items SHOW THEMSELVES. A row that said "Planeta" and "Aurora" was
 * asking the reader to know the catalogue by heart; the preview is the offer.
 */
.shop-pass {
    grid-column: 1 / -1;
    position: relative;
    overflow: hidden;
    border: 0;
    padding: 0;
    margin: 0;
    background: none;
}
/* Koma scattered behind the card.
 *
 * Its own layer rather than a third background on .shop-pass, because it needs
 * an opacity the gradient above it must not inherit - and because one dimmed
 * grey asset then serves both themes instead of two tinted ones.
 *
 * `pointer-events: none` and `aria-hidden` by construction: it is a pseudo
 * element, so it is already out of the accessibility tree and out of the way
 * of the buttons sitting on top of it. */
.shop-pass > * { position: relative; z-index: 1; }
.shop-pass-head { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; justify-content: space-between; }
.shop-pass-title {
    margin: 0;
    font-size: 1.2rem;
    letter-spacing: -0.01em;
}
.shop-pass-lead { margin: 5px 0 0; color: var(--c-font-dim, inherit); font-size: 0.95rem; line-height: 1.45; max-width: 52ch; }
.shop-pass-side { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
.shop-pass-price {
    font-weight: 800;
    font-size: 1.5rem;
    white-space: nowrap;
    line-height: 1;
    color: var(--pass-gold-deep);
}
.shop-pass-price span { font-weight: 400; font-size: 0.78rem; opacity: 0.7; color: var(--c-font); }
.shop-pass-state { font-size: 0.82rem; opacity: 0.75; }
/* Tier rows. A grid rather than flex so the marks, names, prices and buttons
   line up down the three rows: comparing prices is the job this list has, and
   ragged columns are what stop it being done at a glance. */
.shop-pass-tiers {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 0 0 24px;
}
/* Selectable, not clickable-to-buy: picking one only moves the ring, and the
   single button at the foot is what spends money. */
.shop-pass-tier {
    display: grid;
    grid-template-columns: 34px minmax(72px, auto) 1fr auto;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 14px 16px;
    border: 1px solid var(--c-border);
    border-radius: 14px;
    background: var(--c-box);
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.shop-pass-tier:hover { border-color: var(--c-border-soft, var(--c-border)); background: var(--c-hover); }
.shop-pass-tier.is-chosen {
    border-color: var(--c-accent);
    box-shadow: 0 0 0 1px var(--c-accent) inset;
}
.shop-pass-tier:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
/* Just a box to centre the seal in. It used to be a faint kanji of its own;
   the seal itself is what the tier actually grants, so the row shows that. */
.shop-pass-tier-mark { display: flex; align-items: center; justify-content: center; }
.shop-pass-tier-mark .title-badge {
    width: 28px;
    height: 28px;
    font-size: 16px;
    border-radius: 8px;
    margin: 0;
}
.shop-pass-tier-seal { color: var(--c-font); font-weight: 600; }
.shop-pass-tier-name { font-weight: 700; font-size: 1.02rem; }
.shop-pass-tier-perks {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.85rem;
    color: var(--c-font-dim);
    flex-wrap: wrap;
}
.shop-pass-tier-perks strong { font-weight: 700; color: var(--c-font); }
.shop-pass-tier-sep { opacity: 0.4; }
.shop-pass-tier-price { font-weight: 800; font-size: 1.1rem; white-space: nowrap; justify-self: end; }
.shop-pass-tier-price span { font-weight: 400; font-size: 0.7rem; color: var(--c-font-dim); }
.shop-pass-tier-current {
    grid-column: 2 / -1;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--c-accent);
}
/* Narrow.
 *
 * Everything is PLACED, not auto-flowed. The first attempt left a third `auto`
 * column and let the browser find somewhere for the price; with the perks
 * spanning to the end it landed in an implicit cell and, being `justify-self:
 * end`, hung off the left edge of the card - "R$ 1" outside the screen and
 * "9,90/mês" inside it. Two columns, one for the mark and one for everything
 * else, and each child told which one it belongs to. */
@media (max-width: 560px) {
    .shop-pass-tier {
        grid-template-columns: 32px 1fr;
        row-gap: 3px;
        padding: 12px 13px;
    }
    .shop-pass-tier-mark { grid-row: 1 / span 3; align-self: start; }
    .shop-pass-tier-name,
    .shop-pass-tier-perks,
    .shop-pass-tier-price,
    .shop-pass-tier-current { grid-column: 2; justify-self: start; }
    /* Stacked, so the middle dot has nothing left to separate. */
    .shop-pass-tier-perks { flex-direction: column; align-items: flex-start; gap: 1px; }
    .shop-pass-tier-sep { display: none; }
    .shop-pass-tier-price { margin-top: 2px; }
}
/* An item the week is showing but this tier does not reach. */
.shop-pass-item.is-above-tier { opacity: 0.55; }
.shop-pass-item.is-above-tier .shop-pass-item-free { opacity: 0.6; }

.play-invite-name-wrap { display: inline-flex; align-items: center; min-width: 0; }
/* The seal in a lobby row sits a shade smaller than on a profile: these rows
   are dense and a full-size seal changes their height. */
.play-recent-name + .title-badge,
.play-invite-name-wrap .title-badge,
.play-player-name .title-badge { width: 17px; height: 17px; font-size: 10px; border-radius: 5px; }

.shop-pass-titletest {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin: 0 0 20px;
    padding: 10px 12px;
    border: 1px dashed var(--c-border);
    border-radius: 12px;
}
.shop-pass-titletest-label { font-size: 0.8rem; color: var(--c-font-dim); }
.shop-pass-titletest-opts { display: flex; flex-wrap: wrap; gap: 6px; }
.shop-pass-titletest-opt { display: inline-flex; align-items: center; gap: 6px; }
.shop-pass-titletest-opt.is-current { border-color: var(--c-accent); color: var(--c-accent); }

.shop-pass-week {
    margin: 22px 0 10px;
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--pass-gold-deep);
}
body.dark-mode .shop-pass-week { color: var(--pass-gold); }
.shop-pass-items { display: flex; flex-direction: column; gap: 8px; }
.shop-pass-item {
    display: grid;
    grid-template-columns: 48px 1fr auto auto;
    align-items: center;
    gap: 14px;
    border: 1px solid var(--c-border);
    border-radius: 12px;
    padding: 9px 12px;
    background: var(--c-box);
}
@media (max-width: 560px) {
    /* Same fix, same reason: the button was auto-placed and overflowed. */
    .shop-pass-item { grid-template-columns: 44px 1fr; row-gap: 6px; }
    .shop-pass-item-body,
    .shop-pass-item-meta { grid-column: 2; justify-self: start; }
    .shop-pass-item > .shop-btn { grid-column: 2; justify-self: start; }
}
/* The preview tile is a fixed square whatever it holds - a ringed avatar, a
   coloured name, a face - so two items never sit at different heights. */
.shop-pass-item-preview {
    flex: none;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    background: var(--c-box-alt);
    overflow: hidden;
}
.shop-pass-item-preview img { border-radius: 50%; display: block; }
.shop-pass-sample {
    font-weight: 700;
    font-size: 0.95rem;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 0 4px;
}
.shop-pass-item-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.shop-pass-item-name { font-weight: 600; }
.shop-pass-item-meta { display: flex; align-items: center; gap: 9px; font-size: 0.78rem; white-space: nowrap; }
.shop-pass-item-was { opacity: 0.5; text-decoration: line-through; }
.shop-pass-item-free {
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--pass-gold-deep);
}
body.dark-mode .shop-pass-item-free { color: var(--pass-gold); }
@media (max-width: 560px) {
    .shop-pass-side { align-items: flex-start; }
    .shop-pass-item { flex: 1 1 100%; }
}

/* ---- The shop ------------------------------------------------------------
 *
 * Laid out sideways. Under the header, one strip says how kakera are
 * earned (four figures in a row) with the reader's own history folded at
 * its end; then the goods, grouped by kind behind iconed tabs, each one a
 * wide row: the thing previewed on the reader's own picture or name at the
 * left, its name and rarity in the middle, the price and the button at the
 * right. What is yours is said by a small tag on the name, not a ribbon. */
/* The same side gutter the header has, so nothing below it touches the edge. */
.content { --shop-gutter: 24px; }
@media (max-width: 640px) { .content { --shop-gutter: 14px; } }
.shop-icon { width: 1.05em; height: 1.05em; flex: none; vertical-align: -0.15em; }
/* No hairline under the header here: the tabs sit right under it. */
.shop-hero { align-items: center; border-bottom: 0; padding-bottom: 20px; }
.shop-purse {
    display: inline-flex; align-items: center; gap: 8px; margin: 0;
    padding: 10px 12px 10px 18px; border-radius: 999px;
    background: var(--c-box); border: 1px solid var(--c-border);
    font-size: 1rem; white-space: nowrap;
}
.shop-purse .kakera-glyph { width: 22px; height: 22px; color: var(--c-accent, #c8102e); }
.shop-purse strong { font-size: 1.5rem; line-height: 1; }

.shop-purse-wrap { position: relative; }
/* The two small controls in the purse: bare glyphs behind a hairline,
 * lit only under the pointer or while their balloon is open. */
.shop-purse-btn {
    display: inline-grid; place-items: center; width: 30px; height: 30px; margin: -4px 0 -4px 0;
    border-radius: 50%; border: 0; background: transparent;
    color: var(--c-font-dim); cursor: pointer; padding: 0;
    transition: background-color 120ms ease, color 120ms ease;
}
.shop-purse-btn:first-of-type { margin-left: 6px; padding-left: 0; position: relative; }
.shop-purse-btn:first-of-type::before { content: ''; position: absolute; left: -6px; top: 6px; bottom: 6px; width: 1px; background: var(--c-border); }
.shop-purse-btn .shop-icon { width: 17px; height: 17px; }
.shop-purse-btn:hover, .shop-purse-btn:focus-visible, .shop-purse-btn[aria-expanded="true"] { background: var(--c-box-alt); color: var(--c-accent, #c8102e); outline: none; }
.shop-purse-btn[hidden] { display: none; }
.shop-popover {
    position: absolute; right: 0; top: calc(100% + 8px); z-index: 30;
    width: min(380px, calc(100vw - 48px)); padding: 12px 14px;
    background: var(--c-box); border: 1px solid var(--c-border);
    border-radius: 12px; box-shadow: 0 14px 36px rgba(0,0,0,0.14); text-align: left;
}
.shop-popover[hidden] { display: none; }
.shop-popover-title { margin: 0 0 10px; font-size: 0.85rem; font-weight: 700; }
.shop-earn { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.shop-earn li { display: grid; grid-template-columns: 30px auto minmax(0, 1fr); align-items: center; gap: 10px; font-size: 0.84rem; line-height: 1.3; }
.shop-earn-icon { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; background: var(--c-box-alt); color: var(--c-accent, #c8102e); }
.shop-earn-icon .shop-icon { width: 16px; height: 16px; }
.shop-earn strong { white-space: nowrap; font-size: 1rem; min-width: 44px; }
.shop-earn li > span:last-child { color: var(--c-font-dim); }
.shop-ledger { list-style: none; margin: 0; padding: 0; max-height: 300px; overflow-y: auto; }
.shop-ledger li { display: grid; grid-template-columns: 1fr auto auto; gap: 10px; align-items: baseline; padding: 6px 0; border-bottom: 1px solid var(--c-border); font-size: 0.83rem; }
.shop-ledger li:last-child { border-bottom: 0; }
.shop-ledger-what { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shop-ledger-when { color: var(--c-font-dim); font-size: 0.75rem; }
.shop-ledger-amount.is-plus { color: var(--c-good, #15803d); font-weight: 700; }
.shop-ledger-amount.is-minus { color: var(--c-bad, #b91c1c); font-weight: 700; }

.shop-catalogue { margin: 22px var(--shop-gutter) 32px; }
.shop-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }
.shop-tab {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 14px; border-radius: 999px;
    border: 1px solid var(--c-border);
    background: transparent; color: inherit; font: inherit; font-size: 0.9rem; cursor: pointer;
}
.shop-tab[aria-selected="true"] { background: var(--c-accent, #c8102e); color: var(--c-on-accent); border-color: transparent; }
.shop-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: 10px 14px; }
@media (max-width: 480px) { .shop-grid { grid-template-columns: minmax(0, 1fr); } }
.shop-item {
    display: grid; grid-template-columns: 76px minmax(0, 1fr) auto; align-items: center; gap: 14px;
    padding: 12px 14px; border-radius: 12px;
    border: 1px solid var(--c-border);
    background: var(--c-box);
    transition: box-shadow 120ms ease;
}
.shop-item:hover { box-shadow: 0 6px 20px rgba(0,0,0,0.07); }
.shop-item[hidden] { display: none; }
.shop-item.is-owned { border-color: var(--c-accent, #c8102e); }
.shop-item.is-wearing { box-shadow: inset 0 0 0 2px var(--c-accent, #c8102e); }
.shop-item.is-short { opacity: 0.88; }
.shop-item-preview { display: grid; place-items: center; width: 76px; min-height: 64px; }
.shop-item-preview .avatar-frame { width: 56px; height: 56px; }
.shop-item-preview .avatar-frame img, .shop-item-preview img { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; display: block; }
.shop-name-preview { font-size: 1.15rem; font-weight: 700; line-height: 1.2; max-width: 76px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shop-perk-icon { width: 40px; height: 40px; color: var(--c-accent, #c8102e); }
.shop-item-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.shop-item-name { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-weight: 700; font-size: 0.98rem; }
.shop-item-state { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; background: var(--c-accent, #c8102e); color: var(--c-on-accent); }
.shop-item-state.is-wearing { background: var(--c-good); color: var(--c-page); }
.shop-item-state[hidden] { display: none; }
.shop-item-desc { font-size: 0.82rem; color: var(--c-font-dim); line-height: 1.3; }
.shop-item-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.shop-chip { display: inline-flex; align-items: center; gap: 3px; padding: 2px 8px; border-radius: 999px; font-size: 0.7rem; font-weight: 600; background: var(--c-box-alt); color: var(--c-font-dim); }
.shop-chip-tier-2 { background: rgba(59, 130, 246, 0.14); color: #1d4ed8; }
.shop-chip-tier-3 { background: rgba(184, 134, 11, 0.16); color: #92400e; }
.shop-chip-anim { background: rgba(200, 16, 46, 0.1); color: var(--c-accent, #c8102e); }
body.dark-mode .shop-chip-tier-2 { color: #93c5fd; }
body.dark-mode .shop-chip-tier-3 { color: #fcd34d; }
.shop-item-side { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.shop-item-price { font-weight: 700; font-size: 1.05rem; }
.shop-item-actions { display: flex; gap: 6px; justify-content: flex-end; }
.shop-btn { display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; border-radius: 999px; border: 1px solid var(--c-border); background: transparent; color: inherit; font: inherit; font-size: 0.85rem; cursor: pointer; white-space: nowrap; }
.shop-btn-primary { background: var(--c-accent, #c8102e); color: var(--c-on-accent); border-color: transparent; }
.shop-btn-owned { border-color: var(--c-accent, #c8102e); color: var(--c-accent, #c8102e); cursor: default; }
.shop-btn[disabled] { opacity: 0.55; cursor: not-allowed; }
.shop-btn[hidden] { display: none; }
.shop-empty { padding: 30px 10px; text-align: center; color: var(--c-font-dim); }

/* ---- Search, pages, shelves and the gift --------------------------------
 *
 * The additions that turned a wall of 260 cards back into a shop: one search
 * box over everything, 24 cards a page, and two shelves up top - what people
 * hold, and what fits this reader. All of it is drawn by shop.js; none of it
 * exists for a reader with scripting off, whose catalogue is complete below. */
.shop-toolbar { margin: 14px 0 10px; }
.shop-search-box {
    display: flex; align-items: center; gap: 10px;
    padding: 9px 14px; border-radius: 999px;
    border: 1px solid var(--c-border); background: var(--c-box-alt);
    color: var(--c-font-dim); cursor: text;
}
.shop-search-box:focus-within { border-color: var(--c-accent); color: var(--c-font); }
.shop-search-box .shop-icon { flex: 0 0 18px; width: 18px; height: 18px; }
.shop-search-box input {
    flex: 1 1 auto; min-width: 0; border: 0; background: none; outline: none;
    font: inherit; font-size: 0.95rem; color: var(--c-font);
}
.shop-pager {
    display: flex; align-items: center; justify-content: center; gap: 14px;
    margin: 18px 0 6px;
}
.shop-pager-label { font-size: 0.88rem; color: var(--c-font-dim); font-variant-numeric: tabular-nums; }
.shop-pager .shop-btn[disabled] { opacity: 0.45; cursor: default; }
/* A card the pager or a shelf just travelled to. */
@keyframes shop-item-flash { 0%, 60% { box-shadow: 0 0 0 2px var(--c-accent); } 100% { box-shadow: 0 0 0 2px transparent; } }
.shop-item.is-flash { animation: shop-item-flash 1.6s ease-out; }

.shop-rail { margin: 16px 0 6px; }
/* The signed-in gate turns any .logged-in-only into inline-flex, which laid
   the "for you" shelf's title BESIDE its cards. Put the block back - and
   keep `hidden` meaning hidden, which the blanket display rules break. */
body.is-logged-in .shop-rail.logged-in-only { display: block; }
.shop-rail[hidden] { display: none !important; }
.shop-rail-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 8px; }
.shop-rail-title {
    display: flex; align-items: center; gap: 7px;
    margin: 0; font-size: 0.82rem; font-weight: 700;
    letter-spacing: 0.06em; text-transform: uppercase; color: var(--c-font-dim);
}
.shop-rail-title .shop-icon { width: 16px; height: 16px; flex: 0 0 16px; opacity: 0.7; }
/* The arrows: for pointers that cannot drag a row sideways. Hidden where a
   finger can (coarse pointers), and hidden by shop.js when the shelf fits. */
.shop-rail-nav { display: none; gap: 4px; }
@media (hover: hover) and (pointer: fine) { .shop-rail-nav:not([hidden]) { display: inline-flex; } }
.shop-rail-arrow {
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px; border-radius: 50%;
    border: 1px solid var(--c-border); background: var(--c-box);
    color: var(--c-font-dim); cursor: pointer; padding: 0;
}
.shop-rail-arrow:hover { border-color: var(--c-accent); color: var(--c-font); }
.shop-rail-arrow[disabled] { opacity: 0.35; cursor: default; }
.shop-rail-arrow[disabled]:hover { border-color: var(--c-border); color: var(--c-font-dim); }
/* One row, scrolled sideways inside itself - the shelves must never make
   the page wider than the grid below them. The scrollbar is hidden: the
   cut-off card at the edge is the affordance, and a fat Windows bar under
   each shelf read as two broken sliders. */
.shop-rail-items {
    display: flex; gap: 8px; overflow-x: auto; padding: 2px;
    scrollbar-width: none;
}
.shop-rail-items::-webkit-scrollbar { display: none; }
.shop-rail-card {
    position: relative;
    flex: 0 0 auto; width: 122px; box-sizing: border-box;
    display: flex; flex-direction: column; align-items: center; gap: 4px;
    padding: 12px 8px 9px; border-radius: 12px;
    border: 1px solid var(--c-border); background: var(--c-box);
    color: var(--c-font); font: inherit; text-align: center; cursor: pointer;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.shop-rail-card:hover { border-color: var(--c-accent); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.07); }
/* The place, worn as a small seal in the corner rather than a row of its own. */
.shop-rail-rank {
    position: absolute; top: 5px; left: 7px;
    font-size: 0.64rem; font-weight: 800; line-height: 1;
    color: var(--c-font-dim); opacity: 0.75; font-variant-numeric: tabular-nums;
}
/* Overflow stays VISIBLE: a frame's ring (and the koma frames' orbiting
   glyph) draws outside the picture, and clipping it sold half the product.
   The text samples are four characters, so nothing here needs a fence. */
.shop-rail-card .shop-rail-preview {
    height: 46px; display: flex; align-items: center; justify-content: center;
    max-width: 100%;
}
.shop-rail-preview img { width: 30px; height: 30px; border-radius: 50%; object-fit: cover; }
.shop-rail-preview .shop-name-preview { font-size: 0.95rem; white-space: nowrap; }
.shop-rail-preview .shop-icon { width: 26px; height: 26px; opacity: 0.75; }
.shop-rail-name {
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 0.78rem; font-weight: 600; line-height: 1.25;
}
.shop-rail-meta {
    display: flex; align-items: center; justify-content: center; gap: 3px;
    font-size: 0.72rem; font-weight: 600; color: var(--c-font-dim); line-height: 1.2;
}
.shop-rail-meta .kakera-glyph { width: 11px; height: 11px; }
/* "{n} have it", its own quiet line under the price. */
.shop-rail-note { font-size: 0.66rem; color: var(--c-font-dim); opacity: 0.85; line-height: 1.2; }

/* The gift dialog: one small box, centred - the pass takeover would be a
   cannon for this. */
.shop-gift-modal { display: flex; align-items: center; justify-content: center; padding: 16px; background: rgba(0, 0, 0, 0.5); }
.shop-gift-box {
    width: min(440px, 100%); max-height: min(560px, 92vh); overflow-y: auto;
    box-sizing: border-box; padding: 16px 18px 18px; border-radius: 16px;
    background: var(--c-box); border: 1px solid var(--c-border);
    box-shadow: var(--elev-2);
}
.shop-gift-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 4px; }
.shop-gift-title { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 1.05rem; }
.shop-gift-title .shop-icon { width: 20px; height: 20px; }
.shop-gift-close { border: 0; background: none; color: var(--c-font-dim); cursor: pointer; padding: 4px; border-radius: 8px; }
.shop-gift-close:hover { background: var(--c-hover); color: var(--c-font); }
.shop-gift-lead { margin: 0 0 10px; font-size: 0.86rem; color: var(--c-font-dim); }
.shop-gift-none { margin: 8px 0; font-size: 0.88rem; color: var(--c-font-dim); }
.shop-gift-people { display: flex; flex-direction: column; gap: 4px; margin: 0 0 12px; }
.shop-gift-person {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 8px 10px; border-radius: 10px; border: 1px solid transparent;
    background: none; color: var(--c-font); font: inherit; text-align: left; cursor: pointer;
}
.shop-gift-person:hover { background: var(--c-hover); }
.shop-gift-person.is-chosen { border-color: var(--c-accent); background: var(--c-accent-soft); }
.shop-gift-person img { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; flex: 0 0 32px; }
.shop-gift-person-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.shop-gift-row { display: flex; align-items: flex-end; gap: 10px; }
.shop-gift-amount { display: flex; flex-direction: column; gap: 4px; flex: 1 1 auto; font-size: 0.8rem; color: var(--c-font-dim); }
.shop-gift-amount input {
    width: 100%; box-sizing: border-box; padding: 8px 10px; border-radius: 10px;
    border: 1px solid var(--c-border); background: var(--c-box-alt);
    font: inherit; font-size: 1rem; color: var(--c-font);
}
.shop-gift-amount input:focus { outline: none; border-color: var(--c-accent); }

/* A locked perk on the profile: the banner control that needs the shop. */
.profile-banner-edit.is-locked { opacity: 0.85; }


.profile-frame-btn {
    display: inline-flex; align-items: center; gap: 6px;
    margin-top: 8px; padding: 4px 10px;
    border-radius: 999px; border: 1px solid var(--c-border);
    background: transparent; color: inherit; font: inherit; font-size: 0.82rem; cursor: pointer;
}
.profile-frame-btn:hover { border-color: var(--c-accent, #c8102e); }
.frame-picker { display: flex; flex-wrap: wrap; gap: 10px; margin: 10px 0 4px; }
.frame-picker-option {
    width: 46px; height: 46px; border-radius: 50%; padding: 0;
    border: 1px solid var(--c-border);
    background: var(--c-box-alt);
    cursor: pointer; position: relative;
}
.frame-picker-option.is-active { outline: 2px solid var(--c-accent, #c8102e); outline-offset: 3px; }
.frame-picker-option.is-locked { opacity: 0.35; cursor: not-allowed; }
.frame-picker-option.is-locked::after { content: ''; position: absolute; inset: 0; margin: auto; width: 14px; height: 14px; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='5' y='10' width='14' height='11' rx='2'/%3E%3Cpath d='M8 10V7a4 4 0 0 1 8 0v3' fill='none' stroke='%23000' stroke-width='2.4'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='5' y='10' width='14' height='11' rx='2'/%3E%3Cpath d='M8 10V7a4 4 0 0 1 8 0v3' fill='none' stroke='%23000' stroke-width='2.4'/%3E%3C/svg%3E") center / contain no-repeat; }

/* ---- Player card --------------------------------------------------------- */

.player-card-modal { position: fixed; inset: 0; z-index: 1200; display: grid; place-items: center; background: rgba(0,0,0,0.55); padding: 16px; }
.player-card-modal[hidden] { display: none; }
.player-card-box { background: var(--c-box); color: var(--c-font); border-radius: 10px; padding: 14px; max-width: min(720px, 100%); width: 100%; box-shadow: 0 20px 60px rgba(0,0,0,0.35); }
.player-card-box img, .player-card-box canvas { display: block; width: 100%; height: auto; border-radius: 6px; }
.player-card-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; margin-top: 10px; }
.profile-card-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px; border-radius: 999px;
    border: 1px solid var(--c-border);
    background: transparent; color: inherit; font: inherit; font-size: 0.88rem; cursor: pointer;
}
.profile-card-btn:hover { border-color: var(--c-accent, #c8102e); }

/* ---- Tsume of the day and Tsume Rush ------------------------------------- */

/* Everything in this band shares the 24px inset .tsume-lengths and
   .tsume-layout carry; without it the date and the score sat on the raw
   edge of the page. */
.tsume-rush-hud { display: flex; gap: 18px; align-items: baseline; margin: 10px 24px 4px; font-variant-numeric: tabular-nums; }
.tsume-rush-hud strong { font-size: 1.6rem; }
.tsume-rush-hud .is-low { color: var(--c-bad, #b91c1c); animation: board-fx-clock 1s infinite; }
body[data-tsume-mode="rush"] [data-tsume-hint], body[data-tsume-mode="rush"] [data-tsume-solution] { display: none; }
.tsume-daily-date { font-size: 0.9rem; color: var(--c-font-dim); margin: 0 24px 6px; }

/* ---- Several recipes per seat in the opening editor --------------------- */

.opening-recipe-bar { margin: 6px 0 10px; }
.opening-recipe-tabs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.opening-recipe-label { font-size: 0.85rem; color: var(--c-font-dim); margin-right: 2px; }
.opening-recipe-tab {
    padding: 3px 10px; border-radius: 999px;
    border: 1px solid var(--c-border);
    background: transparent; color: inherit; font: inherit; font-size: 0.85rem; cursor: pointer;
}
.opening-recipe-tab.is-active { background: var(--c-accent, #c8102e); color: var(--c-on-accent); border-color: transparent; }
.opening-recipe-add { border-style: dashed; }
.opening-recipe-title-row { display: flex; gap: 8px; align-items: center; margin-top: 6px; }
.opening-recipe-title {
    flex: 1 1 auto; min-width: 0; padding: 5px 8px;
    border: 1px solid var(--c-border); border-radius: 4px;
    font: inherit; font-size: 0.9rem; background: transparent; color: inherit;
}
.opening-recipe-remove { flex: 0 0 auto; font-size: 0.8rem; }
.tsume-modes { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 0; }
.tsume-mode {
    padding: 4px 12px; border-radius: 999px; text-decoration: none;
    border: 1px solid var(--c-border); color: inherit; font-size: 0.88rem;
}
.tsume-mode.is-current { background: var(--c-accent, #c8102e); color: var(--c-on-accent); border-color: transparent; }

/* The sidebar account row: the picture, then the name with the kakera
 * balance right under it. */
.sidebar-auth-user { align-items: center; }
/* The name and the balance share one left edge: the name used to hug the
 * picture with a negative margin of its own; the column carries it now. */
/* Room for a frame's ring (and an orbiting piece) between the picture
 * and the text: the old -13px hug put the name on top of them. */
.sidebar-auth-meta { display: flex; flex-direction: column; min-width: 0; gap: 0; margin-left: -4px; }
/* Both lines are nav links, which carry the rail's vertical padding;
 * stacked, that padding read as a gap. Neither line gets any here. */
.sidebar-auth-meta .sidebar-auth-name { margin: 0; padding: 0; line-height: 1.2; min-height: 0; }
.sidebar-auth-meta .sidebar-kakera { margin: 1px 0 0; padding: 0; line-height: 1.2; min-height: 0; }
/* The framed picture keeps the link's box; the ring hangs just outside it. */
.sidebar-auth-avatar-link .avatar-frame { width: 100%; height: 100%; display: block; }
.sidebar-auth-avatar-link .avatar-frame > img { width: 100%; height: 100%; }

/* The name-style picker under the profile picture's menu. */
.style-picker-title { margin: 10px 0 4px; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--c-font-dim); }
.style-picker { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.style-picker-option {
    padding: 5px 12px; border-radius: 999px;
    border: 1px solid var(--c-border);
    background: var(--c-box); color: inherit; font: inherit; font-size: 0.95rem; font-weight: 700; cursor: pointer;
}
.style-picker-option.is-active { outline: 2px solid var(--c-accent, #c8102e); outline-offset: 2px; }
.style-picker-more { font-size: 0.82rem; margin-left: 4px; }
.profile-banner.is-locked .profile-banner-edit { cursor: pointer; }

/* ---- The appearance page ----------------------------------------------------
 *
 * The shop's own furniture - its tabs, its rows, its buttons - holding only
 * what the account can wear, so dressing the account looks like the place
 * the clothes came from. The live preview sits in the header where the
 * shop keeps its purse. */
.appear-page { margin: 22px var(--shop-gutter) 40px; }
.appear-grid[hidden] { display: none; }
.appear-preview {
    display: flex; align-items: center; gap: 16px; min-width: 280px;
    margin: 0; padding: 14px 18px; border-radius: 14px;
    background: var(--c-box); border: 1px solid var(--c-border);
}
.appear-preview-avatar, .appear-preview .avatar-frame > img { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; display: block; }
.appear-preview .avatar-frame { margin: 5px; }
.appear-preview-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.appear-preview-name { font-size: 1.35rem; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.appear-preview-hint { font-size: 0.8rem; color: var(--c-font-dim); }
.appear-option .shop-name-preview { max-width: 76px; }
.appear-empty { grid-column: 1 / -1; padding: 14px 4px; text-align: left; }
.appear-more {
    text-decoration: none; color: inherit;
    border-style: dashed; background: transparent;
}
.appear-more:hover { border-color: var(--c-accent, #c8102e); box-shadow: none; }
.appear-more .shop-item-name { color: var(--c-font-dim); font-weight: 600; }
.appear-more:hover .shop-item-name { color: var(--c-accent, #c8102e); }
.appear-more-icon { color: var(--c-accent, #c8102e); }
.appear-more-icon .shop-icon { width: 26px; height: 26px; }
@media (max-width: 640px) { .shop-hero { flex-direction: column; align-items: stretch; } .appear-preview { min-width: 0; } }

/* A hero action with a drawn mark before its word. */
.home-cta-iconed { display: inline-flex; align-items: center; gap: 8px; }
.home-cta-iconed .shop-icon { width: 18px; height: 18px; flex: none; }

/* kakera for money: the pack rows and the purse's "+". */
.shop-pack-preview { display: flex; flex-direction: column; align-items: center; gap: 2px; color: var(--c-accent, #c8102e); }
.shop-pack-preview .kakera-glyph { width: 26px; height: 26px; }
.shop-pack-preview strong { font-size: 1.05rem; color: var(--c-font); }
.shop-pack-note { margin: 4px 0 0; padding: 8px 4px; text-align: left; }
.shop-pack-note[hidden] { display: none; }
.shop-purse-plus { text-decoration: none; }
.shop-purse-plus:hover { color: var(--c-accent, #c8102e); }
.shop-tab-kakera { margin-left: auto; }

/* On a phone the purse sat at the right of an empty row, its "buy" button
   under it at another width, and the kakera tab below repeated the same
   words in a third size. One column: purse full width, its button full
   width beneath it, and the tab reads as a tab like the others. */
@media (max-width: 900px) {
    .shop-hero { align-items: stretch; }
    .shop-purse-wrap { width: 100%; }
    .shop-purse { display: flex; width: 100%; box-sizing: border-box; }
    .shop-purse strong { flex: 1 1 auto; }
    .shop-purse-buy {
        display: inline-flex; width: 100%; box-sizing: border-box;
        justify-content: center; margin-top: 10px; min-height: 44px;
    }
    .shop-tab { min-height: 40px; }
    .shop-tab-kakera { margin-left: 0; }
    .shop-popover { right: auto; left: 0; width: min(380px, 100%); }
}

/* ---- The roulette ---------------------------------------------------------
 *
 * A strip of cards slid under a pointer with a long ease-out; the prize the
 * server drew is the card that stops there. Reduced motion jumps straight
 * to it. */
.roulette-panel { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 10px; }
.roulette-panel[hidden] { display: none; }
.roulette-viewport { position: relative; overflow: hidden; border-radius: 12px; background: var(--c-box-alt); border: 1px solid var(--c-border); }
.roulette-pointer { position: absolute; top: 0; bottom: 0; left: 50%; width: 2px; margin-left: -1px; background: var(--c-accent); z-index: 2; pointer-events: none; }
.roulette-pointer::before, .roulette-pointer::after { content: ''; position: absolute; left: 50%; margin-left: -7px; border: 7px solid transparent; }
.roulette-pointer::before { top: 0; border-top: 9px solid var(--c-accent); }
.roulette-pointer::after { bottom: 0; border-bottom: 9px solid var(--c-accent); }
.roulette-reel { display: flex; gap: 8px; padding: 14px 12px; will-change: transform; }
.roulette-card {
    flex: 0 0 116px; display: flex; flex-direction: column; align-items: center; gap: 6px;
    padding: 10px 8px 8px; border-radius: 10px;
    background: var(--c-box); border: 1px solid var(--c-border);
}
.roulette-card-tier-2 { border-color: rgba(59, 130, 246, 0.45); }
.roulette-card-tier-3 { border-color: rgba(184, 134, 11, 0.6); }
.roulette-card.is-prize { box-shadow: 0 0 0 2px var(--c-accent); }
.roulette-card-preview { display: grid; place-items: center; height: 56px; }
.roulette-card-preview img, .roulette-card-preview .avatar-frame > img { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; display: block; }
.roulette-card-preview .avatar-frame { margin: 4px; }
.roulette-sample { font-size: 1rem; font-weight: 700; max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.roulette-card-name { font-size: 0.72rem; color: var(--c-font-dim); max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.roulette-result { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px; margin: 0; padding: 6px 0 2px; font-weight: 600; }
.roulette-result[hidden] { display: none; }

/* Short of kakera, a buy button is a way to the packs, not a dead end. */
.shop-btn-short { border-color: var(--c-accent); color: var(--c-accent); background: transparent; }
.shop-btn-short:hover { background: var(--c-accent); color: var(--c-on-accent); }
.shop-purse-wrap { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
a.shop-btn, .shop-purse-buy { text-decoration: none; }
.shop-purse-buy { padding: 9px 16px; font-size: 0.92rem; }


/* --- The card on hover ------------------------------------------------
   A person's picture, anywhere, held under the pointer for a moment: their
   card, above the picture if there is room and below it if not. It is a
   link to the profile like the picture is, so the pointer can move onto it
   and click. Fixed, so a scrolling list does not carry it away; player-
   card.js hides it on scroll. */
.player-card-pop {
    position: fixed;
    z-index: 96;
    display: block;
    width: 420px;
    border-radius: 14px;
    overflow: hidden;
    background-color: #1b1410;
    box-shadow: var(--elev-2, 0 12px 32px rgba(0, 0, 0, 0.35));
    animation: player-card-pop-in 0.14s ease;
}
.player-card-pop[hidden] { display: none; }
.player-card-pop img { display: block; width: 100%; height: auto; }
@keyframes player-card-pop-in {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .player-card-pop { animation: none; } }

/* --- The kakera on the end-of-game card ------------------------------
   Beside the rating figure: the stone and the amount, counted up from
   nothing once the rating has landed, with the accuracy that set it in the
   chip beneath. The number lifts and glows gold as it lands. */
.play-endcard-kakera { margin-left: 6px; padding-left: 12px; border-left: 1px solid rgba(255, 255, 255, 0.14); }
.play-endcard-kakera-number {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: #f2c14e;
    transition: transform 0.36s cubic-bezier(0.2, 1.6, 0.4, 1), text-shadow 0.4s ease;
}
.play-endcard-kakera-number .kakera-glyph { width: 20px; height: 20px; opacity: 0.9; }
.play-endcard-kakera-number.is-counting { transform: scale(1.04); }
.play-endcard-kakera-number.is-paid {
    transform: scale(1.1);
    text-shadow: 0 0 12px rgba(242, 193, 78, 0.55);
    animation: play-endcard-kakera-pop 0.5s cubic-bezier(0.2, 1.6, 0.4, 1);
}
.play-endcard-kakera-why { background: rgba(242, 193, 78, 0.16); color: #f2c14e; }
@keyframes play-endcard-kakera-pop {
    0% { transform: scale(1.04); }
    55% { transform: scale(1.22); }
    100% { transform: scale(1.1); }
}
@media (prefers-reduced-motion: reduce) {
    .play-endcard-kakera-number, .play-endcard-kakera-number.is-paid { transition: none; animation: none; transform: none; }
}

/* ---- Tsume of the day: levels and the day's ranking ------------------- */
.tsume-daily-levels { margin-bottom: 4px; }
/* The date and the day's tally on one quiet line under the pills, indented
   with them rather than glued to the page edge. */
.tsume-daily-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 14px;
    margin: 4px 0 6px;
    padding: 0 24px;
}
.tsume-daily-meta .tsume-daily-date,
.tsume-daily-meta .tsume-daily-score { margin: 0; }
.tsume-daily-check {
    display: inline-block;
    margin-left: 6px;
    color: #15803d;
    font-weight: 700;
}
body.dark-mode .tsume-daily-check { color: #4ade80; }
.tsume-lengths .tsume-length.is-solved { border-color: rgba(21, 128, 61, 0.5); }
.tsume-daily-score {
    font-size: 0.9rem;
    color: var(--c-font-dim);
    margin: 0 0 6px;
    font-variant-numeric: tabular-nums;
}
/* The reader's own row on today's ranking. */
.tsume-rank-row-me { outline: 2px solid var(--c-accent); outline-offset: 1px; }
/* The phone inset is 16px (see the .tsume-lengths block); these rules sit
   after that media layer in the file, so they restate it for themselves. */
@media (max-width: 900px) {
    .tsume-daily-meta { padding-left: 16px; padding-right: 16px; }
    .tsume-rush-hud, .tsume-daily-date { margin-left: 16px; margin-right: 16px; }
    .tsume-daily-meta .tsume-daily-date { margin: 0; }
}

/* /solicit/removeaccount - the deletion form. The fields are the auth
   dialog's; only the layout around them belongs to this page, plus a red
   button: the one button on the site whose click cannot be taken back. */
.remove-account-form {
    display: flex;
    flex-direction: column;
    gap: 14px;
    max-width: 420px;
    margin: 12px 0 8px;
}
.remove-account-confirm {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 0.92em;
    cursor: pointer;
}
.remove-account-confirm input {
    margin-top: 3px;
    accent-color: #b3261e;
}
.remove-account-submit,
body.dark-mode .remove-account-submit {
    background-color: #b3261e;
    color: #ffffff;
    align-self: flex-start;
}
.remove-account-form .auth-error { text-align: left; }
.remove-account-done {
    max-width: 420px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 10px;
    padding: 12px 16px;
}
body.dark-mode .remove-account-done { border-color: rgba(255, 255, 255, 0.18); }

/* ---- Controls on a phone: tsume, the drill, the lobby -------------------
 *
 * Every control on these pages was a pill sized by its own label, and on a
 * narrow screen that left ragged rows with a strip of dead space down the
 * right of each one: "dica" 90px wide next to "ver a solução" at 220, and
 * "qualquer tamanho" and "9 lances" trying to share a grid they were never
 * given. Below 900px the rows become grids instead - the buttons take the
 * whole width the page has, in equal shares, and their text is centred in
 * the box rather than sitting where the padding leaves it.
 *
 * The pill rows are scoped to the tsume page: .tsume-lengths is the shared
 * filter control, and the activity feed and the ranking tabs want theirs to
 * stay the width of their labels. .tsume-actions is not scoped, because the
 * opening drill is the same panel with the same three buttons and the two
 * pages are meant to read as one thing. */
@media (max-width: 900px) {
    /* The three ways in. They grow to share whatever the row has, so the set
       finishes flush at the right edge in every language rather than
       trailing off after the shortest label. */
    body[data-tsume-page] .tsume-mode {
        flex: 1 1 auto;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-height: 44px;
        padding: 4px 10px;
        text-align: center;
    }

    /* The lengths, two to a row. "qualquer tamanho" is the reset rather than
       one of the shelves, and it is twice the width of the four figures
       beside it, so it takes a row of its own instead of squeezing the
       first column. The day's levels are four, which is the grid exactly. */
    body[data-tsume-page] .tsume-lengths {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
    }
    body[data-tsume-page] .tsume-length {
        justify-content: center;
        text-align: center;
        padding: 10px 12px;
    }
    body[data-tsume-page] .tsume-length[data-tsume-length="any"] { grid-column: 1 / -1; }

    /* Hint and reveal share a row; the primary action takes one of its own,
       because it is the one a thumb reaches for between problems and it
       should not be a half-width target beside a button that undoes the
       problem. */
    .tsume-actions {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
    }
    .tsume-actions .home-cta {
        box-sizing: border-box;
        justify-content: center;
        text-align: center;
        min-height: 48px;
        padding: 11px 12px;
    }
    .tsume-actions .home-cta-primary { grid-column: 1 / -1; }

    /* The promotion question sits between the board and the komadai and asks
       for one of two taps. The question takes its own line so the two
       answers can split the row evenly under it. */
    .tsume-promotion p { flex: 1 1 100%; }
    .tsume-promotion .home-cta {
        flex: 1 1 0;
        justify-content: center;
        min-height: 44px;
    }

    /* The signed-out call to action is the only button in its row here, so
       it takes the row. */
    body[data-tsume-page] .home-hero-actions .home-cta { width: 100%; }
}

/* ---- The lobby hero once it stacks -------------------------------------
 *
 * Under 820px .home-hero turns into a column, but .play-hero keeps the
 * `align-items: center` it is given for the desktop row - which in a column
 * is the CROSS axis, so the text block shrink-wrapped to its own longest
 * line and sat in the middle of the page. On a 768px tablet that made every
 * button in the hero 340px wide with 210px of empty page on either side.
 * The block takes the width it is given; the board below it keeps centring
 * itself, which is what `align-self` on .home-showcase is already for. */
@media (max-width: 820px) {
    .play-hero { align-items: stretch; }
    .play-hero .home-hero-text { width: 100%; }
    /* The 46ch cap is what the lead needs on a desktop row and what was
       holding the column narrow here. */
    .play-hero .home-hero-intro { max-width: none; }
    .play-hero .home-showcase { align-self: center; }
    /* Same for the tsume and studies heroes, which stack the same way. */
    .studies-hero { align-items: stretch; }
    .studies-hero .home-hero-text { width: 100%; }
    .studies-hero .tsume-stats { flex: 0 0 auto; }
}
