/* ============================================================================
   TOP BAR - streak number + fire + FOMO timer + Upgrade + user
   ============================================================================ */
/* v0.5.1.1: [clock] [pet] [1fr spacer] [right cluster]. The old lone streak
   digit merged into the clock as its leading segment (.streak-clock-days).
   v0.5.8.3 fix: KEEP four columns. .topbar-right is pinned to grid-column 4,
   so adding a 5th column (the v0.5.7 day-state experiment) turned column 4
   into the 1fr spacer and dragged the right cluster left. The day-state chip,
   when present, auto-flows into the 1fr spacer column and left-packs there -
   exactly where it belongs, no extra column needed. */
.topbar {
    display: grid;
    grid-template-columns: auto auto 1fr auto;
    align-items: center;
    gap: 14px;
    padding: 4px 0;
}

.streak-flame {
    width: 26px;
    height: 36px; /* v0.4.11.2: native 108×150 source ratio (108:150 ≈ 26:36) */
    flex-shrink: 0;
    object-fit: contain;
    display: inline-block;
    vertical-align: middle;
    user-select: none;
    pointer-events: none;
}

/* v0.4.11.2: combo flame as CSS sprite. fire-sprite.png is a 26-frame horizontal
   strip (676×36, each frame 26×36 - extracted from fire.gif with ffmpeg).
   `animation-direction: alternate` plays forward 0→25, then reverse 25→0, then
   forward again - eliminating the hard cut from last frame back to first that
   the looping GIF had. Period: 1s per direction = 2s round trip, which mirrors
   the GIF's native 1.06s loop while doubling the perceived smoothness. */
.streak-flame-anim {
    background-image: url('/fire-sprite.png');
    background-repeat: no-repeat;
    background-size: 676px 36px;
    background-position: 0 0;
    animation: fire-sprite-loop 1s steps(25) infinite alternate;
}
@keyframes fire-sprite-loop {
    from { background-position-x: 0; }
    to   { background-position-x: -650px; }
}
@media (prefers-reduced-motion: reduce) {
    /* Freeze on a mid-cycle frame so the flame still reads as a flame visually,
       just without motion. Picks frame 13 (middle of 26). */
    .streak-flame-anim {
        animation: none;
        background-position: -338px 0;
    }
}

/* v0.4.20.3: brief flare-up while a completion combo is playing (~2s). Layered on
   the always-on idle loop - flickers faster and scales up, then settles back. */
.streak-flame-combo {
    animation-duration: 0.55s;
    transform: scale(1.3);
    transform-origin: center bottom;
    transition: transform 0.18s ease-out;
}

.timer {
    font-family: var(--chronos-font-mono);
    font-size: 22px;
    font-weight: 600;
    color: var(--chronos-fg-primary);
    transition: color 0.2s;
    /* Tabular nums so HH:MM:SS digits don't jitter as they tick; nowrap so the
       countdown never folds into the streak cluster on tight layouts. */
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Red only inside the critical window - see StreakCountdown.CriticalThreshold (2h). */
/* v0.4.13: timer FOMO motion redesign - NO pulse (project feedback said app is
   pulse-overloaded). Replaced with two non-pulse signals:
     1. Slow color drift between the phase's "calm" and "alarmed" hues.
     2. Tiny horizontal jitter (±1.5px) at a low irregular cadence - reads as
        "twitchy / restless" rather than rhythmic breathing.
   The `.timer-fomo` modifier (applied only in Counting phase by Home.razor)
   carries the jitter; `.approaching` / `.critical` modulate the color drift's
   end-color and tempo. */
.timer.approaching {
    color: #F59E0B;
    animation:
        timer-color-drift-amber 3.0s ease-in-out infinite alternate,
        timer-jitter            1.4s steps(8, end)   infinite;
}
.timer.critical {
    color: #DC2626;
    animation:
        timer-color-drift-red 1.4s ease-in-out infinite alternate,
        timer-jitter          0.9s steps(8, end)   infinite;
}
@keyframes timer-color-drift-amber {
    0%   { color: #F59E0B; }   /* amber */
    100% { color: #D97706; }   /* darker amber, almost rust */
}
@keyframes timer-color-drift-red {
    0%   { color: #DC2626; }   /* dark red */
    100% { color: #991B1B; }   /* deeper crimson */
}
@keyframes timer-jitter {
    /* 8 discrete steps, irregularly displaced. Total range ±1.5px so it reads
       as twitch, not a slide. steps() with no smooth interpolation keeps the
       motion "broken" - feels less mechanical than a sine wobble. */
    0%   { transform: translateX(0); }
    13%  { transform: translateX(-1.5px); }
    27%  { transform: translateX(1px); }
    41%  { transform: translateX(0); }
    55%  { transform: translateX(1.5px); }
    69%  { transform: translateX(-1px); }
    83%  { transform: translateX(0.5px); }
    100% { transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) {
    .timer.approaching,
    .timer.critical {
        animation: none;
    }
}

/* v0.4.13: "Good!" chip - shown in Safe phase (< 24h since last task). Replaces
   the timer entirely. Green-ish violet so it reads as positive without breaking
   from the brand palette. No animation - Safe phase is supposed to be CALM. */
.streak-good {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-family: var(--chronos-font-mono);
    font-size: 18px;
    font-weight: 600;
    color: #16A34A; /* fresh green; WCAG-AA on white */
    padding: 2px 10px;
    border-radius: 999px;
    background: color-mix(in srgb, #16A34A 12%, transparent);
    user-select: none;
}

/* Broken / no-streak placeholder. Just muted. */
.timer.broken {
    color: var(--chronos-fg-muted);
    opacity: 0.55;
}

/* v0.4.67.19: streak "clock" - the countdown/status text and the always-on streak
   flame combined into ONE control so the flame reads as part of the clock (founder
   ask), not a separate glyph. Styled as a CHRONOMETER BEZEL: a dark device face in
   BOTH themes (the light theme already speaks this accent language - the selected
   calendar day is near-black), with a top specular sheen, inner depth shadow, a warm
   violet cast near the flame end, and glowing digits. The rim narrates the FOMO
   phase: violet = counting, green = safe, amber/red = deadline approaching/critical,
   gray + ashen flame = broken. Static glows only - no new pulse (pulse-budgeted app).
   The inner .timer keeps its mono type + colour-drift/jitter animations. */
.streak-clock {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 38px;
    padding: 0 7px 0 14px;
    border-radius: var(--radius-pill);
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0) 40%),
        radial-gradient(130% 100% at 88% 30%, rgba(168, 85, 247, 0.28), transparent 62%),
        linear-gradient(180deg, #241F35 0%, #14121F 58%, #1A1728 100%);
    border: 1px solid rgba(139, 92, 246, 0.45);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        inset 0 -2px 5px rgba(0, 0, 0, 0.35),
        0 2px 10px color-mix(in srgb, var(--chronos-violet) 20%, transparent);
    white-space: nowrap;
}
/* v0.5.1.1: day counter - the clock's leading segment, split off by a hairline.
   Same mono voice as the digits; the phase modifiers tint it below so the whole
   device reads as one instrument (days | state | flame). */
.streak-clock-days {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
    font-size: 19px;
    font-weight: 800;
    line-height: 1;
    color: #F1ECFF;
    text-shadow: 0 0 8px rgba(167, 139, 250, 0.35);
    padding-right: 9px;
    margin-right: 2px;
    border-right: 1px solid rgba(255, 255, 255, 0.14);
}
.streak-clock.is-safe .streak-clock-days { color: #C7F9DD; text-shadow: 0 0 8px rgba(52, 211, 153, 0.30); }
.streak-clock.is-frozen .streak-clock-days { color: #BFDBFE; text-shadow: 0 0 8px rgba(96, 165, 250, 0.40); }
.streak-clock.is-broken .streak-clock-days { color: #9AA1B2; text-shadow: none; }

.streak-clock .timer {
    font-size: 20px;
    color: #F1ECFF;
    text-shadow: 0 0 9px rgba(167, 139, 250, 0.40);
}
/* Amber/red ink must survive on the dark face: the base .timer.approaching/.critical
   rules sit EARLIER in this file, so the .streak-clock .timer colour above would win
   at equal specificity. Re-assert them (the keyframe colour drift still overrides
   while animating; these matter for reduced-motion + as the resting hue). */
.streak-clock .timer.approaching { color: #FBBF24; text-shadow: 0 0 9px rgba(245, 158, 11, 0.35); }
.streak-clock .timer.critical   { color: #F87171; text-shadow: 0 0 9px rgba(220, 38, 38, 0.40); }
.streak-clock .streak-good {
    background: transparent;
    padding: 0;
    font-size: 17px;
    color: #4ADE80;
    text-shadow: 0 0 8px rgba(52, 211, 153, 0.35);
}
/* Flame: optically seated. The sprite's mass is bottom-heavy, so dead-centring reads
   as sagging - lift it 1px and trace its shape with a warm ember halo so it feels
   socketed into the device rather than floating beside the digits. */
.streak-clock .streak-flame {
    transform: translateY(-1px);
    filter: drop-shadow(0 0 5px rgba(251, 146, 60, 0.55));
}
/* Completion flare-up: the base .streak-flame-combo scale loses to the translate
   above at lower specificity - compose both so the flare still plays. */
.streak-clock .streak-flame-combo {
    transform: translateY(-1px) scale(1.25);
    transform-origin: center bottom;
}
/* FOMO escalation on the frame itself as the deadline nears. */
.streak-clock.is-safe { border-color: rgba(74, 222, 128, 0.38); }
.streak-clock.is-approaching {
    border-color: rgba(245, 158, 11, 0.55);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        inset 0 -2px 5px rgba(0, 0, 0, 0.35),
        0 2px 12px rgba(245, 158, 11, 0.30);
}
.streak-clock.is-critical {
    border-color: rgba(239, 68, 68, 0.60);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        inset 0 -2px 5px rgba(0, 0, 0, 0.35),
        0 2px 14px rgba(239, 68, 68, 0.38);
}
/* v0.4.68: Frozen - the 48-72h grace with a freeze in inventory. The streak is
   SAVEABLE (next completion burns the freeze and continues it), so the clock must
   NOT look dead: icy blue rim + digits counting down to the grace end, flame
   hue-shifted to a cold blue "frozen fire". */
.streak-clock.is-frozen {
    border-color: rgba(96, 165, 250, 0.55);
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0) 40%),
        radial-gradient(130% 100% at 88% 30%, rgba(59, 130, 246, 0.30), transparent 62%),
        linear-gradient(180deg, #1C2740 0%, #101828 58%, #152036 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.10),
        inset 0 -2px 5px rgba(0, 0, 0, 0.35),
        0 2px 12px rgba(96, 165, 250, 0.32);
}
.streak-clock .timer.timer-frozen {
    color: #BFDBFE;
    text-shadow: 0 0 9px rgba(96, 165, 250, 0.45);
}
.streak-clock .clock-flake {
    font-size: 14px;
    line-height: 1;
    filter: drop-shadow(0 0 4px rgba(147, 197, 253, 0.7));
}
.streak-clock.is-frozen .streak-flame {
    /* Cold fire: rotate the sprite's oranges into blue and trace it with an icy halo. */
    filter: hue-rotate(185deg) saturate(0.9) brightness(1.05)
            drop-shadow(0 0 5px rgba(96, 165, 250, 0.6));
}

/* Broken / dead streak: same device, drained - gray rim, dim digits, ashen flame. */
.streak-clock.is-broken {
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0) 40%),
        linear-gradient(180deg, #232230 0%, #141320 58%, #191826 100%);
    border-color: rgba(148, 163, 184, 0.28);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.05),
        inset 0 -2px 5px rgba(0, 0, 0, 0.35);
}
.streak-clock .timer.broken { color: #9AA1B2; opacity: 0.8; text-shadow: none; }
.streak-clock.is-broken .streak-flame {
    filter: grayscale(0.85) brightness(0.75) drop-shadow(0 0 3px rgba(148, 163, 184, 0.25));
    opacity: 0.85;
}

/* v0.8.3.0: the 1fr spacer column, now an element rather than empty space, so the
   Upgrade CTA can be centred in it. Three tracks: the day-state chip left-packs in
   the first (unchanged behaviour - see the four-column note at the top of this
   file), the CTA occupies the middle one, and the third balances the first so the
   middle track really is the centre of the gap. */
.topbar-center {
    grid-column: 3;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 10px;
    min-width: 0;
}
.topbar-center > .daystate-slot { grid-column: 1; justify-self: start; min-width: 0; }
.topbar-center > .upgrade-halo { grid-column: 2; }

.topbar-right {
    grid-column: 4;
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

/* v0.4.22.1: topbar sound on/off toggle - icon button matching the pill chrome.
   The theme (light/dark) toggle shares the exact same chrome so the two sit as a
   matched pair in the topbar. */
.sound-toggle,
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    font-size: 16px;
    line-height: 1;
    background: var(--chronos-card-bg);
    border: 1px solid var(--chronos-outline);
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: transform 0.12s ease, border-color 0.12s ease;
}
.sound-toggle:hover,
.theme-toggle:hover {
    border-color: var(--chronos-violet);
    transform: translateY(-1px);
}

/* Theme toggle icon: show exactly one glyph for the action available now. Light
   theme -> moon ("switch to dark"); dark theme -> sun ("switch to light"). CSS
   owns the swap (keyed off html[data-theme]) so theme.js never touches the DOM. */
.theme-toggle .material-icons { font-size: 18px; color: var(--chronos-fg-primary); }
.theme-toggle .theme-icon-to-light { display: none; }
[data-theme="dark"] .theme-toggle .theme-icon-to-dark { display: none; }
[data-theme="dark"] .theme-toggle .theme-icon-to-light { display: inline; }

/* v0.4.30.1: topbar sign-out - same chip as the sound toggle, red-tinted on hover. */
.logout-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    background: var(--chronos-card-bg);
    border: 1px solid var(--chronos-outline);
    border-radius: var(--radius-pill);
    color: inherit;
    cursor: pointer;
    transition: transform 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.logout-btn .material-icons { font-size: 18px; }
.logout-btn:hover {
    border-color: #e0405a;
    color: #e0405a;
    transform: translateY(-1px);
}

/* v0.4.21.1: language picker - CSS-only <details> dropdown in the topbar. */
.lang-picker { position: relative; }
.lang-picker > summary {
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 28px;
    padding: 0 9px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border, rgba(0,0,0,0.12));
    background: transparent;
    color: var(--muted, #6b7280);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.04em;
    cursor: pointer;
    user-select: none;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.lang-picker > summary::-webkit-details-marker { display: none; }
.lang-picker > summary:hover {
    background: rgba(124, 58, 237, 0.10);
    color: var(--accent, #7c3aed);
    border-color: rgba(124, 58, 237, 0.35);
}
.lang-picker .lang-flag { font-size: 14px; line-height: 1; }
.lang-picker .lang-caret { font-size: 9px; opacity: 0.7; }
.lang-picker-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 50;
    min-width: 172px;
    padding: 6px;
    border-radius: 12px;
    background: #fff;
    border: 1px solid rgba(0, 0, 0, 0.10);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.lang-picker-item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 10px;
    border-radius: 8px;
    text-decoration: none;
    color: #1f2430;
    font-size: 13px;
    font-weight: 500;
}
.lang-picker-item:hover { background: rgba(124, 58, 237, 0.10); }
.lang-picker-item.active {
    background: rgba(124, 58, 237, 0.14);
    color: var(--accent, #7c3aed);
    font-weight: 700;
}

/* v0.5.8.4: the chip is a BUTTON (opens the profile) - it must read as one.
   Pointer cursor, no text-selection caret, and a hover lift + violet tint so
   it reacts like every other topbar control. */
.user-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--chronos-card-bg);
    border: 1px solid var(--chronos-outline);
    border-radius: var(--radius-pill);
    padding: 6px 14px;
    cursor: pointer;
    user-select: none;
    transition: border-color 0.15s ease, background 0.15s ease,
                box-shadow 0.15s ease, transform 0.12s ease;
}
.user-chip:hover {
    background: color-mix(in srgb, var(--chronos-violet) 7%, var(--chronos-card-bg));
    border-color: color-mix(in srgb, var(--chronos-violet) 45%, var(--chronos-outline));
    box-shadow: 0 2px 10px rgba(124, 58, 237, 0.18);
    transform: translateY(-1px);
}
.user-chip:focus-visible {
    outline: 2px solid var(--chronos-violet);
    outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
    .user-chip { transition: none; }
    .user-chip:hover { transform: none; }
}

.avatar {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: #374151;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden; /* clip the avatar image to the circle */
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12px;
    font-weight: 800;
    line-height: 1; /* keep the initial optically centered in the circle */
    color: #e8e4f5;
}
/* v0.4.23: uploaded avatar shown in the topbar chip (mirrors the profile modal). */
.avatar-img { width: 100%; height: 100%; object-fit: cover; }

/* ============================================================================
   INTENTIONAL DARK-UX - pulsing & tint-cycling Upgrade button.
   Mirrors Chronos.Desktop's Button.upgrade exactly: 2.4s SineEaseInOut cycle,
   scale 1.0 → 1.06, background violet → lavender → pink → lavender → violet.
   Do not flatten without an explicit product call.
   ============================================================================ */
@keyframes upgrade-pulse {
    0%   { transform: scale(1.0);   background: var(--chronos-violet); }
    25%  { transform: scale(1.035); background: var(--chronos-lavender); }
    50%  { transform: scale(1.06);  background: var(--chronos-pink); }
    75%  { transform: scale(1.035); background: var(--chronos-lavender); }
    100% { transform: scale(1.0);   background: var(--chronos-violet); }
}

@keyframes upgrade-halo {
    0%   { box-shadow: 0 0 14px 0 rgba(124, 58, 237, 0.30); }
    50%  { box-shadow: 0 0 28px 2px rgba(236, 72, 153, 0.60); }
    100% { box-shadow: 0 0 14px 0 rgba(124, 58, 237, 0.30); }
}

.upgrade-halo {
    border-radius: var(--radius-pill);
    padding: 0;
    animation: upgrade-halo 2.4s ease-in-out infinite;
}

.upgrade-btn {
    background: var(--chronos-violet);
    color: white;
    border: none;
    border-radius: var(--radius-pill);
    padding: 9px 18px;
    font-weight: 600;
    font-size: 14px;
    animation: upgrade-pulse 2.4s ease-in-out infinite;
    cursor: pointer;
}

@media (max-width: 720px) {
    /* v0.5.1.1: ONE-ROW phone topbar (see 02-main-layout.css for the flex switch).
       Compact the clock + pet so [clock][pet]......[icons] fits ~412px; on narrower
       screens or Free tier (wide Upgrade CTA) the right cluster wraps under,
       right-aligned - never a horizontal scroll. The .topbar prefix wins over
       05-streak-milestone.css's base pet sizes regardless of file order. */
    .topbar .pet-slot { width: 30px; height: 30px; margin-left: 0; }
    .topbar .pet-emoji { font-size: 23px; }
    .topbar .pet-locked-egg { width: 32px; height: 32px; }
    /* v0.5.7: day-state histogram compacts alongside the clock + pet. */
    .topbar .daystate-chip { height: 33px; padding: 5px 8px 6px; gap: 3px; }
    .topbar .daystate-pct { font-size: 11.5px; margin-left: 3px; }
    .streak-clock { height: 34px; padding: 0 3px 0 8px; gap: 4px; }
    .streak-clock-days { font-size: 14px; padding-right: 5px; }
    .streak-clock .timer { font-size: 14px; }
    .streak-clock .streak-good { font-size: 12.5px; }
    .streak-clock .streak-flame { transform: translateY(-1px) scale(0.8); }
    .streak-clock .streak-flame-combo { transform: translateY(-1px) scale(1.05); }
    /* Right cluster: icon-only chips (labels + username hide here, not at 480 -
       the one-row promise starts at 720). */
    .topbar-right { gap: 4px; }
    .user-chip { padding: 4px 6px; }
    .user-chip > span:first-child { display: none; }
    .logout-btn { width: 32px; height: 32px; }
    .upgrade-btn { padding: 7px 11px; font-size: 12px; letter-spacing: 0; }
}

@media (max-width: 480px) {
    .topbar-right {
        gap: 4px;
        flex-wrap: wrap;
        justify-content: flex-end;
        row-gap: 4px;
    }
    .sound-toggle { padding: 4px 6px; }
    .logout-btn { padding: 4px 6px; }
    .upgrade-btn {
        padding: 6px 9px;
        font-size: 11px;
        letter-spacing: 0;
    }
    .user-chip > span:first-child {
        display: none;
    }
    .lang-picker > summary {
        padding: 0 6px;
    }
    .lang-picker .lang-flag {
        font-size: 14px;
    }
    .lang-picker .lang-caret {
        display: none;
    }
}

/* Ultra-narrow (down to ~300px, e.g. 300x800 or split-screen). The right cluster
   already wraps via flex-wrap above; shrink it a touch more so it rarely needs a
   second row. */
@media (max-width: 340px) {
    .topbar-right { gap: 3px; row-gap: 3px; }
    .upgrade-btn { padding: 6px 9px; font-size: 11px; letter-spacing: 0; }
}

