/* Points Page — uses theme.css for base styles */

/* The page shell: a fixed-height column, so the leaderboard scrolls inside the
   right panel instead of pushing the footer off screen.

   Both rules below are `min-height: 0` on purpose. A flex child defaults to
   `min-height: auto`, which means it refuses to shrink below its content — with a
   thirty-row leaderboard that stretched the row past the viewport, pushed the footer
   out of view, and left the panel with no scrollbar because it was already as tall as
   its content. */
.points-page .points-main-row,
.points-page .side-panel-body {
    min-height: 0;
}

/* Both panels scroll on their own; the page itself never does. */
.points-page .side-panel-body {
    overflow-y: auto;
}

.points-footer {
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    background: var(--bg-dark);
    border-top: 1px solid var(--border-base);
    flex-shrink: 0;
}

/* The way back into Arya's walkthrough once it has been seen (see TOUR_ID in client.js). */
.arya-guide-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 10px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-muted);
    border-color: transparent;
    padding: 3px 10px;
}

.arya-guide-btn:hover {
    color: var(--accent-gold);
    border-color: var(--border-bronze);
}

.arya-guide-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    border: 1px solid currentColor;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
}

/* ---------------------------------------------------------------------------
   The left panel's two tabs

The daily run and the one-time tasks are different bargains, so they get a tab each rather than
sitting in one long column. The strip is the first thing in the panel — above the wallet card —
because choosing between the two is the first decision a returning player makes. Styled from the
same tokens as the rankings tabs on the right, at a size that fits a 400px column.
   */
.points-tabs {
    display: flex;
    gap: 4px;
    padding: 3px;
    border: 1px solid var(--border-base);
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.35);
}

.points-tab {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 7px 10px;
    border: 1px solid transparent;
    border-radius: 3px;
    background: transparent;
    color: var(--text-muted);
    font-family: inherit;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    cursor: pointer;
    transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}

.points-tab:hover {
    color: var(--accent-gold);
}

.points-tab.is-active {
    border-color: var(--border-bronze, var(--border-accent, var(--accent-gold)));
    background: rgba(212, 168, 67, 0.12);
    color: var(--accent-gold);
}

.points-tab:focus-visible {
    outline: 1px solid var(--accent-gold);
    outline-offset: 1px;
}

/* How many one-time tasks are still unclaimed. Only rendered when the answer is above zero, so
   it reads as a nudge rather than a permanent badge. */
.points-tab-badge {
    min-width: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: var(--accent-gold, #d4a843);
    color: #14100a;
    font-size: 9.5px;
    line-height: 16px;
    text-align: center;
    letter-spacing: 0;
}

/* ---------------------------------------------------------------------------
   A one-time task

A claim rather than a proof: the reward is stated, the step is a button, and the card says in the
small print that nothing was checked. The claimed state dims the whole card instead of removing
it, so the tab still shows what has been done — the count of what is left is the point of the tab.
   */
.one-task {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    border: 1px solid var(--border-base);
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.28);
}

.one-task.is-claimed {
    border-color: rgba(90, 160, 90, 0.4);
    background: rgba(90, 160, 90, 0.05);
}
/* Waiting on its review window: not paid, not refused, and deliberately not styled like an error —
   the claim is already the player's, so the card reads as in-progress rather than incomplete. */
.one-task.is-pending {
    border-color: rgba(200, 168, 96, 0.45);
    background: rgba(200, 168, 96, 0.05);
}
.one-task.is-rejected {
    border-color: rgba(232, 164, 155, 0.35);
    background: rgba(232, 164, 155, 0.04);
}

.one-task-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
}

/* An anchor here, not a button: it opens X in a new tab, and a real link is what a long-press or
   a middle-click can use. It has to wear the button's clothes, so it borrows them rather than
   being styled twice. */
.one-task-actions > .btn {
    justify-content: center;
    text-decoration: none;
}

.one-task-footer {
    padding: 4px;
    font-size: 10px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* A narrow column stacks the two buttons instead of squeezing them. */
@media (max-width: 520px) {
    .one-task-actions {
        grid-template-columns: 1fr;
    }
}

/* Section headings inside the left panel (vault progress, share, referrals) */
.panel-section-title {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 4px 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--accent-gold);
}

.panel-hint {
    padding: 0 4px;
    margin-bottom: 8px;
    font-size: 10px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* A locked button still has to be readable — "Vault Cleared Today" is information,
   not just a dead end. */
.points-left-panel .btn:disabled {
    opacity: 0.72;
    cursor: not-allowed;
}

.points-left-panel .btn:disabled .btn-icon-img {
    filter: grayscale(0.6);
}

/* A cleared floor reads as done, and stays legible while it does. */
.stat-row.is-done .stat-label {
    opacity: 0.65;
}

/* ---------------------------------------------------------------------------
   Wallet card
   The page needs a wallet before it can pay anything, so this states clearly
   which wallet is earning and how to start earning.
   --------------------------------------------------------------------------- */
.wallet-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    border: 1px solid var(--border-base);
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.28);
}

.wallet-card.is-connected {
    border-color: var(--border-accent, var(--accent-gold));
    background: rgba(212, 168, 67, 0.06);
}

.wallet-card-line {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    letter-spacing: 0.5px;
    color: var(--text-primary);
}

.wallet-card-meta {
    font-size: 10.5px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* The "live" dot next to the address and the chip it sits in are defined in `theme.css` now,
   where every route can load them — this sheet, `staking.css` and the Portfolio page each need
   the same control. */

/* Transient feedback: "+100 PTS banked", "Signed in…" */
.points-notice {
    position: fixed;
    left: 50%;
    bottom: 56px;
    transform: translateX(-50%);
    z-index: 950;
    padding: 10px 18px;
    border: 1px solid var(--border-accent, var(--accent-gold));
    border-radius: 4px;
    background: rgba(10, 10, 14, 0.94);
    color: var(--accent-gold);
    font-size: 12px;
    letter-spacing: 1px;
    text-transform: uppercase;
    pointer-events: none;
    animation: points-notice-in 0.18s ease-out;
}

@keyframes points-notice-in {
    from { opacity: 0; transform: translate(-50%, 8px); }
    to { opacity: 1; transform: translate(-50%, 0); }
}

/* Failures that need saying out loud (a 500 from the API, a rejected floor) */
.points-banner {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 10px 12px;
    border-radius: 4px;
    font-size: 11.5px;
    line-height: 1.5;
}

.points-banner-error {
    border: 1px solid rgba(200, 70, 60, 0.5);
    background: rgba(200, 70, 60, 0.12);
    color: #e8a49b;
}

/* A real warning: the page works, but the deployment is not storing points anywhere
   durable. Amber, not red — it is a setup task, not a fault. */
.points-banner-warn {
    border: 1px solid rgba(212, 168, 67, 0.5);
    background: rgba(212, 168, 67, 0.1);
    color: #e0c882;
}

.points-banner code {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 10.5px;
    color: var(--accent-gold);
}

/* Failures have to stay visible while the vault covers the page (overlay z-index 900). */
.points-banner-float {
    position: fixed;
    left: 50%;
    top: 18px;
    transform: translateX(-50%);
    z-index: 960;
    max-width: 620px;
    background: rgba(22, 10, 10, 0.96);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.55);
}

.points-banner-x {
    margin-left: auto;
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    font-size: 12px;
    line-height: 1;
    padding: 2px;
}

/* ---------------------------------------------------------------------------
   Ranking table and referral ledger
   These rows had no styles anywhere, so the table used to render as colliding
   run-together text. One grid definition drives the header and every row.
   --------------------------------------------------------------------------- */
.leaderboard-table,
.referrals-list {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--border-base);
    border-radius: 4px;
    overflow: hidden;
}

.lb-header,
.lb-row {
    display: grid;
    grid-template-columns: 52px 1fr 110px 64px;
    align-items: center;
    gap: 8px;
    padding: 9px 14px;
}

.lb-header {
    background: rgba(0, 0, 0, 0.4);
    border-bottom: 1px solid var(--border-base);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-muted);
}

.lb-row {
    border-bottom: 1px solid rgba(255, 255, 255, 0.04);
    font-size: 13px;
    color: var(--text-secondary);
}

.lb-row:last-child {
    border-bottom: none;
}

.lb-row:nth-child(even) {
    background: rgba(255, 255, 255, 0.015);
}

.lb-rank {
    font-family: var(--font-heading, inherit);
    font-weight: 700;
    color: var(--text-muted);
}

.lb-row.top-1 .lb-rank { color: #f0d478; }
.lb-row.top-2 .lb-rank { color: #cfd3d8; }
.lb-row.top-3 .lb-rank { color: #cf9a5a; }

.lb-name {
    display: flex;
    align-items: center;
    gap: 8px;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lb-points {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--accent-gold);
}

.lb-refs {
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

/* Your own row stays findable at a glance, wherever it lands. */
.lb-row.is-you {
    background: rgba(212, 168, 67, 0.12);
    border-left: 3px solid var(--accent-gold);
    padding-left: 11px;
    color: var(--text-primary);
}

.lb-you-tag {
    padding: 1px 6px;
    border: 1px solid var(--accent-gold);
    border-radius: 3px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--accent-gold);
}

/* Empty, loading and error states share one look. */
.lb-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 52px 24px;
    text-align: center;
    font-size: 12px;
    color: var(--text-muted);
}

.lb-state-small {
    padding: 16px;
    font-size: 11px;
}

/* Referral ledger: who you invited, what they have, what you were paid. */
.ref-header,
.ref-row {
    display: grid;
    grid-template-columns: 1fr 110px 110px;
    align-items: center;
    gap: 8px;
    padding: 9px 14px;
}

.ref-header {
    background: rgba(0, 0, 0, 0.4);
    border-bottom: 1px solid var(--border-base);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-muted);
}

.ref-row {
    border-bottom: 1px solid rgba(255, 255, 255, 0.04);
    font-size: 13px;
    color: var(--text-secondary);
}

.ref-row:last-child {
    border-bottom: none;
}

.ref-row.ref-total {
    background: rgba(212, 168, 67, 0.08);
    color: var(--text-primary);
    font-weight: 600;
}

.ref-addr {
    font-variant-numeric: tabular-nums;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ref-their {
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.ref-earned {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--accent-gold);
}

/* Invite link row in the left panel */
.referral-row {
    display: flex;
    gap: 8px;
    margin-bottom: 8px;
}

/* The invite link field. It is a real <input> so the link can still be selected and
   copied by hand when the Clipboard API is unavailable. */
.referral-code {
    flex: 1;
    min-width: 0;
    padding: 6px 10px;
    border: 1px solid var(--border-base);
    border-radius: 4px;
    background: var(--bg-dark);
    color: var(--accent-gold);
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 11px;
    letter-spacing: 0.5px;
    text-overflow: ellipsis;
    outline: none;
    cursor: text;
}

.referral-code:focus {
    border-color: var(--border-accent, var(--accent-gold));
    box-shadow: 0 0 0 2px rgba(212, 168, 67, 0.18);
}

.referral-code::selection {
    background: rgba(212, 168, 67, 0.35);
}

/* The code itself, set large — it exists to be read off the screen and typed by somebody
   else, so it is the one piece of text in the panel that is allowed to be bigger than the
   body copy. Letters and digits only, so the letter-spacing does not break words apart. */
.ref-code {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 10px;
    margin-bottom: 8px;
    border: 1px solid var(--border-base);
    border-radius: 4px;
    background: var(--bg-dark);
}

.ref-code-label {
    font-size: 11px;
    color: var(--text-muted);
    letter-spacing: 0.5px;
    text-transform: uppercase;
}

.ref-code-value {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 18px;
    font-weight: 700;
    letter-spacing: 4px;
    color: var(--accent-gold);
    user-select: all;
}

/* Add-a-code box: shown only while the wallet has no referrer (see the page). Separated by a
   rule because it is the one control here that changes the wallet rather than advertising it. */
.ref-attach {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--border-base);
}

.ref-attach-title {
    margin-bottom: 4px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
}

.ref-attach-input {
    color: var(--text-primary);
    font-size: 13px;
    letter-spacing: 3px;
    text-transform: uppercase;
}

.ref-attach-input::placeholder {
    color: var(--text-muted);
    letter-spacing: 3px;
}

/* Same palette as `.points-banner-error` — a refusal is a refusal wherever it is shown. */
.ref-attach-error {
    padding: 6px 10px;
    border: 1px solid rgba(200, 70, 60, 0.5);
    border-radius: 4px;
    background: rgba(200, 70, 60, 0.12);
    font-size: 11px;
    line-height: 1.45;
    color: #e8a49b;
}

.referral-meta {
    padding: 0 4px;
    font-size: 11px;
    color: var(--text-muted);
}

.ref-earnings {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 8px 10px;
    border: 1px solid var(--border-accent, var(--accent-gold));
    border-radius: 4px;
    background: rgba(212, 168, 67, 0.07);
    font-size: 11px;
}

.ref-earnings-label {
    color: var(--text-secondary);
    letter-spacing: 0.5px;
}

.ref-earnings-value {
    font-weight: 700;
    color: var(--accent-gold);
}

/* All icons on points page */
.points-icon {
    image-rendering: pixelated;
    flex-shrink: 0;
    vertical-align: middle;
}

/* Panel header icons (vault, trophy, link) - 20px */
.panel-header-icon.points-icon {
    width: 20px;
    height: 20px;
}

/* Empty state icons - 40px */
.empty-state-icon {
    width: 40px;
    height: 40px;
    opacity: 0.35;
    margin-bottom: 12px;
}

/* ---------------------------------------------------------------------------
   Points Vault mini-game
   The map is a looping video, the fight is drawn on a transparent canvas above
   it, and the HUD stays in HTML so its text is never scaled by the canvas.
   --------------------------------------------------------------------------- */
.dungeon-overlay {
    position: fixed;
    inset: 0;
    z-index: 900;
    background: #06060a;
    overflow: hidden;
    font-family: var(--font-body, Inter, sans-serif);
}

.dungeon-map {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    image-rendering: pixelated;
}

/* Darken the map's edges so the sprites and HUD stay readable on top of it */
.dungeon-vignette {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse at center, rgba(0, 0, 0, 0) 45%, rgba(0, 0, 0, 0.72) 100%),
        linear-gradient(to bottom, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 22%, rgba(0, 0, 0, 0) 62%, rgba(0, 0, 0, 0.8) 100%);
    pointer-events: none;
}

.dungeon-container {
    position: relative;
    height: 100%;
    display: flex;
    flex-direction: column;
}

.dungeon-top-bar {
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 14px 22px;
    background: linear-gradient(to bottom, rgba(4, 4, 8, 0.92), rgba(4, 4, 8, 0.35));
    border-bottom: 1px solid var(--border-base, rgba(212, 168, 67, 0.25));
}

.dungeon-level-info {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 260px;
}

.dungeon-level-name {
    font-family: var(--font-display, Cinzel, serif);
    font-size: 20px;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
}

.dungeon-level-num {
    font-size: 12px;
    color: var(--text-secondary, #b8b2a6);
    letter-spacing: 1px;
}

.dungeon-timer {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 12px;
}

.dungeon-timer-text {
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    color: var(--accent-gold, #d4a843);
    min-width: 54px;
}

.dungeon-timer-bar {
    flex: 1;
    height: 8px;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.09);
    border: 1px solid rgba(212, 168, 67, 0.25);
    overflow: hidden;
}

.dungeon-timer-fill {
    height: 100%;
    border-radius: 4px;
    transition: width 0.12s linear;
}

.dungeon-points-so-far {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 1px;
    color: var(--accent-gold, #d4a843);
    border: 1px solid rgba(212, 168, 67, 0.4);
    border-radius: 4px;
    padding: 4px 10px;
    background: rgba(212, 168, 67, 0.08);
}

.dungeon-stage {
    position: relative;
    flex: 1;
    min-height: 0;
}

.dungeon-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.dungeon-loading {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display, Cinzel, serif);
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--accent-gold, #d4a843);
    opacity: 0.8;
}

.dungeon-bottom {
    min-height: 108px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 16px 22px 22px;
    background: linear-gradient(to top, rgba(4, 4, 8, 0.95), rgba(4, 4, 8, 0.2));
    border-top: 1px solid var(--border-base, rgba(212, 168, 67, 0.25));
}

/* Deploy / Recall / Exit — the same controls, and the same order, as the
   main dungeon game's control bar. */
.dungeon-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 10px;
}

.dungeon-controls .dungeon-btn {
    min-width: 150px;
}

.dungeon-controls .dungeon-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.dungeon-fighting {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.dungeon-dummy-label {
    font-size: 11px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-muted, #8b857a);
}

.dungeon-status-text {
    font-family: var(--font-display, Cinzel, serif);
    font-size: 15px;
    letter-spacing: 2px;
    color: var(--accent-gold, #d4a843);
}

.dungeon-complete {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    text-align: center;
}

.dungeon-reward-announce {
    font-family: var(--font-display, Cinzel, serif);
    font-size: 26px;
    font-weight: 700;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--accent-gold, #d4a843);
    text-shadow: 0 0 24px rgba(212, 168, 67, 0.45);
}

.dungeon-final-note {
    font-size: 12px;
    color: var(--text-secondary, #b8b2a6);
    max-width: 520px;
    line-height: 1.5;
}

.dungeon-final-btns {
    display: flex;
    gap: 12px;
}

.dungeon-btn {
    min-width: 200px;
    justify-content: center;
    letter-spacing: 1px;
    text-transform: uppercase;
    font-size: 12px;
}

.dungeon-btn.is-shared {
    opacity: 1;
    border-color: var(--accent-gold, #d4a843);
}

/* ---------------------------------------------------------------------------
   Earning on X — the account, and the two verified tasks

The account card is the gate: points are awarded against a named X account and the server refuses
any award without one, so it sits directly under the wallet and states that plainly. The task cards
below it are the same shape for both rewards, because they are the same rule — post it, paste the
link, and X is asked about it before anything is paid.
   */
.x-bind-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    border: 1px solid rgba(212, 168, 67, 0.45);
    border-radius: 4px;
    background: rgba(212, 168, 67, 0.07);
}

.x-bind-card.is-bound {
    border-color: var(--border-base);
    background: rgba(0, 0, 0, 0.28);
}

.x-proof-tag {
    margin-left: auto;
    padding: 1px 7px;
    border: 1px solid rgba(90, 160, 90, 0.55);
    border-radius: 3px;
    font-size: 9px;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: #96d096;
}

.x-bind-actions {
    display: flex;
    gap: 6px;
}

.x-bind-actions > .btn {
    flex: 1;
}

/* Typing a handle is the fallback for a browser with no Privy link to prove — one row, so it
   reads as an alternative rather than a second step. */
.x-bind-manual {
    display: flex;
    gap: 6px;
}

/* The binding is permanent, and it says so where the button used to be. A line and not a control:
   there is nothing to press, it is a fact about the account above. */
.x-bind-locked {
    align-self: center;
    font-size: 10px;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
}

/* ---------------------------------------------------------------- the share kit
   The picture and the words that go out with a shared run. The photo is the point of the card, so
   it takes the full column width; the steps under it are a real <ol> because they are a sequence —
   save, post, paste — and the numbers are what make that readable at eleven pixels. */
.x-share-kit {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.x-share-photo {
    display: block;
    border: 1px solid var(--border-base);
    border-radius: 4px;
    overflow: hidden;
    line-height: 0;
}

.x-share-photo img {
    display: block;
    width: 100%;
    height: auto;
}

/* Where the picture went on the last press of the post button. It outlives the toast on purpose:
   the composer takes the focus, so a fading sentence in the tab the player just left is a sentence
   nobody reads — this one is still here when they come back for the link. */
.x-share-picture {
    margin: 0;
    padding: 8px 9px;
    border: 1px solid rgba(212, 175, 55, 0.45);
    border-left-width: 3px;
    border-radius: 4px;
    background: rgba(212, 175, 55, 0.10);
    font-size: 11px;
    line-height: 1.5;
    color: var(--text-primary, #eee);
}

.x-share-steps {
    margin: 0;
    padding-left: 18px;
    font-size: 11px;
    line-height: 1.5;
    color: var(--text-secondary, var(--text-muted));
}

.x-share-steps li + li {
    margin-top: 4px;
}

/* The post as it will be sent — selectable, because the words are what a player pastes when they
   post from X's own app rather than through the composer link. */
.x-share-text {
    padding: 8px 9px;
    border: 1px solid var(--border-dim, var(--border-base));
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.35);
    font-size: 11px;
    line-height: 1.5;
    color: var(--text-primary);
    overflow-wrap: anywhere;
    user-select: text;
}

.x-task {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.x-task-reward {
    margin-left: auto;
    font-size: 10px;
    letter-spacing: 0.8px;
    color: var(--text-muted);
}

.x-task-reward.is-paid {
    color: #96d096;
}
.x-task-reward.is-pending {
    color: var(--accent-gold);
}

.x-task-submit {
    display: flex;
    gap: 6px;
}

.x-task-input {
    flex: 1;
    min-width: 0;
    padding: 7px 9px;
    border: 1px solid var(--border-base);
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.45);
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 11px;
    color: var(--text-primary);
}

.x-task-input:focus {
    outline: none;
    border-color: var(--accent-gold);
}

.x-task-input:disabled {
    opacity: 0.6;
}

.x-task-line {
    font-size: 11px;
    line-height: 1.5;
    color: var(--text-secondary, var(--text-muted));
}

.x-task-line.is-paid {
    display: flex;
    align-items: center;
    gap: 8px;
    color: #96d096;
}

.x-task-line.is-error {
    color: #e8a49b;
}
.x-task-line.is-pending {
    color: var(--accent-gold);
    opacity: 0.9;
}

.x-task-link {
    color: var(--accent-gold);
    text-decoration: underline;
}

/* The pending, failed and expired notes are banners, so they carry the same colours as the
   rest of the page's status messages — with the "check again" button inside the pending one. */
.x-task-note {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
}
