:root {
    color-scheme: light;
    --bg: #f4f8fb;
    --bg-accent: #eaf2f7;
    --panel: rgba(255, 255, 255, 0.78);
    --panel-strong: rgba(255, 255, 255, 0.94);
    --line: rgba(12, 30, 50, 0.1);
    --text: #0c1626;
    --muted: #586478;
    --accent: #06b6d4;
    --accent-2: #14b8a6;
    --accent-3: #7c3aed;
    --danger: #e8486a;
    --glow: rgba(6, 182, 212, 0.35);
    --glow-soft: rgba(6, 182, 212, 0.14);
    --shadow: 0 18px 44px rgba(12, 30, 50, 0.08);
    --radius: 12px;
    --font-display: "Orbitron", "Rajdhani", ui-sans-serif, system-ui, sans-serif;
    --font-body: "Rajdhani", "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

/* Chinese (zh) typography overrides. DingTalk JinBuTi 钉钉进步体 is a free
   geometric/sci-fi Chinese display face that pairs cleanly with Orbitron's
   wide caps; Noto Sans SC is the universally-supported body face. Both
   fall back through the Latin stack for any glyphs they don't cover (e.g.
   the flower code's ASCII characters render in JetBrains Mono / Orbitron
   even on a Chinese page). */
html[lang="zh"] {
    --font-display: "DingTalk JinBuTi", "Orbitron", "Noto Sans SC", "Rajdhani", ui-sans-serif, system-ui, sans-serif;
    --font-body: "Noto Sans SC", "Rajdhani", "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

/* Orbitron's wide 0.14–0.22em letter-spacing reads as cyberpunk caps in
   English but looks too airy / broken when applied to CJK glyphs. Dial
   it back across the page when the active language is zh. */
html[lang="zh"] .eyebrow,
html[lang="zh"] .section-label,
html[lang="zh"] .name-label,
html[lang="zh"] .login-divider,
html[lang="zh"] .pill {
    letter-spacing: 0.08em;
}

html[lang="zh"] .title,
html[lang="zh"] .modal-title,
html[lang="zh"] .ghost-button,
html[lang="zh"] .primary-button,
html[lang="zh"] .user-name,
html[lang="zh"] .ghost-button.small {
    letter-spacing: 0.06em;
}

/* Buttons on zh pages don't need uppercase (Chinese has no case). Apply
   `text-transform: none` only to the labels that were uppercased for the
   Latin display — the typography variables already handle font swapping. */
html[lang="zh"] .ghost-button,
html[lang="zh"] .primary-button,
html[lang="zh"] .eyebrow,
html[lang="zh"] .section-label,
html[lang="zh"] .name-label,
html[lang="zh"] .login-divider,
html[lang="zh"] .pill,
html[lang="zh"] .modal-title,
html[lang="zh"] .user-name {
    text-transform: none;
}

* {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    height: 100%;
    color: var(--text);
    font-family: var(--font-body);
}

/* Paint the gradient ONCE on <html> so every transparent descendant (including
   the flower canvas wrapper and stage) inherits the exact same backdrop. This
   prevents any visible seam between the canvas area and its host container. */
/* Cooler page gradient. We deliberately do NOT paint a tiled dot grid here:
   on long scrolling pages (the garden gallery) a tiled radial-gradient on
   <html> repaints every scroll frame and produces visible jank. The
   horizon-style radial accents below are stationary, large, and cheap. */
html {
    background:
        radial-gradient(ellipse 120% 70% at 50% -5%, rgba(6, 182, 212, 0.10), transparent 45%),
        radial-gradient(ellipse 80% 50% at 92% 8%, rgba(20, 184, 166, 0.08), transparent 42%),
        radial-gradient(ellipse 70% 45% at 6% 92%, rgba(124, 58, 237, 0.06), transparent 45%),
        linear-gradient(180deg, #ffffff 0%, #f4f9fc 45%, #eef4f9 100%);
}

body {
    min-height: 100vh;
    background: transparent;
}

button,
textarea {
    font: inherit;
}

.app-shell {
    height: 100vh;
    max-height: 100vh;
    overflow: hidden;
    padding: 16px;
    display: grid;
    grid-template-rows: auto 1fr;
    gap: 12px;
}

/* No-topbar variant removes chrome around the stage so the flower canvas
   blends seamlessly with the page background. */
.app-shell.no-topbar {
    padding: 0;
    gap: 0;
    grid-template-rows: 1fr;
}

/* ?? Flower-first stage layout (index.html) ????????????????????????????????? */

/* Vertical clearance reserved at the bottom of the stage for the dialogue
   card.  The canvas itself spans the full viewport (so loading bubbles can
   travel all the way from the listening pill to the plant root); the
   renderer reads --dialogue-clearance via getComputedStyle and lifts its
   internal `groundY` by that amount so the plant stays above the
   dialogue card instead of being hidden behind it.  Tweak this value to
   move both the plant baseline and the dialogue card's reserved area. */
.stage-layout {
    --dialogue-clearance: 168px;
    position: relative;
    min-height: 0;
    overflow: hidden;
    /* Transparent + no border so the canvas inherits the body's gradient
       and there is no visible "panel" edge around the flower. */
    background: transparent;
    border: 0;
    border-radius: 0;
}

.full-stage {
    position: absolute;
    inset: 0;
    display: grid;
    min-height: 0;
}

.full-canvas,
.canvas-wrap.full-canvas {
    width: 100%;
    height: 100%;
    min-height: 0;
    /* Aggressively strip any chrome so the flower blends seamlessly with the
       page gradient ??the !importants defeat the base .canvas-wrap rules
       further down without needing selector order gymnastics. */
    border-radius: 0 !important;
    border: 0 !important;
    background: transparent !important;
    box-shadow: none !important;
    overflow: visible;
}

.dialogue-float {
    position: absolute;
    left: 50%;
    bottom: 18px;
    transform: translateX(-50%);
    width: min(460px, calc(100% - 32px));
    z-index: 20;
    display: grid;
    gap: 8px;
    pointer-events: none; /* children re-enable */
    transition: width 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

.dialogue-float > * { pointer-events: auto; }

.floating-card {
    background: rgba(255, 255, 255, 0.58);
    backdrop-filter: blur(22px) saturate(1.3);
    -webkit-backdrop-filter: blur(22px) saturate(1.3);
    /* Subtle cyan-tinted border — the only obvious "futuristic" mark on the
       game page. Combined with the inset cyan top edge below it reads as a
       thin HUD panel rather than a soft glass pill. */
    border: 1px solid rgba(6, 182, 212, 0.28);
    box-shadow:
        0 12px 36px rgba(12, 30, 50, 0.1),
        0 2px 6px rgba(12, 30, 50, 0.04),
        0 0 26px var(--glow-soft),
        inset 0 1px 0 rgba(6, 182, 212, 0.42);
}

.compact-card {
    padding: 12px 14px 10px;
    border-radius: 14px;
    display: grid;
    gap: 8px;
}

.dialogue-float .question-text {
    margin: 0;
    font-size: 15px;
    line-height: 1.4;
    color: var(--muted);
    font-weight: 500;
    letter-spacing: 0.01em;
    padding: 0 2px;
    max-height: 4.2em;
    overflow-y: auto;
}

.input-row {
    position: relative;
    display: block;
}

.dialogue-float textarea {
    width: 100%;
    min-height: 54px;
    max-height: 160px;
    resize: none;
    padding: 12px 56px 12px 14px;
    font-family: var(--font-body);
    font-size: 15px;
    line-height: 1.4;
    letter-spacing: 0.005em;
    border-radius: 10px;
    border: 1px solid rgba(12, 30, 50, 0.08);
    background: rgba(255, 255, 255, 0.85);
    color: var(--text);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.dialogue-float textarea::placeholder {
    color: rgba(88, 100, 120, 0.55);
    font-style: italic;
}

.dialogue-float textarea:focus {
    outline: none;
    border-color: rgba(6, 182, 212, 0.55);
    box-shadow: 0 0 0 3px var(--glow-soft), 0 0 18px var(--glow-soft);
}

/* The send / save button lives inside the textarea's right padding, rendered
   as a chrome-less icon so it feels like part of the input, not a separate
   control stuck on top of it. */
.send-button {
    position: absolute;
    right: 6px;
    bottom: 6px;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 0;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.12s ease, background 0.12s ease, opacity 0.12s ease;
}

.send-button:hover:not(:disabled) {
    color: var(--accent);
    background: rgba(6, 182, 212, 0.08);
}

.send-button:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

.send-button.save-variant {
    color: var(--accent-2);
}

.send-button.save-variant:hover:not(:disabled) {
    color: var(--accent-2);
    background: rgba(20, 184, 166, 0.10);
}

/* Brief loading indicator on the save button (used during DB write). The
   submit flow uses the collapsed-card state instead. */
.send-button.save-variant.is-loading {
    cursor: wait;
    animation: send-pulse 1.6s ease-in-out infinite;
}

/* Answer option chips — populated by renderOptions() into #answer-options.
   Flex-wrap so 2–3 tappable chips flow naturally.
   :empty hides the container and its sibling divider when no options exist. */
.answer-options {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.answer-options:empty {
    display: none;
}

.option-btn {
    flex: 0 1 auto;
    padding: 6px 12px;
    border-radius: 8px;
    border: 1px solid var(--line);
    background: rgba(255, 255, 255, 0.65);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: 0.005em;
    cursor: pointer;
    text-align: left;
    transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}

.option-btn:hover:not(:disabled) {
    border-color: rgba(6, 182, 212, 0.5);
    background: rgba(6, 182, 212, 0.06);
    box-shadow: 0 0 10px var(--glow-soft);
}

.option-btn:active:not(:disabled) {
    background: rgba(6, 182, 212, 0.12);
}

/* "or write your own" label — sits between the chips and the textarea.
   Hidden automatically via adjacent-sibling selector when options are absent. */
.options-divider {
    margin: 0;
    font-size: 11px;
    font-family: var(--font-body);
    color: var(--muted);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    opacity: 0.55;
}

.answer-options:empty + .options-divider {
    display: none;
}

/* ?? Floating stage controls (overlaid on the flower canvas) ???????????????? */

.stage-controls {
    position: absolute;
    top: 14px;
    z-index: 30;
    display: flex;
    gap: 8px;
    align-items: flex-start;
    pointer-events: none;
}

.stage-controls > * { pointer-events: auto; }

.stage-controls-left  { left: 14px; }
.stage-controls-right { right: 14px; }

.icon-button {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.55);
    background: rgba(255, 255, 255, 0.72);
    backdrop-filter: blur(14px) saturate(1.2);
    -webkit-backdrop-filter: blur(14px) saturate(1.2);
    color: var(--text);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 12px rgba(12, 30, 50, 0.08);
    text-decoration: none;
    padding: 0;
    overflow: hidden;
    transition: background 0.15s ease, transform 0.12s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.icon-button:hover {
    background: rgba(255, 255, 255, 0.94);
    border-color: rgba(6, 182, 212, 0.45);
    box-shadow: 0 4px 12px rgba(12, 30, 50, 0.08), 0 0 14px var(--glow-soft);
    transform: translateY(-1px);
}

.icon-button:active {
    transform: translateY(0);
}

.portrait-button {
    padding: 0;
}

.portrait-button .user-avatar {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-size: cover;
    background-position: center;
    background-color: rgba(6, 182, 212, 0.16);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
}

.portrait-button .user-avatar.has-image { background-color: transparent; }

/* ?? Account dropdown ??????????????????????????????????????????????????????? */

.user-menu {
    position: relative;
}

.user-dropdown {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    min-width: 200px;
    background: rgba(255, 255, 255, 0.96);
    backdrop-filter: blur(20px) saturate(1.2);
    -webkit-backdrop-filter: blur(20px) saturate(1.2);
    border: 1px solid rgba(20, 24, 40, 0.08);
    border-radius: 14px;
    box-shadow: 0 12px 32px rgba(24, 32, 64, 0.16);
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    animation: dropdown-appear 0.14s ease-out;
}

@keyframes dropdown-appear {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.user-dropdown-header {
    padding: 8px 12px 6px;
    border-bottom: 1px solid rgba(20, 24, 40, 0.06);
    margin-bottom: 4px;
}

.user-dropdown-header .user-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    max-width: none;
    white-space: normal;
    overflow: visible;
}

.user-dropdown-item {
    display: flex;
    align-items: center;
    padding: 9px 12px;
    border-radius: 8px;
    border: 0;
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: 14px;
    text-decoration: none;
    cursor: pointer;
    text-align: left;
    width: 100%;
}

.user-dropdown-item:hover {
    background: rgba(6, 182, 212, 0.08);
}

.user-dropdown-item.danger {
    color: var(--danger);
}

.user-dropdown-item.danger:hover {
    background: rgba(232, 72, 106, 0.08);
}

/* ?? Listening (loading) state ??????????????????????????????????????????????
   When the seed is thinking we collapse the whole floating card down to a
   single small pill and play the rotating-shadow animation on that pill.
   Question text, textarea, and buttons are hidden during this state. */

.send-spinner {
    display: none;
}

.dialogue-float {
    transition: width 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

.dialogue-float.listening {
    width: 56px;
}

.dialogue-float.listening .compact-card {
    padding: 0;
    width: 56px;
    height: 56px;
    min-height: 56px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    animation: send-pulse 1.6s ease-in-out infinite;
}

.dialogue-float.listening .question-text,
.dialogue-float.listening .input-row {
    display: none;
}

.compact-card {
    transition:
        padding   0.35s cubic-bezier(0.4, 0, 0.2, 1),
        width     0.35s cubic-bezier(0.4, 0, 0.2, 1),
        height    0.35s cubic-bezier(0.4, 0, 0.2, 1),
        min-height 0.35s cubic-bezier(0.4, 0, 0.2, 1),
        border-radius 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

/* A soft, breathing yellow-green halo for the "thinking" state.  The
   real visual interest during loading is the canvas-side energy bubbles
   that drift up toward the plant ? the pill itself just needs a subtle
   pulse so the user can tell something is happening near the input. */
@keyframes send-pulse {
    0%, 100% {
        box-shadow:
            0 0 0 0 rgba(6, 182, 212, 0),
            0 0 14px 2px rgba(6, 182, 212, 0.28);
    }
    50% {
        box-shadow:
            0 0 0 8px rgba(6, 182, 212, 0.12),
            0 0 22px 4px rgba(6, 182, 212, 0.55);
    }
}

/* ?? Submit error banner ????????????????????????????????????????????????? */

.submit-error {
    margin-top: 10px;
    padding: 10px 14px;
    border-radius: 14px;
    background: rgba(255, 235, 238, 0.92);
    border: 1px solid rgba(200, 40, 60, 0.25);
    color: #8a1f2c;
    font-size: 13px;
    line-height: 1.35;
    backdrop-filter: blur(12px) saturate(1.2);
    -webkit-backdrop-filter: blur(12px) saturate(1.2);
    box-shadow: 0 6px 18px rgba(24, 32, 64, 0.08);
    animation: dialogue-appear 0.3s ease-out both;
}

@keyframes dialogue-appear {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

.bloom-banner {
    position: absolute;
    left: 50%;
    bottom: 32px;
    transform: translateX(-50%);
    width: min(420px, calc(100% - 48px));
    z-index: 20;
    text-align: center;
    animation: bloom-banner-appear 0.8s cubic-bezier(0.22, 1, 0.36, 1) both;
    pointer-events: auto;
}

.bloom-banner.hidden {
    display: none !important;
}

.bloom-message {
    margin: 0 0 4px;
    font-family: var(--font-display, "Orbitron", sans-serif);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.04em;
    line-height: 1.5;
    color: var(--muted);
}

.bloom-signin-cta {
    margin-top: 12px;
    display: inline-block;
    background: transparent;
    border: 1px solid rgba(6, 182, 212, 0.55);
    border-radius: 9px;
    padding: 7px 18px;
    font-family: var(--font-display, "Orbitron", sans-serif);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.06em;
    color: rgb(6, 182, 212);
    cursor: pointer;
    transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.bloom-signin-cta:hover {
    background: rgba(6, 182, 212, 0.14);
    border-color: rgba(6, 182, 212, 0.85);
    color: rgb(103, 232, 249);
}

@keyframes bloom-banner-appear {
    from { opacity: 0; transform: translateX(-50%) translateY(14px); }
    to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

.topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.minimal-topbar {
    justify-content: space-between;
}

.topbar-left,
.topbar-right {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.topbar-right {
    margin-left: auto;
}

.eyebrow,
.section-label,
.name-label {
    color: var(--muted);
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.22em;
    font-size: 10px;
    font-weight: 500;
}

.title {
    margin: 6px 0 0;
    font-family: var(--font-display);
    font-size: clamp(20px, 3vw, 32px);
    font-weight: 600;
    letter-spacing: 0.06em;
}

.ghost-button,
.primary-button {
    min-height: 42px;
    padding: 0 18px;
    border-radius: 10px;
    border: 1px solid var(--line);
    color: var(--text);
    cursor: pointer;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}

.ghost-button:hover:not(:disabled) {
    border-color: rgba(6, 182, 212, 0.4);
    box-shadow: 0 0 14px var(--glow-soft);
}

.ghost-button.small {
    min-height: 30px;
    padding: 0 12px;
    font-size: 11px;
    letter-spacing: 0.16em;
}

.ghost-button.danger {
    color: var(--danger);
    border-color: rgba(232, 72, 106, 0.4);
}

.ghost-button:disabled,
.primary-button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.primary-button:disabled {
    opacity: 0.72;
    cursor: wait;
}

.ghost-button {
    background: rgba(0, 0, 0, 0.04);
}

.primary-button {
    background: linear-gradient(135deg, var(--accent), var(--accent-2));
    color: #04222a;
    font-weight: 600;
    border: 0;
    box-shadow: 0 8px 22px var(--glow-soft), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}

.primary-button:hover:not(:disabled) {
    box-shadow: 0 10px 28px var(--glow), inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

.layout,
.minimal-layout {
    min-height: 0;
}

.minimal-layout {
    width: min(760px, 100%);
    margin: 0 auto;
    display: grid;
    grid-template-rows: 1fr auto;
    gap: 16px;
    min-height: 0;
    overflow: hidden;
}

.dialogue-panel,
.garden-panel {
    min-height: 0;
    overflow: hidden;
}

.dialogue-panel {
    display: grid;
    gap: 14px;
    align-content: start;
    max-height: 40vh;
    overflow-y: auto;
}

.minimal-dialogue {
    width: 100%;
    max-width: 760px;
    margin: 0 auto;
}

.status-row,
.button-row,
.name-card,
.feedback-grid,
.garden-hud {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.pill {
    display: inline-flex;
    align-items: center;
    min-height: 30px;
    padding: 0 12px;
    border-radius: 999px;
    background: rgba(6, 182, 212, 0.07);
    border: 1px solid var(--line);
    color: var(--muted);
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}

.name-card,
.question-card,
.answer-card,
.panel,
.garden-stage {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    backdrop-filter: blur(10px);
}

.name-card,
.question-card,
.answer-card,
.panel {
    padding: 16px;
}

.name-card {
    display: grid;
    gap: 8px;
}

.name-line {
    display: flex;
    justify-content: space-between;
    gap: 12px;
}

.question-card {
    display: grid;
    gap: 8px;
}

.question-text {
    margin: 0;
    font-size: 20px;
    line-height: 1.35;
}

.seed-reply,
.summary-text {
    margin: 0;
    color: var(--muted);
    line-height: 1.55;
}

.answer-card {
    display: grid;
    gap: 10px;
}

textarea {
    width: 100%;
    resize: vertical;
    min-height: 120px;
    border-radius: 10px;
    padding: 14px;
    border: 1px solid rgba(12, 30, 50, 0.12);
    background: rgba(255, 255, 255, 0.92);
    color: var(--text);
}

.feedback-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.chip-list,
.effect-list,
.conversation-log {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.chip {
    display: inline-flex;
    align-items: center;
    padding: 7px 12px;
    border-radius: 999px;
    background: rgba(6, 182, 212, 0.08);
    color: #066879;
    border: 1px solid rgba(6, 182, 212, 0.22);
    font-size: 12px;
    letter-spacing: 0.02em;
}

/* Flower code: the F0XX-XXXX-XXXC serial. Mono + uppercase + thin
   luminous outline so it reads like a sci-fi spec number rather than a tag. */
.chip.flower-code {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 6px 12px;
    border-radius: 6px;
    color: #04778a;
    background: rgba(6, 182, 212, 0.06);
    border: 1px solid rgba(6, 182, 212, 0.45);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4), 0 0 10px var(--glow-soft);
    transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.chip.flower-code:hover {
    border-color: rgba(6, 182, 212, 0.65);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4), 0 0 14px var(--glow);
}

.effect {
    width: 100%;
    color: var(--muted);
    line-height: 1.45;
}

.conversation-log {
    display: grid;
    gap: 12px;
}

.log-entry {
    padding: 12px 14px;
    border-radius: 18px;
    background: rgba(0, 0, 0, 0.03);
    border: 1px solid rgba(20, 24, 40, 0.06);
}

.log-entry strong {
    display: block;
    margin-bottom: 6px;
}

.log-entry p {
    margin: 0 0 6px;
    color: var(--muted);
    line-height: 1.45;
}

.garden-panel {
    display: grid;
    min-height: 0;
    overflow: hidden;
}

.garden-stage {
    padding: 12px;
    display: grid;
    grid-template-rows: 1fr;
    min-height: 0;
    overflow: hidden;
    background:
        radial-gradient(ellipse 90% 55% at 50% 0%, rgba(6, 182, 212, 0.10), transparent 45%),
        radial-gradient(ellipse 70% 50% at 85% 15%, rgba(20, 184, 166, 0.07), transparent 42%),
        linear-gradient(180deg, #ffffff 0%, #f4f9fc 100%);
}

.single-stage {
    min-height: 0;
}

.canvas-wrap {
    position: relative;
    min-height: 200px;
    border-radius: var(--radius);
    overflow: hidden;
    border: 1px solid rgba(12, 30, 50, 0.06);
    background:
        radial-gradient(ellipse 85% 60% at 50% 18%, rgba(6, 182, 212, 0.10), transparent 48%),
        radial-gradient(ellipse 55% 40% at 15% 85%, rgba(20, 184, 166, 0.07), transparent 45%),
        linear-gradient(165deg, #ffffff 0%, #f1f7fa 55%, #eaf3f8 100%);
}

#flower-canvas {
    display: block;
    width: 100% !important;
    height: 100% !important;
}

.garden-hud {
    justify-content: space-between;
}

.hud-item {
    display: grid;
    gap: 4px;
}

.hidden {
    display: none !important;
}

/* ?? User widget (topbar) ??????????????????????????????????????????????????? */

/* Topbar user widget: shaped to match the adjacent .ghost-button (same
   height, same corner radius, same line-border-on-cyan-hover treatment) so
   the "Back to game" button and the user-identity pill read as a unified
   pair. The avatar becomes a small Orbitron monogram (first letter of the
   display name) — no decorative emoji. */
.user-widget {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    height: 42px;
    padding: 0 6px;
    border-radius: 10px;
    background: transparent;
    border: 1px solid var(--line);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.user-widget:hover {
    border-color: rgba(6, 182, 212, 0.4);
    box-shadow: 0 0 14px var(--glow-soft);
}

.user-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background-color: rgba(6, 182, 212, 0.10);
    border: 1px solid rgba(6, 182, 212, 0.35);
    background-size: cover;
    background-position: center;
    color: var(--accent);
    font-family: var(--font-display);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: uppercase;
}

.user-avatar.has-image {
    background-color: transparent;
    color: transparent;
}

/* The floating portrait icon on the game page already supplies its own
   border via .icon-button; suppress the avatar's border so we don't get a
   double-ring effect. */
.portrait-button .user-avatar {
    border: 0;
}

.user-name {
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--text);
    max-width: 110px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ?? Modal ?????????????????????????????????????????????????????????????????? */

.modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}

.modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(20, 24, 40, 0.45);
    backdrop-filter: blur(4px);
}

.modal-card {
    position: relative;
    width: min(440px, 100%);
    background: var(--panel-strong);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 28px 24px 24px;
    display: grid;
    gap: 14px;
}

.modal-close {
    position: absolute;
    top: 10px;
    right: 12px;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 0;
    background: transparent;
    color: var(--muted);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
}

.modal-close:hover {
    background: rgba(0, 0, 0, 0.06);
    color: var(--text);
}

.modal-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.modal-subtitle {
    margin: 0;
    color: var(--muted);
    line-height: 1.5;
}

.login-options {
    display: grid;
    gap: 12px;
}

.login-button {
    width: 100%;
    gap: 10px;
}

.login-icon {
    font-size: 18px;
}

.login-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--muted);
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.22em;
    margin: 4px 0;
}

.login-divider::before,
.login-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--line);
}

.login-hint {
    margin: 0;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.45;
    padding: 10px 12px;
    border-radius: 12px;
    background: rgba(255, 176, 32, 0.1);
    border: 1px solid rgba(255, 176, 32, 0.25);
}

.mock-name-card {
    padding: 12px 14px;
    gap: 6px;
}

.mock-name-card input {
    width: 100%;
    padding: 10px 12px;
    border-radius: 8px;
    border: 1px solid rgba(12, 30, 50, 0.12);
    background: rgba(255, 255, 255, 0.92);
    color: var(--text);
    font: inherit;
}

/* ?? Garden page ???????????????????????????????????????????????????????????? */

.garden-page {
    width: min(1100px, 100%);
    margin: 0 auto;
    padding: 8px 4px 40px;
    display: grid;
    gap: 20px;
}

/* The default .app-shell pins itself to the viewport (height: 100vh +
   overflow: hidden) so the game's stage canvas can fill the screen. The
   garden gallery, however, is a long list that should scroll naturally as
   a normal web page. Override the layout for garden.html so the document
   body becomes the scroll container ??this avoids the fragile
   "scroll-inside-a-grid-track" arrangement that was causing the page to
   snap back to the top when scrolling toward the bottom. */
.garden-body,
html:has(.garden-body) {
    height: auto;
    overflow: auto;
}

.app-shell.garden-shell {
    height: auto;
    max-height: none;
    min-height: 100vh;
    overflow: visible;
}

.garden-page-header {
    display: grid;
    gap: 4px;
}

.garden-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 16px;
}

.flower-card {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
    cursor: pointer;
    display: grid;
    grid-template-rows: auto auto;
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

.flower-card:hover,
.flower-card:focus-visible {
    transform: translateY(-2px);
    border-color: rgba(6, 182, 212, 0.4);
    /* Single, lower-blur shadow on hover — large-blur shadows are expensive
       to re-rasterize, especially while the hovered mini-canvas is animating. */
    box-shadow: 0 12px 28px rgba(12, 30, 50, 0.1);
    outline: none;
}

.mini-canvas-wrap {
    aspect-ratio: 4 / 3;
    min-height: 180px;
    border-radius: 0;
    border: 0;
    border-bottom: 1px solid var(--line);
}

.flower-card-meta {
    padding: 12px 14px;
    display: grid;
    gap: 6px;
}

.flower-card-name {
    margin: 0;
    font-family: var(--font-display);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.08em;
    line-height: 1.3;
}

.flower-card-date {
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.06em;
}

#flower-detail {
    display: grid;
    gap: 14px;
}


.detail-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
}

/* Detail-actions reads as a tight, intentional control group rather than
   three independent buttons floating next to the title. Share is the
   primary action (cyan-filled), Close is a quiet ghost, Delete is danger
   but de-emphasized as the rarest action. */
.detail-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.detail-actions .ghost-button,
.detail-actions .primary-button {
    min-height: 36px;
    padding: 0 14px;
    font-size: 11px;
}

/* Information design for the per-flower metadata: each datum is a small
   Orbitron uppercase eyebrow label stacked over its value. Less visual
   weight than the old chip pills and reads as a data-card field rather
   than an arbitrary tag. Lives inside .detail-card below the description
   and shares a divider with it (border-top added by the card-scoped
   rule below). */
.detail-meta {
    display: flex;
    flex-wrap: wrap;
    column-gap: 24px;
    row-gap: 10px;
    align-items: flex-end;
}

.meta-item {
    display: inline-flex;
    flex-direction: column;
    gap: 3px;
    line-height: 1.1;
}

.meta-label {
    font-family: var(--font-display);
    font-size: 9px;
    font-weight: 500;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--accent);
    opacity: 0.78;
}

.meta-value {
    font-size: 13px;
    color: var(--text);
    letter-spacing: 0.02em;
}

.meta-value-mono {
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #04778a;
}

.meta-value-mono:hover {
    color: var(--accent);
}

/* Chinese tweaks: drop the wide Orbitron tracking on the tiny labels and
   leave the value spacing natural (CJK glyphs have intrinsic side-bearing
   and don't need extra letter-spacing). */
html[lang="zh"] .meta-label {
    letter-spacing: 0.12em;
}
html[lang="zh"] .meta-value {
    letter-spacing: 0;
}

.detail-canvas-wrap {
    aspect-ratio: 16 / 10;
    min-height: 320px;
}

/* The flower + description live inside a single self-contained card with
   a divider between them — same visual idiom as a gallery flower-card,
   scaled up. The outer #flower-detail.panel still hosts the title bar,
   action buttons, and meta row; the card sits below as the "artifact". */
.detail-card {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--panel-strong);
    box-shadow: 0 10px 26px rgba(12, 30, 50, 0.06);
}

/* The canvas-wrap normally has its own border + radius. Suppress those
   here so we don't get a double-ring effect, and use a border-bottom to
   separate the render from the description (matches .mini-canvas-wrap
   on the gallery cards). */
.detail-card .canvas-wrap {
    border: 0;
    border-radius: 0;
    border-bottom: 1px solid var(--line);
}

.detail-card #detail-summary {
    /* Zero bottom padding — the meta's top padding below provides the
       breathing room between description text and the ID/SAVED row. */
    padding: 18px 20px 0;
    margin: 0;
    color: var(--muted);
    line-height: 1.55;
    font-size: 14px;
}

.detail-card #detail-summary:empty {
    display: none;
}

/* Meta sits tight against the card's bottom edge — only a small bottom
   padding so descenders + the rounded corner have clearance, no
   intentional whitespace below. The 18px top padding becomes the gap
   between the description and the ID/SAVED row. */
.detail-card .detail-meta {
    padding: 18px 20px 6px;
}

/* ── Language switcher (EN | 中) ──────────────────────────────────────────── */

.lang-switcher {
    display: inline-flex;
    align-items: stretch;
    height: 34px;
    border-radius: 999px;
    border: 1px solid var(--line);
    overflow: hidden;
    background: rgba(255, 255, 255, 0.72);
    backdrop-filter: blur(14px) saturate(1.2);
    -webkit-backdrop-filter: blur(14px) saturate(1.2);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.lang-switcher:hover {
    border-color: rgba(6, 182, 212, 0.4);
    box-shadow: 0 0 12px var(--glow-soft);
}

.lang-switcher button {
    border: 0;
    background: transparent;
    color: var(--muted);
    padding: 0 10px;
    cursor: pointer;
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.10em;
    text-transform: uppercase;
    transition: background 0.15s ease, color 0.15s ease;
    min-width: 30px;
}

.lang-switcher button:hover {
    color: var(--text);
}

.lang-switcher button[data-lang-active="true"] {
    background: rgba(6, 182, 212, 0.14);
    color: var(--accent);
}

/* On the game page (frosted floating chrome over the canvas), the switcher
   matches the icon-button height so it sits on the same baseline. The
   garden topbar uses the default 38px height which lines up with the
   42px ghost-button via the gap. */
.stage-controls .lang-switcher {
    height: 38px;
}

/* ── Share modal (garden detail → Share) ─────────────────────────────────── */

.share-modal-card {
    width: min(520px, 100%);
    max-height: 92vh;
    overflow: auto;
}

.share-modal-card .modal-subtitle {
    font-size: 13px;
}

.share-preview {
    position: relative;
    width: 100%;
    aspect-ratio: 3 / 4;
    background: rgba(6, 182, 212, 0.04);
    border: 1px solid rgba(6, 182, 212, 0.18);
    border-radius: 10px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}

.share-preview-loading {
    font-family: var(--font-display);
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--muted);
    animation: send-pulse 1.6s ease-in-out infinite;
    padding: 8px 14px;
    border-radius: 999px;
    background: rgba(6, 182, 212, 0.06);
}

#share-preview-image {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

.share-modal-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.share-modal-actions > * {
    flex: 1 1 auto;
}

/* ── New-game confirmation modal ─────────────────────────────────────────── */

.new-game-card {
    width: min(420px, 100%);
}

.new-game-actions {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    margin-top: 6px;
}

.new-game-actions > * {
    flex: 0 1 auto;
}

/* ── Share viewer page (share.html) ──────────────────────────────────────── */

.share-body {
    height: auto;
    overflow: auto;
}

html:has(.share-body) {
    height: auto;
    overflow: auto;
}

.share-page {
    width: min(560px, 100%);
    margin: 0 auto;
    padding: 32px 16px 48px;
    display: grid;
    gap: 18px;
    min-height: 100vh;
}

.share-header {
    display: grid;
    gap: 4px;
}

.share-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.share-header-row > div:first-child {
    text-align: left;
}

.share-wordmark {
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 600;
    letter-spacing: 0.28em;
    color: var(--text);
    text-transform: uppercase;
}

.share-card {
    display: grid;
    gap: 16px;
    padding: 18px;
}

.share-canvas-wrap {
    aspect-ratio: 4 / 3;
    min-height: 280px;
}

.share-canvas-wrap canvas {
    display: block;
    width: 100% !important;
    height: 100% !important;
}

.share-meta {
    display: grid;
    gap: 10px;
    text-align: center;
}

.share-name {
    margin: 0;
    text-transform: uppercase;
    letter-spacing: 0.1em;
}

.share-code-row {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.chip.motif-play {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    border: 1px solid rgba(255, 255, 255, 0.15);
    background: rgba(255, 255, 255, 0.04);
    color: inherit;
    font: inherit;
    padding: 4px 10px;
}

.chip.motif-play:hover {
    background: rgba(255, 255, 255, 0.08);
}

.chip.motif-play .motif-play-icon {
    font-size: 0.9em;
    line-height: 1;
}

/* Topbar sound toggle: show one of two icons depending on state. */
.icon-button.sound-toggle .sound-icon-off { display: none; }
.icon-button.sound-toggle[data-sound-state="off"] .sound-icon-on { display: none; }
.icon-button.sound-toggle[data-sound-state="off"] .sound-icon-off { display: inline-block; }

.share-header-controls {
    display: flex;
    align-items: center;
    gap: 8px;
}

.share-summary {
    margin: 0;
    color: var(--muted);
    line-height: 1.5;
    font-size: 15px;
}

.share-footer {
    display: flex;
    justify-content: center;
    padding-top: 8px;
}

.share-cta {
    width: 100%;
    max-width: 360px;
}

@media (max-width: 640px) {
    .app-shell {
        padding: 10px;
    }

    .topbar {
        /* Keep the row direction on mobile so the "Back to game" button and
           the user widget sit on the same horizontal line. flex-wrap lets
           them break onto a second row only when they genuinely overflow
           (very narrow phones with a long display name). */
        align-items: center;
        flex-wrap: wrap;
        gap: 8px;
    }

    .canvas-wrap {
        min-height: 160px;
    }

    .garden-grid {
        grid-template-columns: 1fr;
    }

    .user-name {
        max-width: 90px;
    }

    /* Canvas wrappers set both `aspect-ratio` and a `min-height` larger than
       what the aspect-ratio would produce at narrow widths — on phones the
       min-height wins and the WebGL plant render gets stretched vertically.
       Drop the min-height so aspect-ratio drives height proportionally. */
    .detail-canvas-wrap,
    .share-canvas-wrap {
        min-height: 0;
    }

    /* Let Share/Close/Delete wrap onto a second row instead of overflowing
       beside a long flower name in the detail header. */
    .detail-actions {
        flex-wrap: wrap;
    }

    /* Bump touch targets closer to the iOS HIG / WCAG 44px minimum. */
    .icon-button {
        width: 42px;
        height: 42px;
    }

    /* Modal action rows: allow wrap so action buttons (Download / Share /
       Copy link, Cancel / Start new game) flow onto a second row when the
       label text exceeds the cramped mobile width. */
    .new-game-actions {
        flex-wrap: wrap;
    }
}

/* Landscape phones / very short viewports: the fixed 168px dialogue
   clearance leaves only ~150px of vertical for the plant render. Cut it
   back so the plant has room. The renderer reads this CSS variable on
   each resize so no JS change is needed. */
@media (max-height: 500px) {
    .stage-layout {
        --dialogue-clearance: 110px;
    }
}

/* Very narrow phones (e.g. 320px iPhone SE): the modal's outer padding +
   the card's internal padding eats too much horizontal room, and Orbitron
   uppercase button labels with wide letter-spacing overflow the card. */
@media (max-width: 360px) {
    .modal {
        padding: 12px;
    }
    .modal-card {
        padding: 22px 18px 18px;
    }
    .ghost-button,
    .primary-button {
        padding: 0 12px;
        letter-spacing: 0.08em;
    }
}

