/* ==========================================================================
   App pages — Task, Orders, Profile, Recharge, Withdraw

   These five are the product. They share one shape: a heading, a lead block
   that carries the single most important number or action, and then
   supporting material that never competes with it.

   Depends on theme.css tokens and its component library.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Entrance motion

   One utility, used on the blocks that make up a page's first screen. It is
   CSS-only and runs once on load — the page assembles itself rather than
   appearing all at once, which is what makes it read as an app rather than
   as a document.
   -------------------------------------------------------------------------- */
.rise {
    animation: rise 0.55s var(--ease) both;
    animation-delay: calc(var(--i, 0) * 70ms);
}

@keyframes rise {
    from { opacity: 0; transform: translateY(16px); }
    to { opacity: 1; transform: none; }
}

.rise-in {
    animation: rise-in 0.5s var(--ease) both;
    animation-delay: calc(var(--i, 0) * 55ms);
}

@keyframes rise-in {
    from { opacity: 0; transform: translateY(10px) scale(0.98); }
    to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .rise,
    .rise-in { animation: none; }
}

/* --------------------------------------------------------------------------
   1. Stat — a label and a number, as its own small surface

   Replaces the hairline-separated `.figures` band on the pages below: a
   phone reads three separate cards more easily than three cells, and the
   set can then wrap without the band collapsing.
   -------------------------------------------------------------------------- */
.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
    gap: var(--sp-2);
}

.stat-row--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (min-width: 560px) {
    .stat-row { gap: var(--sp-3); }
}

.stat {
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--r-lg);
    background: var(--surface);
    box-shadow: var(--shadow-panel);
}

.stat--plain { background: var(--surface-2); box-shadow: none; }

.stat__label {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 3px;
    color: var(--text-muted);
    font-size: var(--t-xs);
    font-weight: 600;
    line-height: 1.3;
}

.stat__label i { font-size: 0.78rem; }

.stat__value {
    /* Pushed to the bottom of the card so a label that wraps to two lines
       does not drop its figure below the ones beside it. */
    margin: auto 0 0;
    font-size: clamp(0.95rem, 3.4vw, 1.12rem);
    font-weight: 800;
    letter-spacing: -0.025em;
    font-variant-numeric: tabular-nums;
    overflow-wrap: break-word;
}

.stat--success .stat__value,
.stat--success .stat__label i { color: var(--success); }
.stat--warning .stat__value,
.stat--warning .stat__label i { color: var(--warning); }
.stat--danger .stat__value,
.stat--danger .stat__label i { color: var(--danger); }
.stat--brand .stat__value,
.stat--brand .stat__label i { color: var(--primary); }

/* --------------------------------------------------------------------------
   2. Task page

   The whole page is one question — how many are left today — and one answer:
   the button. Everything else is reference, and is sized like it.
   -------------------------------------------------------------------------- */
.task-stage {
    display: grid;
    gap: var(--sp-4);
    align-items: start;
}

@media (min-width: 900px) {
    .task-stage {
        grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
        gap: var(--sp-5);
    }
}

/* --- The card the dial sits on ----------------------------------------- */
.task-card {
    position: relative;
    overflow: hidden;
    padding: var(--sp-5) var(--sp-4) var(--sp-5);
    border-radius: var(--r-2xl);
    background: var(--surface);
    box-shadow: var(--shadow-panel);
    text-align: center;
}

@media (min-width: 560px) {
    .task-card { padding: var(--sp-6); }
}

/* A single soft brand wash behind the dial, so the card has a centre of
   gravity without a second fill. */
.task-card::before {
    content: '';
    position: absolute;
    top: -120px;
    left: 50%;
    width: 420px;
    height: 420px;
    transform: translateX(-50%);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(var(--primary-rgb), 0.12), transparent 62%);
    pointer-events: none;
}

.task-card > * { position: relative; }

/* --- Membership row ----------------------------------------------------- */
.task-tier {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-2);
    margin-bottom: var(--sp-5);
    border-radius: var(--r-pill);
    background: var(--surface-2);
    box-shadow: var(--ring);
    text-align: left;
}

.task-tier__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: linear-gradient(140deg, var(--gold), var(--accent));
    color: #fff;
    font-size: 0.95rem;
    box-shadow: 0 4px 12px rgba(var(--accent-rgb), 0.3);
}

.task-tier__badge img { width: 22px; height: 22px; object-fit: contain; }

.task-tier__name {
    margin: 0;
    font-size: var(--t-sm);
    font-weight: 700;
    line-height: 1.25;
}

.task-tier__meta {
    margin: 0;
    font-size: var(--t-xs);
    color: var(--text-muted);
}

/* --- The dial ------------------------------------------------------------

   A conic ring driven by one registered custom property, so the fill can be
   animated from zero on load instead of snapping to its final angle. Where
   @property is unsupported the value still applies — the ring simply arrives
   already filled. */
@property --task-progress {
    syntax: '<number>';
    initial-value: 0;
    /* Inherited on purpose: the ring reads it on .task-dial and the water
       level reads it again inside, so one animated value drives both and
       they can never disagree. */
    inherits: true;
}

.task-dial {
    /* Declared as well as registered: where @property is unsupported this is
       what keeps the conic-gradient below a valid declaration before
       _task.js writes the real value. */
    --task-progress: 0;

    /* The ring's thickness. The hole and the water are both inset by it, so
       they can never disagree about where the ring ends. */
    --dial-ring: 9px;

    position: relative;
    display: grid;
    place-items: center;
    width: clamp(138px, 37vw, 170px);
    aspect-ratio: 1;
    margin: 0 auto;
    border-radius: 50%;
    background: conic-gradient(from -90deg,
        var(--brand-400) 0%,
        var(--brand-600) calc(var(--task-progress) * 1%),
        var(--surface-3) 0);
    transition: --task-progress 1.1s var(--ease);

    /* What the water inside is tinted with. */
    --wave-tint: var(--primary-rgb);
}

body[theme='dark'] .task-dial {
    background: conic-gradient(from -90deg,
        var(--brand-300) 0%,
        var(--brand-500) calc(var(--task-progress) * 1%),
        var(--surface-3) 0);
}

.task-dial--complete,
body[theme='dark'] .task-dial--complete {
    background: conic-gradient(from -90deg, #2ee6a8 0%, var(--success) 100%);
    --wave-tint: var(--success-rgb);
}

/* The hole in the middle. Three layers sit in it and the order matters, so
   each one says where it belongs: the hole, then the water, then the count. */
.task-dial::after {
    content: '';
    position: absolute;
    z-index: 0;
    inset: var(--dial-ring);
    border-radius: 50%;
    background: var(--surface);
    box-shadow: inset 0 2px 8px rgba(18, 19, 26, 0.05);
}

body[theme='dark'] .task-dial::after { box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.4); }

/* A halo that breathes while there is still work left today. */
.task-dial__halo {
    position: absolute;
    inset: -6px;
    border-radius: 50%;
    box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.35);
    animation: dial-halo 2.8s var(--ease) infinite;
    pointer-events: none;
}

@keyframes dial-halo {
    0% { opacity: 0.5; transform: scale(1); }
    70%, 100% { opacity: 0; transform: scale(1.14); }
}

.task-dial__inner {
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    line-height: 1;
}

/* --- Water ---------------------------------------------------------------

   The dial fills like a glass. It is the same figure the ring is already
   showing, which is the point: the wave is not an ornament dropped into the
   circle, it is the reading, so it can move continuously without becoming
   one more thing to watch.

   Two layers drift in opposite directions at different speeds — that
   parallax is what makes a repeating tile stop looking like a repeating
   tile. Both animate transform and nothing else, so the whole effect stays
   on the compositor and costs a phone nothing per frame. */
.dial-wave {
    position: absolute;
    z-index: 1;
    /* Exactly the hole punched by .task-dial::after, so the water is bounded
       by the ring rather than by a second circle drawn on top of it. */
    inset: var(--dial-ring);
    border-radius: 50%;
    overflow: hidden;
    /* The layers are wider than the circle and always moving; this stops the
       browser considering anything outside for paint. */
    contain: paint;
    pointer-events: none;
}

.dial-wave__layer {
    position: absolute;
    left: 0;
    bottom: 0;
    /* Two tiles wide. Sliding it by half its own width moves it by exactly
       one tile, so the loop has no seam, and the half that is left over
       always covers the circle. */
    width: 200%;
    height: calc(var(--task-progress) * 1%);
    background: currentColor;
    animation: dial-wave-drift 7s linear infinite;
    will-change: transform;
}

/* The crest, riding on top of the body. At zero it is all you see — a
   shallow ripple in the bottom of an empty dial, rather than a dead circle. */
.dial-wave__layer::before {
    content: '';
    position: absolute;
    left: 0;
    bottom: 100%;
    width: 100%;
    /* Tall enough that an empty dial still shows a resting ripple rather
       than a flat line. */
    height: 17px;
    background: currentColor;
    /* A sine, tiled. It is a mask rather than a background image so the
       colour stays a CSS property and can follow the theme.

       The tile is a quarter of this element, which is two tiles wide — so
       two crests cross the circle at any moment. One long shallow crest
       across the whole width reads as a tilted line, not as water. */
    -webkit-mask-image: var(--wave-mask);
    mask-image: var(--wave-mask);
    -webkit-mask-repeat: repeat-x;
    mask-repeat: repeat-x;
    -webkit-mask-size: 25% 100%;
    mask-size: 25% 100%;
}

.dial-wave__layer {
    --wave-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 24' preserveAspectRatio='none'%3E%3Cpath d='M0 12C12.5 2 37.5 2 50 12S87.5 22 100 12V24H0Z' fill='%23000'/%3E%3C/svg%3E");
}

/* The far layer: paler, slower, drifting the other way, and sitting a few
   pixels below the near one so the two crests never line up. */
.dial-wave__layer--back {
    color: rgba(var(--wave-tint), 0.11);
    margin-bottom: -5px;
    animation-duration: 11s;
    animation-direction: reverse;
}

.dial-wave__layer--back::before {
    height: 20px;
    /* Started out of phase with the near layer, so the two never agree even
       on the first frame. */
    -webkit-mask-position: 13% 0;
    mask-position: 13% 0;
}

.dial-wave__layer--front { color: rgba(var(--wave-tint), 0.2); }

@keyframes dial-wave-drift {
    from { transform: translate3d(0, 0, 0); }
    to { transform: translate3d(-50%, 0, 0); }
}

/* Where the browser cannot mask, the crest would be a flat bar across the
   water. Drop it and keep the plain fill — still a level, just not a wave. */
@supports not ((-webkit-mask-image: none) or (mask-image: none)) {
    .dial-wave__layer::before { display: none; }
}

.task-dial__count {
    font-size: clamp(1.68rem, 6.2vw, 2.05rem);
    font-weight: 800;
    letter-spacing: -0.05em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.task-dial__limit {
    margin-top: 6px;
    font-size: var(--t-sm);
    font-weight: 600;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.task-dial__caption {
    margin-top: var(--sp-2);
    font-size: var(--t-2xs);
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--primary);
}

.task-dial--complete + .task-dial__caption,
.task-dial--complete .task-dial__caption { color: var(--success); }

/* --- Progress line ------------------------------------------------------- */
.task-progress {
    max-width: 320px;
    margin: var(--sp-5) auto 0;
    text-align: left;
}

.task-progress .meter__fill {
    /* Grown from nothing on load — see _task.js, which writes the real width
       one frame in. */
    transition: width 1.1s var(--ease) 0.15s;
}

/* --- The action ----------------------------------------------------------

   One button, and it is the only thing on the page with a brand fill. */
.task-start {
    position: relative;
    overflow: hidden;
    margin-top: var(--sp-5);
    padding-block: 16px;
    font-size: 0.95rem;
    letter-spacing: 0.01em;
    box-shadow: var(--shadow-brand);
}

.task-start:hover { box-shadow: 0 14px 34px rgba(var(--primary-rgb), 0.38); }

/* A slow sweep across the fill. It is the one idle animation on the page, so
   it is the one thing the eye returns to. */
.task-start::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 55%;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.28), transparent);
    transform: translateX(-160%);
    animation: task-sweep 3.4s var(--ease) infinite;
    pointer-events: none;
}

@keyframes task-sweep {
    0% { transform: translateX(-160%); }
    55%, 100% { transform: translateX(320%); }
}

.task-start i { animation: task-bolt 2.6s var(--ease) infinite; }

@keyframes task-bolt {
    0%, 82%, 100% { transform: none; }
    88% { transform: scale(1.22) rotate(-8deg); }
    94% { transform: scale(1.08) rotate(4deg); }
}

.task-start:disabled::after,
.task-start:disabled i { animation: none; }

@media (prefers-reduced-motion: reduce) {
    .task-dial { transition: none; }
    .task-dial__halo,
    .task-start::after,
    .task-start i { animation: none; }
    .task-start::after { opacity: 0; }

    /* The water keeps its level — it just stops travelling. */
    .dial-wave__layer { animation: none; }
}

/* --- Side column --------------------------------------------------------- */
.task-side {
    display: grid;
    gap: var(--sp-3);
}

/* One per line, at every width.

   Three of these abreast on a phone gives each about 110px to hold a label
   and a currency figure — "Today Profit" wraps, the figures stop lining up,
   and the set reads as a cramped table. Stacked, each one is a single line:
   label left, figure right, nothing wrapping. */
.task-side .stat-row { grid-template-columns: 1fr; }

.task-side .stat {
    display: flex;
    /* The base rule stacks the label over the figure and pushes the figure to
       the bottom of the card; both have to be undone for a one-line row. */
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
}

.task-side .stat__label { margin: 0; }
.task-side .stat__value { margin: 0; }

/* --------------------------------------------------------------------------
   3. Orders

   A card per order, in as many columns as the width allows. The three
   figures are the reason the card exists, so they sit on their own band.
   -------------------------------------------------------------------------- */
.order-grid {
    display: grid;
    gap: var(--sp-3);
    grid-template-columns: 1fr;
}

@media (min-width: 620px) {
    .order-grid { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
}

.order-card {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    padding: var(--sp-4);
    border-radius: var(--r-xl);
    background: var(--surface);
    box-shadow: var(--shadow-panel);
    transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

.order-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-raised);
}

.order-card__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
}

.order-card__time {
    font-size: var(--t-xs);
    font-weight: 600;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.order-card__tags { display: inline-flex; align-items: center; gap: 5px; }

.order-card__main {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    min-width: 0;
}

.order-card__thumb {
    flex: 0 0 auto;
    width: 58px;
    height: 58px;
    border-radius: var(--r-md);
    object-fit: cover;
    background: var(--surface-3);
    box-shadow: var(--ring);
}

.order-card__title {
    margin: 0 0 3px;
    font-size: var(--t-body);
    font-weight: 700;
    line-height: 1.35;
    letter-spacing: -0.015em;
}

.order-card__amount {
    margin: 0;
    font-size: var(--t-xs);
    color: var(--text-muted);
}

.order-card__amount strong {
    color: var(--text);
    font-size: var(--t-sm);
    font-variant-numeric: tabular-nums;
}

/* The three figures, as one band inside the card. */
.order-card__figures {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1px;
    padding: var(--sp-3) 0;
    border-radius: var(--r-md);
    background: var(--surface-2);
    text-align: center;
    overflow: hidden;
}

.order-card__fig { min-width: 0; padding-inline: var(--sp-1); }

.order-card__fig + .order-card__fig { box-shadow: inset 1px 0 0 var(--border); }

.order-card__fig-k {
    margin: 0 0 2px;
    font-size: var(--t-2xs);
    font-weight: 600;
    color: var(--text-muted);
}

.order-card__fig-v {
    margin: 0;
    font-size: var(--t-sm);
    font-weight: 800;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}

.order-card__fig-v--profit { color: var(--success); }

.order-card__foot {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.order-card__foot > * { flex: 1 1 0; }

/* --------------------------------------------------------------------------
   4. Profile

   Identity, then the money, then everything you can do. The identity block
   is the one branded surface on the page.
   -------------------------------------------------------------------------- */
.profile-hero {
    position: relative;
    overflow: hidden;
    padding: var(--sp-5);
    border-radius: var(--r-2xl);
    background: linear-gradient(135deg, var(--brand-700) 0%, var(--brand-600) 45%, #7a5cf0 100%);
    color: #fff;
    box-shadow: var(--shadow-brand);
}

body[theme='dark'] .profile-hero {
    background: linear-gradient(135deg, #251d63 0%, #3a2ea0 50%, #5b4be8 100%);
}

.profile-hero::before {
    content: '';
    position: absolute;
    top: -55%;
    right: -12%;
    width: 340px;
    height: 340px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255, 255, 255, 0.16), transparent 64%);
    pointer-events: none;
}

.profile-hero > * { position: relative; }

.profile-hero__who {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    min-width: 0;
}

.profile-hero__who .avatar {
    background: rgba(255, 255, 255, 0.2);
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25);
}

.profile-hero__name {
    margin: 0 0 4px;
    color: #fff;
    font-size: 1.18rem;
    font-weight: 800;
    letter-spacing: -0.025em;
}

.profile-hero__meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0;
    font-size: var(--t-xs);
    color: rgba(255, 255, 255, 0.82);
}

.profile-hero__uid {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 4px 3px 10px;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, 0.16);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.profile-hero__uid .icon-btn {
    width: 22px;
    height: 22px;
    font-size: 0.68rem;
    background: transparent;
    color: #fff;
}

.profile-hero__uid .icon-btn:hover { background: rgba(255, 255, 255, 0.22); color: #fff; }

.profile-hero__chip {
    padding: 3px 10px;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, 0.16);
    color: #fff;
    font-size: var(--t-2xs);
    font-weight: 700;
}

/* The three figures, in the hero rather than under it: they are part of who
   you are here, not a separate report. */
.profile-hero__figures {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1px;
    margin-top: var(--sp-5);
    border-radius: var(--r-lg);
    background: rgba(255, 255, 255, 0.14);
    overflow: hidden;
}

.profile-hero__figure {
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: var(--sp-3);
    background: rgba(255, 255, 255, 0.06);
}

.profile-hero__figure-k {
    margin: 0 0 2px;
    font-size: var(--t-2xs);
    font-weight: 600;
    color: rgba(255, 255, 255, 0.78);
}

.profile-hero__figure-v {
    margin: auto 0 0;
    font-size: 0.98rem;
    font-weight: 800;
    letter-spacing: -0.025em;
    font-variant-numeric: tabular-nums;
    overflow-wrap: break-word;
}

.profile-hero__actions {
    display: flex;
    gap: var(--sp-2);
    margin-top: var(--sp-4);
}

.profile-hero__actions .btn-app {
    flex: 1 1 0;
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    box-shadow: none;
}

.profile-hero__actions .btn-app:hover { background: rgba(255, 255, 255, 0.3); color: #fff; }

.profile-hero__actions .btn-app--light {
    background: #fff;
    color: var(--brand-700);
}

.profile-hero__actions .btn-app--light:hover { background: rgba(255, 255, 255, 0.88); color: var(--brand-700); }

@media (min-width: 760px) {
    .profile-hero {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: center;
        gap: var(--sp-5) var(--sp-6);
        padding: var(--sp-6);
    }

    .profile-hero__actions { margin-top: 0; }
    .profile-hero__figures { grid-column: 1 / -1; margin-top: 0; }
}

/* --------------------------------------------------------------------------
   5. Wallet pages (Recharge / Withdraw)
   -------------------------------------------------------------------------- */

/* The balance, at the size it deserves on a page that is about it. */
.balance-card--hero { padding: var(--sp-6) var(--sp-5); }

.balance-card--hero .balance-card__amount { font-size: clamp(1.9rem, 8vw, 2.6rem); }

/* A numbered line of instructions — three steps, no boxes. */
.steps { display: grid; gap: var(--sp-4); }

.step {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
}

.step__n {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: rgba(var(--primary-rgb), 0.12);
    color: var(--primary);
    font-size: var(--t-xs);
    font-weight: 800;
}

.step__title { margin: 0 0 2px; font-size: var(--t-sm); font-weight: 700; }
.step__text { margin: 0; font-size: var(--t-xs); color: var(--text-muted); line-height: 1.55; }

/* The withdrawal amount field, sized like the figure it produces. */
.amount-field .input-shell {
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--r-lg);
}

.amount-field .input-shell__prefix {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--text-muted);
    padding-inline: var(--sp-2) 0;
}

.amount-field .input {
    padding: var(--sp-2);
    background: transparent;
    box-shadow: none;
    font-size: 1.7rem;
    font-weight: 800;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}

.amount-field .input:focus { box-shadow: none; }
