*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body{
    /* Swapped from Inter to Outfit: Inter-everywhere is one of the most
       recognizable "an AI made this" tells, and Playfair Display already
       covers the two brand-title spots (see .title/.authBrandTitle below),
       so this is the base sans-serif for literally everything else.
       -apple-system/BlinkMacSystemFont stay first in the stack as the
       fastest-available fallback while the Google Fonts <link> loads. */
    font-family: -apple-system, BlinkMacSystemFont, 'Outfit', 'Segoe UI', sans-serif;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    align-items: center;
    min-height: 100svh;
    padding: clamp(12px, 2.6vh, 24px) 0;
    background: linear-gradient(320deg, rgb(104, 255, 189), rgb(169, 228, 255), rgb(185, 198, 251), rgb(253, 255, 247));
}

.container{
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    width: min(640px, 96vw);
    min-height: 300px;
    height: auto;
    background-color: rgba(255, 255, 255, 0.3);
    backdrop-filter: blur(10px);
    border: 3px solid #769ff880;
    border-radius: 20px;
    margin: 0 auto;
}


.title{
    font-family: 'Playfair Display', serif;
    font-size: 36px;
    font-weight: 700;
    color: #1e1e1e;
    margin-bottom: 20px;

}

.motivatorContainer{
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 20px;
    width: 100%;
    height: 100px;
    padding: 20px;
    background: rgba(255, 255, 255, 0.3);
    backdrop-filter: blur(10px);
    border: 3px solid rgba(103, 159, 255, 0.7);
    border-radius: 10px;
    margin-bottom: 14px;
}

.motivatorText{
    font-size: 24px;
    font-weight: 600;
    color: #1e1e1e;
    position: relative;
    left: -60px;
    top: -15px;
}

.progressBarContainer{
    width: 250px;
    height: 20px;
    background: rgba(5, 5, 5, 1);
    position: absolute;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    border-radius: 10px;
    top: 55px;
    transform: translateX(-45px);
    border: 2px solid rgba(100, 165, 255, 1);
    overflow: hidden;
}

.progressBar{
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 0%;
    background: linear-gradient(90deg, #4ba2ff, #8bdaff);
    border-radius: 8px;
    transition: width 0.25s ease-in-out;
}

.taskAmountContainer{
    display: flex;
    justify-content: center;
    align-items: center;
    width: 70px;
    height: 70px;
    background: rgba(35, 35, 35, 1);
    border-radius: 50%;
    border: 3px solid rgb(155, 215, 255);
    position: relative;
    left: 65px;
}

.taskAmount{
    font-size: 24px;
    font-weight: 500;
    color: #8bdaff;
}

.inputContainer{
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;
    width: 100%;
    flex-wrap: nowrap;
}

.quickAddHint{
    width: 92%;
    margin-top: 8px;
    color: #2f557f;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.3;
    text-align: left;
}

.quickAddHint.hidden{
    display: none;
}

.taskInput{
    width: auto;
    flex: 1;
    min-width: 0;
    height: 50px;
    padding: 15px 10px;
    border: none;
    outline: none;
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.3);
    backdrop-filter: blur(10px);
    border: 2px solid rgba(103, 159, 255, 0.7);
    font-size: var(--text-base);
}

.detailsToggleBtn{
    height: 42px;
    border: 2px solid rgba(103, 159, 255, 0.65);
    background: rgba(238, 248, 255, 0.78);
    color: #2f557f;
    border-radius: var(--radius-pill);
    padding: 0 var(--space-4);
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}

.detailsToggleBtn:hover{
    border-color: rgba(63, 136, 252, 0.9);
    background: rgba(223, 242, 255, 0.95);
}

.detailsToggleBtn[aria-expanded="true"]{
    border-color: rgba(49, 132, 246, 0.95);
    background: linear-gradient(90deg, rgba(84, 170, 255, 0.92), rgba(132, 203, 255, 0.95));
    color: #ffffff;
    box-shadow: 0 0 0 3px rgba(49, 132, 246, 0.2);
}

.taskDetailsPanel{
    width: 92%;
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity 0.18s ease, transform 0.18s ease, margin-top 0.18s ease;
    margin-top: 0;
}

.taskDetailsPanel.open{
    /* Bumped from 520px - deadline (plus its preset row) moved from More
       options into the always-visible primary tier, so the panel's
       collapsed-more-options height grew even though its fully-expanded
       worst case did not (more options itself now has one less field).
       overflow is visible below, not hidden, so oversized content would
       still be readable even past this cap, but it would visually spill
       outside the panel's own background/border - safer to just give it
       enough room. */
    max-height: 640px;
    overflow: visible;
    opacity: 1;
    transform: translateY(0);
    margin-top: 10px;
}

.optionsHint{
    margin-bottom: 8px;
    color: #355d87;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.3;
}

.taskDetailsPanel .matrixSelect,
.taskDetailsPanel .difficultySelect,
.taskDetailsPanel .durationInput,
.taskDetailsPanel .deadlineInput{
    backdrop-filter: none;
}

.detailsGrid{
    display: flex;
    flex-direction: column;
    gap: 10px;
    overflow: visible;
}

.matrixSelect{
    width: 100%;
    height: 50px;
    padding: 0 10px;
    border: none;
    outline: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.35);
    backdrop-filter: blur(10px);
    border: 2px solid rgba(103, 159, 255, 0.7);
    color: #1e1e1e;
    font-weight: 500;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.difficultySelect{
    width: 100%;
    height: 50px;
    padding: 0 10px;
    border: none;
    outline: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.35);
    backdrop-filter: blur(10px);
    border: 2px solid rgba(103, 159, 255, 0.7);
    color: #1e1e1e;
    font-weight: 500;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.recurrenceSelect{
    width: 100%;
    height: 50px;
    padding: 0 10px;
    border: none;
    outline: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.35);
    backdrop-filter: blur(10px);
    border: 2px solid rgba(103, 159, 255, 0.7);
    color: #1e1e1e;
    font-weight: 500;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.matrixSelect:hover{
    border-color: rgba(72, 145, 255, 0.95);
    background: rgba(246, 252, 255, 0.92);
}

.difficultySelect:hover{
    border-color: rgba(72, 145, 255, 0.95);
    background: rgba(246, 252, 255, 0.92);
}

.matrixSelect:focus,
.matrixSelect:focus-visible{
    border-color: rgba(47, 143, 255, 1);
    box-shadow: 0 0 0 4px rgba(47, 143, 255, 0.18);
    background: rgba(246, 252, 255, 0.98);
}

.difficultySelect:focus,
.difficultySelect:focus-visible{
    border-color: rgba(47, 143, 255, 1);
    box-shadow: 0 0 0 4px rgba(47, 143, 255, 0.18);
    background: rgba(246, 252, 255, 0.98);
}

.recurrenceSelect:focus,
.recurrenceSelect:focus-visible{
    border-color: rgba(47, 143, 255, 1);
    box-shadow: 0 0 0 4px rgba(47, 143, 255, 0.18);
    background: rgba(246, 252, 255, 0.98);
}

.matrixSelect option{
    background: #e8f2ff;
    color: #17375f;
    font-weight: 600;
}

.difficultySelect option{
    background: #e8f2ff;
    color: #17375f;
    font-weight: 600;
}

.effortContainer{
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
    gap: 8px;
    overflow: visible;
}

.taskTypePills{
    display: flex;
    align-items: center;
    gap: 8px;
    overflow: visible;
}

.typePill{
    border: 2px solid rgba(108, 166, 247, 0.62);
    background: rgba(238, 248, 255, 0.82);
    color: #365984;
    border-radius: 999px;
    padding: 6px 12px;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    position: relative;
}

.typePill::after{
    content: attr(data-tip);
    position: absolute;
    left: 50%;
    bottom: calc(100% + 9px);
    transform: translateX(-50%) translateY(6px);
    width: 230px;
    background: rgba(24, 43, 69, 0.95);
    color: #f2f8ff;
    border: 1px solid rgba(130, 186, 255, 0.5);
    border-radius: 10px;
    padding: 8px 10px;
    font-size: 11px;
    font-weight: 500;
    text-align: left;
    line-height: 1.35;
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
    z-index: 6;
}

.typePill:hover::after,
.typePill:focus-visible::after{
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
}

.typePill.active{
    border-color: rgba(47, 143, 255, 0.95);
    background: linear-gradient(90deg, rgba(89, 173, 255, 0.92), rgba(144, 211, 255, 0.95));
    color: #ffffff;
}

.durationWrap{
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
}

.durationWrap.hidden{
    display: none;
}

.durationInput{
    width: 110px;
    height: 44px;
    padding: 0 10px;
    border: none;
    outline: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.35);
    backdrop-filter: blur(10px);
    border: 2px solid rgba(103, 159, 255, 0.7);
    color: #1e1e1e;
    font-weight: 600;
}

.durationChips{
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.durationChip{
    border: 1px solid rgba(103, 159, 255, 0.62);
    background: rgba(239, 249, 255, 0.85);
    color: #365d87;
    border-radius: 999px;
    padding: 4px 10px;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
}

.durationChip:hover{
    border-color: rgba(47, 143, 255, 0.9);
    background: rgba(224, 243, 255, 1);
}

.durationChip.active{
    border-color: rgba(47, 143, 255, 0.95);
    background: rgba(74, 167, 255, 0.95);
    color: #ffffff;
}

.deadlineContainer{
    display: flex;
    justify-content: flex-start;
    align-items: center;
    width: 100%;
    gap: 8px;
    cursor: pointer;
    border-radius: 12px;
    transition: box-shadow 0.2s ease, background-color 0.2s ease;
}

.deadlineTag{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 34px;
    padding: 0 10px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    white-space: nowrap;
    background: rgba(43, 30, 100, 0.82);
    border: 1px solid rgba(189, 173, 255, 0.45);
    color: #f1ecff;
}

.deadlineContainer:hover{
    background: rgba(235, 247, 255, 0.45);
    box-shadow: 0 0 0 3px rgba(89, 158, 255, 0.14);
}

.deadlineInput{
    width: 100%;
    height: 50px;
    padding: 0 10px;
    border: none;
    outline: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.35);
    backdrop-filter: blur(10px);
    border: 2px solid rgba(103, 159, 255, 0.7);
    color: #1e1e1e;
    color-scheme: dark;
    font-weight: 500;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.deadlineInput::-webkit-calendar-picker-indicator{
    filter: invert(1) sepia(0.18) saturate(1.4) hue-rotate(196deg) brightness(1.2);
    opacity: 0.9;
    cursor: pointer;
}

.deadlineInput:hover{
    border-color: rgba(72, 145, 255, 0.95);
    background: rgba(246, 252, 255, 0.92);
}

.deadlineInput:focus,
.deadlineInput:focus-visible{
    border-color: rgba(47, 143, 255, 1);
    box-shadow: 0 0 0 4px rgba(47, 143, 255, 0.18);
    background: rgba(246, 252, 255, 0.98);
}

.calendarBtn{
    width: 40px;
    min-width: 40px;
    height: 40px;
    background: rgba(35, 35, 35, 1);
    border-radius: 50%;
    border: 3px solid rgb(155, 215, 255);
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
}

.calendarBtn i{
    color: #8bdaff;
    font-size: 13px;
}

.calendarBtn:hover{
    background: rgba(39, 39, 39, 0.8);
    transform: scale(1.08);
    transition: all 0.2s ease-in-out;
}

.calendarBtn:active{
    background: rgb(16, 16, 16);
    transform: scale(0.92);
    transition: all 0.2s ease-in-out;
}

.addBtn{
    width: 35px;
    height: 35px;
    background: rgba(35, 35, 35, 1);
    border-radius: var(--radius-circle);
    border: 3px solid rgb(155, 215, 255);
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
}

.addBtn i{
    color: #8bdaff;
    font-size: 12px;
}

.addBtn:hover{
    background: rgba(39, 39, 39, 0.8);
    transform: scale(1.1);
    transition: all 0.2s ease-in-out;
}

.addBtn:active{
    background: rgb(16, 16, 16);
    transform: scale(0.9);
    transition: all 0.2s ease-in-out;
}

.deadlinePresets{
    width: 100%;
    margin-top: 10px;
    display: none;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 8px;
}

.taskDetailsPanel.show-presets .deadlinePresets{
    display: flex;
}

.schedulePresets{
    width: 100%;
    margin-top: 10px;
    display: none;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 8px;
}

.taskDetailsPanel.show-schedule-presets .schedulePresets{
    display: flex;
}

.urgencyAlert{
    width: 92%;
    margin-top: 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    border-radius: 10px;
    border: 2px solid rgba(95, 160, 255, 0.58);
    background: rgba(237, 248, 255, 0.75);
    padding: 9px 11px;
}

.urgencyAlert.hidden{
    display: none;
}

.urgencyAlert.urgency-soon{
    border-color: rgba(255, 191, 84, 0.85);
    background: rgba(255, 244, 218, 0.9);
}

.urgencyAlert.urgency-critical,
.urgencyAlert.urgency-overdue{
    border-color: rgba(250, 118, 107, 0.85);
    background: rgba(255, 228, 224, 0.92);
}

.urgencyAlertText{
    font-size: 12px;
    color: #24476f;
    font-weight: 700;
}

.notifyEnableBtn{
    height: 30px;
    border: 1px solid rgba(95, 160, 255, 0.65);
    border-radius: 999px;
    padding: 0 10px;
    background: rgba(247, 252, 255, 0.86);
    color: #265580;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
}

.notifyEnableBtn.hidden{
    display: none;
}

.deadlinePresetBtn{
    border: 1px solid rgba(98, 160, 250, 0.6);
    background: rgba(237, 248, 255, 0.78);
    color: #2b4f7b;
    border-radius: 999px;
    padding: 6px 10px;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.18s ease, background-color 0.18s ease, border-color 0.18s ease;
}

.deadlinePresetBtn:hover{
    background: rgba(219, 240, 255, 0.95);
    border-color: rgba(63, 136, 252, 0.9);
    transform: translateY(-1px);
}

.deadlinePresetBtn:active{
    transform: translateY(0);
}

.priorityControls{
    width: 92%;
    margin-top: 10px;
    padding: 8px 12px;
    /* Was a raw 10px, sitting between the actual --radius-sm/-md tokens
       (8/12px) rather than matching either - snapped to the scale so
       corners stop drifting from every other card on the page. */
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.33);
    border: 2px solid rgba(103, 159, 255, 0.6);
}

.priorityHeaderRow{
    display: flex;
    justify-content: flex-start;
    align-items: center;
    gap: 8px;
}

.priorityToggleLabel{
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    font-weight: 700;
    color: #1e1e1e;
    cursor: pointer;
}

.priorityToggle{
    width: 16px;
    height: 16px;
    accent-color: #2f8fff;
    cursor: pointer;
}

.priorityModeHint{
    margin-top: 6px;
    font-size: 12px;
    /* Was #29334a (a leftover from the original light-mode pass, never
       repainted for dark) - near-black on the dark violet card background,
       functionally invisible. Real contrast bug, not a style choice. */
    color: var(--violet-muted, #d7d0ff);
}

.sortOnceBtn{
    border: 2px solid rgba(80, 150, 250, 0.7);
    background: rgba(233, 246, 255, 0.78);
    color: #245787;
    height: 32px;
    border-radius: 999px;
    padding: 0 12px;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    transition: background-color 0.2s ease, transform 0.2s ease;
}

.sortOnceBtn:hover:not(:disabled){
    background: rgba(214, 237, 255, 0.98);
    transform: translateY(-1px);
}

.sortOnceBtn:disabled{
    opacity: 0.55;
    cursor: not-allowed;
}

.alertToggleBtn{
    border: 2px solid rgba(238, 176, 64, 0.72);
    background: rgba(255, 247, 224, 0.9);
    color: #8a5a16;
    height: 32px;
    border-radius: 999px;
    padding: 0 10px;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
    margin-left: auto;
    transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
}

.alertToggleBtn:hover{
    border-color: rgba(226, 151, 30, 0.84);
    background: rgba(255, 240, 199, 0.95);
}

.alertToggleBtn.enabled{
    border-color: rgba(49, 156, 99, 0.86);
    background: rgba(218, 248, 230, 0.95);
    color: #146739;
}

.alertToggleBtn.enabled:hover{
    border-color: rgba(36, 142, 87, 0.92);
    background: rgba(204, 244, 220, 0.98);
}

.metaVisibilityRow{
    display: none;
}

/* Now living in Settings (section A of the UI/UX rework - see settings.js's
   buildOverlay), so it's unconditionally visible there rather than only
   ≤900px the way it was in its old sideColumn spot - Settings itself is
   reachable regardless of viewport. Uses the shared .toggleSwitch component
   below (also used by settings.js's own Mute toggle, right above this one) -
   an earlier version of this comment noted this matched .settingsToggleRow's
   plain-native-checkbox look instead of the old sideColumn's bespoke pill
   switch; direct feedback that a bare native checkbox "looks plain default"
   reversed that call for both of them at once, not just this one. */
.settingsAlertsSection .metaVisibilityRow{
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--violet-muted, #d7d0ff);
    cursor: pointer;
}

/* ===================================================================
   Toggle switch - a real custom on/off control for boolean settings,
   replacing what was a bare native checkbox with only accent-color
   applied (looked like unstyled browser chrome next to everything else
   in Settings - direct feedback). Standard hidden-input + track + thumb
   structure (see app.html's .metaVisibilityRow and settings.js's own
   Mute toggle markup for usage), not appearance:none plus pseudo-
   elements on the <input> itself - ::before/::after support on <input>
   is inconsistent across browsers, real sibling elements aren't. Lives
   here rather than duplicated into settings.js's own injected <style>
   (see the comment there) since style.css is already a hard dependency
   of every page settings.js runs on - one canonical version beats two
   that can quietly drift apart.
   =================================================================== */
.toggleSwitch{
    position: relative;
    display: inline-flex;
    flex: 0 0 auto;
    width: 40px;
    height: 22px;
}

.toggleSwitch input{
    position: absolute;
    inset: 0;
    z-index: 1;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.toggleSwitchTrack{
    position: absolute;
    inset: 0;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.14);
    border: 1px solid var(--violet-border, rgba(181, 139, 255, 0.35));
    transition: background 0.2s ease, border-color 0.2s ease;
}

.toggleSwitchThumb{
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #f3f0ea;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.35);
    transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), background 0.2s ease;
}

.toggleSwitch input:checked + .toggleSwitchTrack{
    background: linear-gradient(135deg, var(--violet-accent, #b58bff), var(--violet-accent-2, #7f6fe8));
    border-color: transparent;
}

.toggleSwitch input:checked + .toggleSwitchTrack .toggleSwitchThumb{
    transform: translateX(18px);
    background: #120b30;
}

.toggleSwitch input:hover + .toggleSwitchTrack{
    border-color: var(--violet-accent, #b58bff);
}

.toggleSwitch input:focus-visible + .toggleSwitchTrack{
    outline: none;
    box-shadow: 0 0 0 3px rgba(181, 139, 255, 0.4);
}

@media (prefers-reduced-motion: reduce){
    .toggleSwitchTrack,
    .toggleSwitchThumb{
        transition: none;
    }
}

/* .alertToggleBtn's base rule (above) has margin-left:auto, meant to push it
   to the far edge of .priorityHeaderRow's flex row - meaningless (and here,
   actively wrong) in .settingsAlertsSection's simple vertical stack. */
.settingsAlertsSection .alertToggleBtn{
    margin-left: 0;
    margin-bottom: var(--space-2);
}

.taskViews{
    width: 92%;
    margin-top: 10px;
    margin-bottom: 2px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}


.activityPanel{
    width: 92%;
    margin-top: 4px;
    margin-bottom: 14px;
    padding: 10px 10px 12px;
    border-radius: 10px;
    border: 2px solid rgba(103, 159, 255, 0.58);
    background: rgba(243, 250, 255, 0.62);
}

.activityHeader{
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 8px;
}

.activityTitle{
    font-size: 14px;
    font-weight: 800;
    color: #264f79;
}

.activitySummary{
    font-size: 11px;
    color: #3d638e;
}

.activityGridWrap{
    --weeks: 26;
    --rows: 7;
    --cell-gap: 3px;
    --day-label-width: 30px;
    overflow-x: auto;
    overflow-y: hidden;
    padding-bottom: 2px;
}

.activityMonthRow{
    margin-left: calc(var(--day-label-width) + 4px);
    display: grid;
    grid-template-columns: repeat(var(--weeks), minmax(0, 1fr));
    gap: var(--cell-gap);
    margin-bottom: 5px;
    min-height: 14px;
}

.activityMonthLabel{
    font-size: 10px;
    line-height: 1;
    color: #4b6790;
    white-space: nowrap;
    justify-self: start;
}

.activityBody{
    display: grid;
    grid-template-columns: var(--day-label-width) 1fr;
    align-items: stretch;
    gap: 4px;
}

.activityDayLabels{
    display: grid;
    grid-template-rows: repeat(var(--rows), minmax(0, 1fr));
    gap: var(--cell-gap);
    width: var(--day-label-width);
    height: 100%;
}

.activityDayLabel{
    font-size: 9px;
    line-height: 1;
    color: #5d769a;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-right: 3px;
}

.activityGrid{
    display: grid;
    grid-template-columns: repeat(var(--weeks), minmax(0, 1fr));
    grid-template-rows: repeat(var(--rows), minmax(0, 1fr));
    grid-auto-flow: column;
    gap: var(--cell-gap);
    width: 100%;
    aspect-ratio: calc(var(--weeks) / var(--rows));
}

.heatCell{
    width: 100%;
    height: 100%;
    border-radius: 3px;
    border: 1px solid rgba(85, 133, 194, 0.25);
    background: rgba(215, 227, 241, 0.8);
}

.heatCell.level-0{ background: rgba(213, 225, 240, 0.72); }
.heatCell.level-1{ background: rgba(178, 218, 244, 0.78); }
.heatCell.level-2{ background: rgba(134, 202, 245, 0.82); }
.heatCell.level-3{ background: rgba(86, 182, 242, 0.9); }
.heatCell.level-4{ background: rgba(35, 153, 235, 0.95); }

.heatCell.outside-window{
    opacity: 0.28;
}

.activityLegend{
    margin-top: 8px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 5px;
    font-size: 11px;
    color: #3c618d;
}

.activityLegend .heatCell{
    width: 14px;
    height: 14px;
    flex: 0 0 14px;
    display: inline-block;
}

.taskViewBtn{
    border: 2px solid rgba(120, 177, 255, 0.55);
    background: rgba(255, 255, 255, 0.48);
    color: #355780;
    border-radius: 999px;
    padding: 5px 11px;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.2s ease;
}

.taskViewBtn:hover{
    border-color: rgba(71, 147, 255, 0.9);
    background: rgba(231, 245, 255, 0.96);
}

.taskViewBtn.active{
    border-color: rgba(46, 139, 255, 0.95);
    background: linear-gradient(90deg, rgba(92, 175, 255, 0.9), rgba(141, 210, 255, 0.95));
    color: #ffffff;
}

.tasks{
    list-style: none;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    gap: 10px;
    width: 100%;
    transform: translateY(20px);
}

.tasks li{
    width: 90%;
    padding: 10px;
    background: rgba(255, 255, 255, 0.4);
    border-radius: 10px;
    border: 2px solid rgba(103, 159, 255, 0.7);
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    cursor: grab;
    will-change: transform;
    position: relative;
    transition: box-shadow 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;

}

.taskTopRow{
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    gap: 10px;
}

.tasks li.status-soon{
    border-color: rgba(255, 191, 84, 0.9);
}

.tasks li.status-critical{
    border-color: rgba(255, 147, 83, 0.95);
    box-shadow: 0 0 0 3px rgba(255, 172, 104, 0.22);
}

.tasks li.status-overdue{
    border-color: rgba(248, 118, 111, 0.95);
    box-shadow: 0 0 0 3px rgba(248, 118, 111, 0.2);
    animation: overduePulse 1.8s ease-in-out infinite;
}

@keyframes overduePulse{
    0% { box-shadow: 0 0 0 0 rgba(248, 118, 111, 0.25); }
    70% { box-shadow: 0 0 0 8px rgba(248, 118, 111, 0); }
    100% { box-shadow: 0 0 0 0 rgba(248, 118, 111, 0); }
}

.tasks.priority-on li{
    cursor: default;
}

.tasks.priority-on li::after{
    content: 'Auto sorted';
    position: absolute;
    top: -9px;
    left: 10px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.2px;
    color: #ffffff;
    background: rgba(41, 129, 236, 0.9);
    border-radius: 999px;
    padding: 3px 8px;
    pointer-events: none;
    opacity: 0;
    transform: translateY(-2px);
    transition: opacity 0.2s ease;
}

.tasks.priority-on li:hover::after{
    opacity: 1;
}

.tasks li:active{
    cursor: grabbing;
}

.tasks li.dragging{
    opacity: 0.55;
    border-color: rgba(75, 162, 255, 1);
    background: rgba(222, 244, 255, 0.9);
    box-shadow: 0 14px 24px rgba(36, 112, 200, 0.25);
}

.tasks li.drag-over-slot{
    border-color: rgba(47, 143, 255, 1);
    background: rgba(236, 250, 255, 1);
    box-shadow: 0 0 0 4px rgba(47, 143, 255, 0.24), 0 10px 20px rgba(47, 143, 255, 0.18);
    transform: scale(1.015);
}

.tasks li.drag-over-slot::before{
    content: 'Drop to swap';
    position: absolute;
    top: -11px;
    right: 10px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.3px;
    color: #ffffff;
    background: #2f8fff;
    border-radius: 999px;
    padding: 4px 8px;
    box-shadow: 0 4px 10px rgba(47, 143, 255, 0.35);
    pointer-events: none;
}

.tasks.drag-active li:not(.dragging):not(.drag-over-slot){
    opacity: 0.72;
    border-style: dashed;
}

.tasks.drag-active li.drag-over-slot,
.tasks.drag-active li.dragging{
    opacity: 1;
}

.tasks.drag-active li *{
    pointer-events: none;
}

/* Premium gradient overdue alert */
.urgencyAlert.urgency-overdue{
    background: linear-gradient(135deg, rgba(255, 115, 140, 0.24) 0%, rgba(214, 90, 122, 0.28) 35%, rgba(132, 74, 171, 0.34) 100%);
    border-color: rgba(255, 148, 169, 0.85);
    box-shadow: 0 8px 24px rgba(112, 42, 86, 0.35), inset 0 1px 0 rgba(255, 220, 228, 0.28);
}

.urgencyAlert.urgency-overdue .urgencyAlertText{
    color: #ffe9ef;
    text-shadow: 0 1px 0 rgba(76, 24, 47, 0.45);
}

.taskMain{
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    width: 100%;
}

.taskContent{
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
    min-width: 0;
}

.taskText{
    color: #1e1e1e;
    word-break: break-word;
}

/* Law of Common Region (section D): a shared, subtle background rail behind
   the whole badge cluster (matrix, difficulty, deadline, effort, schedule)
   so it reads as one "task metadata" unit distinct from the task text above
   it, instead of five independent floating chips with no visual grouping. */
.taskMeta{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 4px 6px;
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.04);
}

.taskMeta:empty{
    padding: 0;
    background: transparent;
}

.matrixBadge,
.deadlineBadge,
.countdownBadge{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    padding: 4px 8px;
    font-size: 11px;
    font-weight: 700;
    border: 1px solid transparent;
}

.effortBadge{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    padding: 4px 8px;
    font-size: 11px;
    font-weight: 700;
    border: 1px solid transparent;
    background: #eaf0ff;
    border-color: #cbd8ff;
    color: #2d468d;
}

.difficultyBadge{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    padding: 4px 8px;
    font-size: 11px;
    font-weight: 700;
    border: 1px solid transparent;
}

.difficulty-1{
    background: #edf9ee;
    border-color: #cdeccd;
    color: #2c6b35;
}

.difficulty-2{
    background: #e8f6ff;
    border-color: #c6e5fb;
    color: #2b5e87;
}

.difficulty-3{
    background: #fff5df;
    border-color: #f3ddb1;
    color: #8a6112;
}

.difficulty-4{
    background: #ffeada;
    border-color: #f7caad;
    color: #8c4217;
}

.difficulty-5{
    background: #ffe2e2;
    border-color: #f3bcbc;
    color: #8b2222;
}

.subtaskProgressBadge{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    padding: 4px 8px;
    font-size: 11px;
    font-weight: 700;
    border: 1px solid #cbd8ff;
    background: #eef2ff;
    color: #3a4c8f;
}

.scheduleBadge{
    display: inline-flex;
    align-items: center;
    gap: 4px;
    border-radius: 999px;
    padding: 4px 8px;
    font-size: 11px;
    font-weight: 700;
    border: 1px solid #cbd8ff;
    background: #eef2ff;
    color: #3a4c8f;
}

.recurrenceBadge{
    display: inline-flex;
    align-items: center;
    gap: 4px;
    border-radius: 999px;
    padding: 4px 8px;
    font-size: 11px;
    font-weight: 700;
    border: 1px solid #cbd8ff;
    background: #eef2ff;
    color: #3a4c8f;
}

.snoozeSection{
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 8px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.35);
    border: 1px solid rgba(103, 159, 255, 0.4);
}

.snoozeSection.hidden{
    display: none;
}

.snoozeLabel{
    font-size: 12px;
    font-weight: 700;
    color: #365984;
}

.subtasksSection{
    width: 100%;
}

.subtasksToggleBtn{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: none;
    background: transparent;
    color: #365984;
    font-size: 11px;
    font-weight: 700;
    padding: 2px 0;
    cursor: pointer;
}

.subtasksToggleBtn i{
    font-size: 9px;
    width: 10px;
    text-align: center;
}

.subtasksToggleBtn:hover{
    color: #1f4c88;
}

.subtasksBody{
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 6px;
    padding-left: 4px;
}

.subtasksBody.hidden{
    display: none;
}

.subtasksList{
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.subtaskItem{
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 6px 8px;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.4);
    border: 1px solid rgba(103, 159, 255, 0.4);
}

.subtaskRow{
    display: flex;
    align-items: center;
    gap: 8px;
}

.subtaskCheckBtn,
.subtaskDeleteBtn,
.subtaskDeadlineBtn,
.subtaskRenameBtn{
    background: transparent;
    border: none;
    outline: none;
    cursor: pointer;
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.subtaskCheckBtn{
    border: 1px solid rgba(103, 159, 255, 0.7);
    color: transparent;
}

.subtaskCheckBtn i{
    font-size: 10px;
}

.subtaskItem.completed .subtaskCheckBtn{
    background: rgba(35, 35, 35, 1);
    border-color: rgb(155, 215, 255);
    color: #8bdaff;
}

.subtaskDeleteBtn{
    color: #8fa3c2;
    font-size: 11px;
}

.subtaskDeleteBtn:hover{
    color: #d0473f;
}

.subtaskDeadlineBtn{
    color: #8fa3c2;
    font-size: 11px;
}

.subtaskDeadlineBtn:hover{
    color: #4a92f6;
}

.subtaskRenameBtn{
    color: #8fa3c2;
    font-size: 11px;
}

.subtaskRenameBtn:hover{
    color: #7c5fd6;
}

.subtaskText{
    flex: 1;
    min-width: 0;
    word-break: break-word;
    font-size: 13px;
    color: #1e1e1e;
}

.subtaskText.hidden{
    display: none;
}

.subtaskRenameInput{
    flex: 1;
    min-width: 0;
    height: 26px;
    padding: 0 8px;
    border: none;
    outline: none;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.5);
    border: 1px solid rgba(103, 159, 255, 0.5);
    font-size: 13px;
    color: #1e1e1e;
}

.subtaskRenameInput.hidden{
    display: none;
}

.subtaskDeadlineBadge{
    flex: 0 0 auto;
    border-radius: 999px;
    padding: 2px 7px;
    font-size: 10px;
    font-weight: 700;
    border: 1px solid transparent;
}

.subtaskDeadlineBadge.hidden{
    display: none;
}

.subtaskDeadlineInputWrap{
    display: flex;
    align-items: center;
    gap: 8px;
}

.subtaskDeadlineInputWrap.hidden{
    display: none;
}

.subtaskDeadlineInput{
    flex: 1;
    min-width: 0;
    height: 30px;
    padding: 0 8px;
    border: none;
    outline: none;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.5);
    border: 1px solid rgba(103, 159, 255, 0.5);
    font-size: 11px;
    color: #1e1e1e;
}

.subtaskDeadlineClearBtn{
    flex: 0 0 auto;
    background: transparent;
    border: none;
    color: #8fa3c2;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
}

.subtaskDeadlineClearBtn:hover{
    color: #d0473f;
}

.subtaskItem.completed .subtaskText{
    text-decoration: line-through;
    opacity: 0.65;
}

.subtaskAddRow{
    display: flex;
    align-items: center;
    gap: 8px;
}

.subtaskInput{
    flex: 1;
    min-width: 0;
    height: 34px;
    padding: 0 10px;
    border: none;
    outline: none;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.5);
    border: 1px solid rgba(103, 159, 255, 0.5);
    font-size: 12px;
    color: #1e1e1e;
}

.subtaskAddBtn{
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: rgba(35, 35, 35, 1);
    border: 2px solid rgb(155, 215, 255);
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
}

.subtaskAddBtn i{
    color: #8bdaff;
    font-size: 10px;
}

.subtaskAddBtn:hover{
    background: rgba(39, 39, 39, 0.8);
    transform: scale(1.08);
    transition: all 0.2s ease-in-out;
}

.emptyTasksMsg{
    width: 90%;
    text-align: center;
    padding: 14px 10px;
    border-radius: 10px;
    border: 2px dashed rgba(103, 159, 255, 0.55);
    color: #406088;
    font-size: 13px;
    font-weight: 600;
    background: rgba(245, 252, 255, 0.62);
    cursor: default;
}

.matrix-do{
    background: #ffe3de;
    border-color: #ffb7ac;
    color: #8f1f10;
}

.matrix-schedule{
    background: #ecf0ff;
    border-color: #cdd8ff;
    color: #2e3f8f;
}

.matrix-delegate{
    background: #fff3df;
    border-color: #ffd8a6;
    color: #8a4f00;
}

.matrix-eliminate{
    background: #e7efe9;
    border-color: #c8dacd;
    color: #375846;
}

/* Auto-escalated by a close deadline (getEffectiveMatrix in task-shared.js) -
   a dashed border so it reads as "became this", not "was set to this". */
.matrixEscalated{
    border-style: dashed;
    cursor: help;
}

.deadline-none,
.countdown-none{
    background: #eef2f8;
    border-color: #d5dce7;
    color: #4d617f;
}

.deadline-normal,
.countdown-normal{
    background: #e8f4ff;
    border-color: #bedffd;
    color: #2e5f96;
}

.deadline-soon,
.countdown-soon{
    background: #fff2dd;
    border-color: #ffd9a2;
    color: #8b5600;
}

.deadline-critical,
.countdown-critical{
    background: #ffe4d8;
    border-color: #ffc095;
    color: #9a4b00;
}

.deadline-overdue,
.countdown-overdue{
    background: #ffe2e0;
    border-color: #ffb9b4;
    color: #9f2318;
}

.checkBtn{
    background: transparent;
    border: none;
    outline: none;
}

.taskButtons{
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;
    background: transparent;

}

/* Real bug found by actually rendering a task row at 320-430px (not just
   reading the CSS): .taskMain has min-width:0 so the flex algorithm is
   free to shrink it toward zero once Edit/Snooze/Delete (all three with
   visible text labels now) claim the width they need on the same row -
   verified this collapses task text to one letter per line on a narrow
   phone, since there was nowhere left for it to go. Unscoped (not
   .mainColumn-prefixed) since solo and group build identical
   .taskTopRow/.taskMain/.taskButtons markup and share this exact bug.
   Fix: below the existing 560px "phone" tier, stop trying to fit both on
   one row at all - task text gets the row to itself, the button cluster
   drops to its own row underneath, right-aligned. More reliable than
   chasing an exact pixel threshold, since task titles are arbitrary
   length and three labeled buttons take a different amount of room
   depending on which are present (Snooze only shows when a task has a
   deadline). */
@media (max-width: 560px){
    .taskTopRow{
        flex-wrap: wrap;
    }

    .taskMain{
        min-width: 100%;
    }

    .taskButtons{
        width: 100%;
        justify-content: flex-end;
    }
}

/* Edit/Snooze/Delete (section D): the shape/background/border that used to
   live on the icon itself moves to the button, since each button now also
   carries a .taskBtnLabel span next to its icon (Snooze permanently,
   Edit/Delete only ≤900px, both below) - the icon alone can't provide a
   circle-becomes-pill background once there's a label sitting beside it. */
.editBtn,
.deleteBtn,
.snoozeBtn,
.handoffBtn,
.handoffPendingBtn{
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 30px;
    height: 30px;
    padding: 0;
    background: rgba(35, 35, 35, 1);
    border: 1px solid rgb(155, 215, 255);
    border-radius: var(--radius-pill);
    cursor: pointer;
}

.taskButtons i{
    color: #8bdaff;
    font-size: 14px;
    cursor: pointer;
}

.taskBtnLabel{
    display: none;
    font-size: var(--text-xs);
    font-weight: 700;
    color: inherit;
    white-space: nowrap;
}

/* Snooze keeps its label at every width - the least universally-recognized
   of the three (section D/M), so it doesn't get to fall back to icon-only
   the way Edit/Delete do. */
.snoozeBtn{
    width: auto;
    padding: 0 var(--space-3);
}

.snoozeBtn .taskBtnLabel{
    display: inline;
}

/* Handoff keeps its label at every width too, same reasoning as Snooze
   right above - "right-left arrows" isn't any more universally recognized
   icon-only than a clock is. */
.handoffBtn,
.handoffPendingBtn{
    width: auto;
    padding: 0 var(--space-3);
}

.handoffBtn .taskBtnLabel,
.handoffPendingBtn .taskBtnLabel{
    display: inline;
}

/* Pending gets the same "already looks different at rest" treatment
   .deleteBtn gets below for its own (opposite) meaning - reuses the
   existing --color-warning token rather than inventing a new color, since
   this is a "waiting on someone" state, not a destructive one. */
.handoffPendingBtn{
    background: var(--color-warning-soft);
    border-color: var(--color-warning);
}

.handoffPendingBtn i,
.handoffPendingBtn .taskBtnLabel{
    color: var(--color-warning);
}

/* Delete gets --color-danger tinting at rest, not just on hover - Jakob's
   Law: the one destructive action in the cluster should already look
   different before it's even touched, matching the convention every other
   app already trains people to expect. */
.deleteBtn{
    background: var(--color-danger-soft, rgba(255, 107, 107, 0.16));
    border-color: var(--color-danger, #ff6b6b);
}

.deleteBtn i{
    color: var(--color-danger-strong, #e03131);
}

@media (max-width: 900px){
    /* height bumped alongside width:auto - a real touch target needs both
       dimensions at a sane minimum, not just a wide-enough pill that's
       still only 30px tall. Width itself is NOT capped here on purpose:
       .mainColumn .editBtn/.deleteBtn below used to hard-set width:42px
       here too (a leftover from before these got a text label), which
       silently won on specificity and crushed "Edit"/"Delete" into a
       fixed 42px circle - the label overflowed/clipped past the button's
       own edge instead of the pill actually growing to fit it. Verified
       the collision directly (real button, real label, 375px viewport)
       before removing it. */
    .editBtn,
    .deleteBtn{
        width: auto;
        height: 42px;
        padding: 0 var(--space-3);
    }

    .editBtn .taskBtnLabel,
    .deleteBtn .taskBtnLabel{
        display: inline;
    }
}

.editBtn:hover,
.deleteBtn:hover,
.snoozeBtn:hover,
.handoffBtn:hover,
.handoffPendingBtn:hover{
    background: rgba(39, 39, 39, 0.8);
    transform: scale(1.05);
    transition: all 0.2s ease-in-out;
}

.deleteBtn:hover{
    background: var(--color-danger-soft, rgba(255, 107, 107, 0.28));
}

/* Keeps its amber "waiting" identity on hover instead of flattening to the
   generic dark hover above - same override pattern .deleteBtn:hover uses
   for its own semantic tint. */
.handoffPendingBtn:hover{
    background: var(--color-warning-soft);
    filter: brightness(1.12);
}

.editBtn:active,
.deleteBtn:active,
.snoozeBtn:active{
    background: rgb(16, 16, 16);
    transform: scale(0.94);
    transition: all 0.2s ease-in-out;
}

.deleteBtn:active{
    background: var(--color-danger, #ff6b6b);
}

.checkBtn i{
    color: transparent;
    font-size: 14px;
    cursor: pointer;
    background: rgba(255, 255, 255, 0.75);
    width: 30px;
    height: 30px;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 50%;
    border: 1px solid rgba(155, 215, 255, 0.95);
    opacity: 0.5;
}

.checkBtn i:hover{
    background: rgba(255, 255, 255, 0.9);
    transform: scale(1.1);
    transition: all 0.2s ease-in-out;
}

.checkBtn i:active{
    background: rgba(255, 255, 255, 1);
    transform: scale(0.9);
    transition: all 0.2s ease-in-out;
}

.tasks li.completed .checkBtn i{
    color: #8bdaff;
    background: rgba(35, 35, 35, 1);
    border: 1px solid rgb(155, 215, 255);
    opacity: 1;
}

.tasks li.completed .checkBtn i:hover{
    background: rgba(39, 39, 39, 0.8);
}

.tasks li.completed .checkBtn i:active{
    background: rgb(16, 16, 16);
}

.tasks li.completed .taskText{
    text-decoration: line-through;
    opacity: 0.7;
}

.taskEditorOverlay{
    position: fixed;
    inset: 0;
    background: rgba(8, 18, 38, 0.42);
    display: none;
    justify-content: center;
    align-items: center;
    padding: var(--space-5);
    z-index: 20;
}

.taskEditorOverlay.open{
    display: flex;
}

.taskEditorCard{
    width: min(460px, 95vw);
    /* Real bug, found by actually rendering this with "More options" open
       on a landscape phone (667x375): with no height cap and
       overflow-y:visible, the expanded form (Task/Matrix/Difficulty/
       Deadline/More options/Save) runs well past 375px tall, and
       .taskEditorOverlay centers it - so it overflowed the viewport on
       BOTH edges equally, with no way to scroll. The Save button was
       literally unreachable. calc(100vh - 40px) leaves the same 20px
       breathing room top and bottom as .taskEditorOverlay's own padding. */
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    background: rgba(247, 252, 255, 0.95);
    border: 2px solid rgba(74, 146, 246, 0.5);
    border-radius: var(--radius-lg);
    box-shadow: 0 20px 44px rgba(28, 67, 128, 0.3);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.taskEditorCard h2{
    font-size: var(--text-xl);
    color: #1f2d4a;
}

.taskEditorCard label{
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 700;
    color: #273451;
}

.editorTextInput,
.editorMatrixSelect,
.editorDeadlineInput{
    width: 100%;
    height: 44px;
    padding: 0 var(--space-2);
    border: 2px solid rgba(91, 152, 255, 0.45);
    border-radius: var(--radius-sm);
    outline: none;
    background: #ffffff;
    color: #1a1a1a;
    font-weight: 500;
    font-size: var(--text-base);
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.editorTaskTypeSelect,
.editorDifficultySelect,
.editorRecurrenceSelect,
.editorDurationInput{
    width: 100%;
    height: 44px;
    padding: 0 var(--space-2);
    border: 2px solid rgba(91, 152, 255, 0.45);
    border-radius: var(--radius-sm);
    outline: none;
    background: #ffffff;
    color: #1a1a1a;
    font-weight: 500;
    font-size: var(--text-base);
}

.editorEffortRow{
    display: flex;
    gap: var(--space-2);
}

.editorDurationInput.hidden{
    display: none;
}

.editorTextInput:focus,
.editorMatrixSelect:focus,
.editorDeadlineInput:focus{
    border-color: rgba(47, 143, 255, 1);
    box-shadow: 0 0 0 4px rgba(47, 143, 255, 0.16);
    background: #f6fbff;
}

.editorTaskTypeSelect:focus,
.editorDifficultySelect:focus,
.editorDurationInput:focus{
    border-color: rgba(47, 143, 255, 1);
    box-shadow: 0 0 0 4px rgba(47, 143, 255, 0.16);
    background: #f6fbff;
}

.editorMatrixSelect,
.editorDeadlineInput,
.editorTaskTypeSelect,
.editorDifficultySelect{
    cursor: pointer;
}

.editorMatrixSelect:hover,
.editorDeadlineInput:hover{
    border-color: rgba(63, 136, 252, 0.95);
    background: #f6fbff;
}

.editorMatrixSelect option{
    background: #e8f2ff;
    color: #17375f;
    font-weight: 600;
}

.editorDeadlineWrap{
    display: flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: box-shadow 0.2s ease, background-color 0.2s ease;
}

.editorDeadlineWrap:hover{
    background: rgba(232, 243, 255, 0.75);
    box-shadow: 0 0 0 3px rgba(89, 158, 255, 0.14);
}

.editorCalendarBtn{
    width: 40px;
    min-width: 40px;
    height: 40px;
    border-radius: var(--radius-circle);
    border: 2px solid #8ec6ff;
    background: #243343;
    cursor: pointer;
    color: #8ec6ff;
}

.editorCalendarBtn:hover{
    transform: scale(1.07);
    transition: transform 0.2s ease;
}

.editorActions{
    display: flex;
    justify-content: flex-end;
    gap: var(--space-3);
}

.editorCancelBtn,
.editorSaveBtn{
    height: 38px;
    padding: 0 var(--space-4);
    border-radius: var(--radius-sm);
    border: 2px solid transparent;
    cursor: pointer;
    font-weight: 700;
    font-size: var(--text-sm);
}

.editorCancelBtn{
    background: rgba(232, 237, 248, 1);
    border-color: rgba(186, 200, 226, 0.9);
    color: #38517a;
}

.editorSaveBtn{
    background: #2f8fff;
    border-color: #58a4ff;
    color: #ffffff;
}

.groupWelcomeIntro{
    font-size: var(--text-sm);
    line-height: 1.5;
    color: #4d617f;
    margin: -4px 0 0;
}

@media (max-width: 620px){
    .title{
        font-size: 32px;
    }

    .motivatorText{
        font-size: 21px;
    }

    .taskAmountContainer{
        left: 55px;
    }

    .progressBarContainer{
        width: 220px;
        transform: translateX(-38px);
    }

    .addBtn{
        width: 40px;
        height: 40px;
    }

    .priorityHeaderRow{
        flex-direction: column;
        align-items: flex-start;
    }

    .activityHeader{
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }

    .activityMonthLabel{
        font-size: 9px;
    }

    .activityPanel{
        margin-bottom: 16px;
    }

    .activityGridWrap{
        --day-label-width: 24px;
        --cell-gap: 2px;
    }

    .activityDayLabel{
        font-size: 8px;
        padding-right: 2px;
    }
}

/*
 * DESIGN SYSTEM — the only values new CSS should use.
 * Added as part of the UI/UX rework (see plan.md). Every font-size, padding/margin/gap,
 * border-radius, and semantic color from here on should reference one of these tokens
 * instead of a new one-off literal. This list is how the app avoided ending up with
 * 18 different font sizes and 240 spacing values, 50% off the 4px grid, again.
 *
 * Type scale (8 steps, dashboards get tighter sizes than a landing page would):
 *   --text-2xs 10px  timestamps, tiny counts, fine print
 *   --text-xs  11px  badge labels, secondary meta text
 *   --text-sm  12px  default UI text: buttons, form labels, most body copy
 *   --text-base 14px task text itself, primary readable content
 *   --text-md  16px  card/section titles, modal headers
 *   --text-lg  20px  dashboard section headers
 *   --text-xl  24px  page-level headers
 *   --text-2xl 32px  app title, auth brand
 *
 * Spacing scale (standard 4pt system): --space-1 through --space-8.
 * Radius tiers: --radius-sm (inputs/chips/badges), --radius-md (cards/panels/rows),
 *   --radius-lg (modals/overlays), --radius-pill (tabs/pill buttons, 999px),
 *   --radius-circle (avatars/icon buttons, 50%).
 * Semantic color: --color-danger/--color-warning/--color-success/--color-info,
 *   for meaning (delete, overdue, success, focus), not decoration.
 */
/* Premium violet gradient mode - re-skinned toward a near-black,
   consulting.com-style "editorial dark" canvas: the accent violet is the
   one saturated color in the system (like their gold), everything else
   is close to true black with only a whisper of violet cast, and surfaces
   read as hairline-bordered cards rather than glowing panels. */
:root{
    /* These three need real spread between them, not just three near-
       identical near-black hexes - #030204→#060409→#0a0712 all sit within
       a few RGB units of each other, so the page's 150deg gradient was
       rendering as a flat black rectangle with no visible sweep at all.
       Still near-black-violet overall (bg-1 stays almost pure black), but
       bg-3 is now a genuinely darker-but-distinct violet so the gradient
       across the page is actually visible, not just present in the code. */
    --violet-bg-1: #030204;
    --violet-bg-2: #0a0620;
    --violet-bg-3: #170b3e;
    --violet-surface: rgba(28, 19, 58, 0.85);
    --violet-surface-soft: rgba(24, 16, 50, 0.6);
    --violet-border: rgba(181, 139, 255, 0.24);
    --violet-border-soft: rgba(181, 139, 255, 0.13);
    --violet-text: #f6f4ff;
    --violet-muted: #d7d0ff;
    --violet-accent: #b58bff;
    --violet-accent-2: #7f86ff;

    /* Shared "dark card" recipe - the one surface treatment every modal/
       panel/task-row should use, instead of each repeating its own
       near-identical literal gradient (see .tasks li, .taskEditorCard,
       .brainDumpCard, .activityDetailsCard, .tourCard, .rewardCard,
       .authCard, .groupHistoryPanel, .leaderboardMemberModalCard,
       .nextTaskPanel below). Dark, but still a real violet gradient, not
       a near-monochrome one - a near-black version of these tokens was
       tried twice (see git history) and reverted both times as flat/
       uglier, once with a colored fill and once with the fill neutral and
       depth carried by shadow/border instead. Settled: the visible violet
       gradient stays. Don't retry near-black here again without a
       genuinely different approach, not just another shadow recipe. */
    --card-1: rgba(42, 28, 88, 0.95);
    --card-2: rgba(26, 17, 62, 0.96);
    --card-3: rgba(12, 8, 42, 0.97);
    --card-border: rgba(181, 139, 255, 0.22);
    --card-top-accent: rgba(181, 139, 255, 0.55);
    --card-shadow: 0 22px 54px rgba(0, 0, 0, 0.65);

    /* Subtle noise tile layered under body's background gradient - a tiny
       inline SVG (feTurbulence, alpha dropped to ~0.025 via feColorMatrix)
       so the canvas reads as textured "editorial smoke" rather than a flat
       vector gradient. Purely additive; safe to blank out (set to `none`)
       if it doesn't read well at real screen size/DPI. */
    --grain-texture: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.025 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");

    /* Type scale */
    --text-2xs: 10px;
    --text-xs: 11px;
    --text-sm: 12px;
    --text-base: 14px;
    --text-md: 16px;
    --text-lg: 20px;
    --text-xl: 24px;
    --text-2xl: 32px;

    /* Spacing scale (4pt system) */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-7: 32px;
    --space-8: 40px;
    --space-9: 48px;

    /* Radius tiers */
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --radius-pill: 999px;
    --radius-circle: 50%;

    /* Semantic color (meaning, not decoration) */
    --color-danger: #ff6b6b;
    --color-danger-strong: #e03131;
    --color-danger-soft: rgba(255, 107, 107, 0.16);
    --color-warning: #ffb84d;
    --color-warning-soft: rgba(255, 184, 77, 0.16);
    --color-success: #4dd699;
    --color-success-soft: rgba(77, 214, 153, 0.16);
    --color-info: #7f86ff;
    --color-info-soft: rgba(127, 134, 255, 0.16);
}

html{
    position: relative;
    background: linear-gradient(150deg, var(--violet-bg-1), var(--violet-bg-2), var(--violet-bg-3));
    /* Dark-only site: tell the browser once at the root so native chrome
       (scrollbars, date/time pickers, form-control defaults) renders dark
       everywhere, not just on the handful of inputs that set this
       individually. */
    color-scheme: dark;
}

/* Quieter, single-tone corner glow instead of the old mixed purple+blue
   double-stop orbs - this is most of what read as "AI-generated gradient
   template": less size, half the opacity, one color fading straight to
   transparent so most of the screen reads as flat black canvas with just
   a whisper of violet at the corners. */
html::before,
html::after{
    content: '';
    position: fixed;
    width: 52vmax;
    height: 52vmax;
    border-radius: 50%;
    filter: blur(80px);
    pointer-events: none;
    z-index: 0;
    opacity: 0.22;
    will-change: transform;
}

html::before{
    top: -26vmax;
    right: -18vmax;
    background: radial-gradient(circle at 36% 32%, rgba(150, 110, 240, 0.9), rgba(0, 0, 0, 0) 70%);
    animation: orbFloatC 26s ease-in-out infinite alternate;
}

html::after{
    left: -22vmax;
    bottom: -24vmax;
    background: radial-gradient(circle at 42% 42%, rgba(120, 120, 220, 0.8), rgba(0, 0, 0, 0) 70%);
    animation: orbFloatD 30s ease-in-out infinite alternate;
}

body{
    position: relative;
    overflow-x: hidden;
    color: var(--violet-text);
    background:
        var(--grain-texture),
        linear-gradient(150deg, var(--violet-bg-1), var(--violet-bg-2), var(--violet-bg-3));
    background-repeat: repeat, no-repeat;
}

body::before,
body::after{
    content: '';
    position: fixed;
    width: 58vmax;
    height: 58vmax;
    border-radius: 50%;
    filter: blur(76px);
    pointer-events: none;
    z-index: 0;
    will-change: transform;
    opacity: 0.24;
}

body::before{
    top: -24vmax;
    left: -20vmax;
    background: radial-gradient(circle at 30% 32%, rgba(160, 120, 240, 0.85), rgba(0, 0, 0, 0) 68%);
    animation: orbFloatA 24s ease-in-out infinite alternate;
}

body::after{
    right: -20vmax;
    bottom: -22vmax;
    background: radial-gradient(circle at 40% 44%, rgba(140, 120, 235, 0.8), rgba(0, 0, 0, 0) 68%);
    animation: orbFloatB 32s ease-in-out infinite alternate;
}

@keyframes orbFloatC {
    0% { transform: translate3d(0, 0, 0) scale(1); }
    50% { transform: translate3d(-16vmax, 8vmax, 0) scale(1.09); }
    100% { transform: translate3d(-6vmax, 22vmax, 0) scale(0.94); }
}

@keyframes orbFloatD {
    0% { transform: translate3d(0, 0, 0) scale(1); }
    50% { transform: translate3d(17vmax, -10vmax, 0) scale(1.12); }
    100% { transform: translate3d(8vmax, -22vmax, 0) scale(0.93); }
}

@keyframes orbFloatA {
    0% { transform: translate3d(0, 0, 0) scale(1); }
    25% { transform: translate3d(12vmax, 6vmax, 0) scale(1.06); }
    50% { transform: translate3d(20vmax, 18vmax, 0) scale(1.12); }
    75% { transform: translate3d(4vmax, 28vmax, 0) scale(0.98); }
    100% { transform: translate3d(-8vmax, 16vmax, 0) scale(0.92); }
}

@keyframes orbFloatB {
    0% { transform: translate3d(0, 0, 0) scale(1); }
    25% { transform: translate3d(-14vmax, -5vmax, 0) scale(1.07); }
    50% { transform: translate3d(-24vmax, -18vmax, 0) scale(1.11); }
    75% { transform: translate3d(-8vmax, -30vmax, 0) scale(1); }
    100% { transform: translate3d(6vmax, -16vmax, 0) scale(0.93); }
}

.container{
    position: relative;
    z-index: 1;
    background: linear-gradient(170deg, rgba(22, 14, 62, 0.9), rgba(12, 8, 44, 0.9));
    border-color: var(--violet-border);
    box-shadow: 0 28px 68px rgba(4, 3, 24, 0.56), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

.title,
.activityTitle,
.motivatorText,
.taskText,
.taskAmount,
.priorityToggleLabel span,
.detailsToggleBtn,
.sortOnceBtn,
.alertToggleBtn,
.taskViewBtn,
.typePill,
.durationChip,
.deadlinePresetBtn,
.addBtn i,
.calendarBtn i,
.taskButtons i{
    color: var(--violet-text);
}

/* .deleteBtn i is also matched by .taskButtons i just above (same
   specificity, so source order decides) - re-asserted here so the danger
   tint (section D) actually wins instead of being pulled back to the
   neutral violet-text color every other task-row icon uses. */
.deleteBtn i{
    color: var(--color-danger-strong, #e03131);
}

.activitySummary,
.quickAddHint,
.optionsHint,
.priorityModeHint,
.activityDayLabel,
.activityMonthLabel,
.urgencyAlertText{
    color: var(--violet-muted);
}

.motivatorContainer,
.activityPanel,
.taskDetailsPanel.open,
.urgencyAlert,
.priorityControls,
.tasks li{
    background: var(--violet-surface-soft);
    border-color: var(--violet-border-soft);
}

.taskInput,
.matrixSelect,
.difficultySelect,
.recurrenceSelect,
.durationInput,
.deadlineInput,
.editorTextInput,
.editorMatrixSelect,
.editorTaskTypeSelect,
.editorDifficultySelect,
.editorRecurrenceSelect,
.editorDurationInput,
.editorDeadlineInput,
.typePill,
.durationChip,
.detailsToggleBtn,
.sortOnceBtn,
.alertToggleBtn,
.deadlinePresetBtn{
    background: var(--violet-surface);
    border-color: var(--violet-border-soft);
    color: var(--violet-text);
}

.taskInput::placeholder,
.durationInput::placeholder,
.editorTextInput::placeholder,
.editorDurationInput::placeholder{
    color: rgba(215, 208, 255, 0.76);
}

.matrixSelect:hover,
.difficultySelect:hover,
.deadlineInput:hover,
.typePill:hover,
.durationChip:hover,
.detailsToggleBtn:hover,
.sortOnceBtn:hover:not(:disabled),
.alertToggleBtn:hover,
.taskViewBtn:hover,
.deadlinePresetBtn:hover{
    background: rgba(42, 30, 100, 0.96);
    border-color: rgba(205, 194, 255, 0.62);
    color: #ffffff;
}

.matrixSelect:focus,
.matrixSelect:focus-visible,
.difficultySelect:focus,
.difficultySelect:focus-visible,
.recurrenceSelect:focus,
.recurrenceSelect:focus-visible,
.deadlineInput:focus,
.deadlineInput:focus-visible,
.taskInput:focus,
.taskInput:focus-visible,
.editorTextInput:focus,
.editorMatrixSelect:focus,
.editorDeadlineInput:focus,
.editorTaskTypeSelect:focus,
.editorDifficultySelect:focus,
.editorRecurrenceSelect:focus,
.editorDurationInput:focus{
    background: rgba(45, 33, 106, 0.98);
    color: #ffffff;
    border-color: rgba(225, 217, 255, 0.72);
    box-shadow: 0 0 0 3px rgba(171, 145, 255, 0.3);
}

.typePill.active,
.durationChip.active,
.taskViewBtn.active,
.detailsToggleBtn[aria-expanded="true"],
.sortOnceBtn:active,
.alertToggleBtn.enabled{
    background: linear-gradient(120deg, #b58bff, #7f86ff);
    border-color: rgba(232, 225, 255, 0.8);
    color: #fdfcff;
}

.progressBarContainer{
    background: rgba(10, 7, 33, 0.95);
    border-color: rgba(180, 164, 255, 0.56);
}

.progressBar{
    background: linear-gradient(90deg, #7f86ff, #b58bff 60%, #d2a0ff 100%);
}

.addBtn,
.calendarBtn,
.editBtn,
.snoozeBtn,
.checkBtn i,
.taskAmountContainer,
.editorCalendarBtn{
    background: #1a123f;
    border-color: rgba(188, 173, 255, 0.68);
}

.editBtn:hover,
.snoozeBtn:hover,
.checkBtn i:hover,
.calendarBtn:hover,
.addBtn:hover,
.editorCalendarBtn:hover{
    background: #2b1f69;
    color: #ffffff;
}

.urgencyAlert.urgency-soon{
    background: #ffe6bf;
    border-color: #f1bf71;
}

.urgencyAlert.urgency-critical{
    background: #ffd6be;
    border-color: #efad81;
}

.urgencyAlert.urgency-overdue{
    background: linear-gradient(135deg, #ffd7d7 0%, #ffc9c9 52%, #ffbdbd 100%);
    border-color: #e98f8f;
}

.urgencyAlert.urgency-soon .urgencyAlertText{
    color: #6f470d;
}

.urgencyAlert.urgency-critical .urgencyAlertText{
    color: #7b370f;
}

.urgencyAlert.urgency-overdue .urgencyAlertText{
    color: #7c1d1d;
}

.tasks li.dragging{
    background: linear-gradient(165deg, rgba(66, 49, 145, 0.94), rgba(44, 31, 108, 0.95));
    border-color: rgba(204, 191, 255, 0.8);
    box-shadow: 0 14px 28px rgba(17, 10, 48, 0.55);
}

.tasks li.dragging .taskText,
.tasks li.dragging .taskMeta,
.tasks li.dragging .taskButtons i,
.tasks li.dragging .checkBtn i{
    color: #ffffff;
}

.tasks li.drag-over-slot{
    background: linear-gradient(165deg, rgba(74, 55, 162, 0.96), rgba(49, 35, 121, 0.96));
    border-color: rgba(216, 204, 255, 0.86);
    box-shadow: 0 0 0 4px rgba(181, 156, 255, 0.28), 0 12px 24px rgba(22, 12, 58, 0.52);
}

.matrixSelect option,
.difficultySelect option,
.editorMatrixSelect option{
    background: #191040;
    color: #f7f4ff;
}

@media (prefers-reduced-motion: reduce){
    html::before,
    html::after,
    body::before,
    body::after{
        animation: none;
    }
}

.taskInput,
.matrixSelect,
.difficultySelect,
.recurrenceSelect,
.durationInput,
.deadlineInput,
.editorTextInput,
.editorMatrixSelect,
.editorTaskTypeSelect,
.editorDifficultySelect,
.editorRecurrenceSelect,
.editorDurationInput,
.editorDeadlineInput,
.typePill,
.durationChip,
.detailsToggleBtn,
.sortOnceBtn,
.alertToggleBtn,
.deadlinePresetBtn{
    background:
        linear-gradient(145deg, rgba(49, 34, 117, 0.92), rgba(32, 22, 86, 0.94));
}


.addBtn,
.calendarBtn,
.editBtn,
.snoozeBtn,
.checkBtn i,
.taskAmountContainer,
.editorCalendarBtn{
    background:
        linear-gradient(145deg, rgba(63, 46, 140, 0.94), rgba(36, 25, 95, 0.96));
}

/* Task input row (section B): + is the fast-add path and gets the clear
   Von Restorff-effect standout - filled accent, not the same neutral dark
   circle every other icon button (calendarBtn, checkBtn, taskButtons) uses.
   Prioritize (.detailsToggleBtn) goes the opposite direction, ghost/outline,
   so the eye lands on + first, Prioritize second. Both overrides need to
   win over the shared-list rules above, hence sitting after them here. */
.addBtn{
    background: linear-gradient(135deg, var(--violet-accent, #b58bff), var(--violet-accent-2, #7f86ff));
    border-color: rgba(232, 225, 255, 0.75);
}

.addBtn i{
    color: #120b30;
}

.addBtn:hover{
    background: linear-gradient(135deg, #c2a3ff, #939aff);
    filter: brightness(1.04);
}

.addBtn:disabled{
    opacity: 0.42;
    cursor: not-allowed;
    filter: none;
    transform: none;
}

.detailsToggleBtn{
    background: transparent;
}

.typePill.active,
.durationChip.active,
.taskViewBtn.active,
.detailsToggleBtn[aria-expanded="true"],
.sortOnceBtn:active,
.alertToggleBtn.enabled{
    background:
        linear-gradient(120deg, rgba(193, 152, 255, 0.98), rgba(132, 140, 255, 0.98));
}

.matrixBadge,
.difficultyBadge,
.effortBadge,
.deadlineBadge,
.countdownBadge{
    background:
        linear-gradient(135deg, rgba(243, 236, 255, 0.98), rgba(222, 231, 255, 0.98));
}

.urgencyAlert.urgency-soon{
    background:
        linear-gradient(135deg, rgba(255, 229, 168, 0.96), rgba(255, 205, 133, 0.96));
}

.urgencyAlert.urgency-critical{
    background:
        linear-gradient(135deg, rgba(255, 205, 164, 0.96), rgba(255, 174, 128, 0.96));
}

.urgencyAlert.urgency-overdue{
    background:
        linear-gradient(135deg, rgba(255, 114, 114, 0.98), rgba(226, 72, 72, 0.98) 52%, rgba(126, 22, 50, 0.98));
    border-color: rgba(255, 164, 164, 0.92);
    box-shadow: 0 8px 22px rgba(120, 12, 28, 0.42), inset 0 1px 0 rgba(255, 214, 214, 0.28);
}

.urgencyAlert.urgency-overdue .urgencyAlertText{
    color: #fff1f1;
    text-shadow: 0 1px 0 rgba(92, 8, 22, 0.55);
}

.checkBtn i{
    color: rgba(198, 183, 255, 0.25);
    border-color: rgba(188, 173, 255, 0.68);
}

.tasks li.completed .checkBtn i{
    color: #f3edff;
    background: linear-gradient(140deg, rgba(180, 132, 255, 0.98), rgba(122, 128, 255, 0.98));
    border-color: rgba(229, 218, 255, 0.85);
    opacity: 1;
}

/* Correction to a claim made earlier in this same redesign pass: this was
   called "single source of truth" for .container's background, but it
   never actually was - a later, unconditional .container{background:
   transparent; border:none; box-shadow:none;} rule (search for "Structural
   layout split") has been winning the whole time, both before and after
   that edit. Removed rather than left as dead weight. .container renders
   no visible surface of its own at all; .tasks li/.motivatorContainer/
   .taskDetailsPanel/etc. are the actual visible cards, floating directly
   on the page's own background - not one big outer frame. */

/* Same near-black-plus-accent-border recipe as the shared --card-* tokens
   (.tasks li gets its own later, identical-in-spirit rule further down -
   this covers the other primary panels so every visible surface on the
   page reads as one consistent system, not several different violet
   intensities). */
.motivatorContainer,
.activityPanel,
.taskDetailsPanel.open,
.urgencyAlert{
    background:
        linear-gradient(160deg, var(--card-1) 0%, var(--card-2) 52%, var(--card-3) 100%);
    border-color: var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    box-shadow: var(--card-shadow);
}

/* .priorityControls deliberately stays out of the gradient group above -
   it's secondary chrome (auto-sort/alerts/visibility toggles), not primary
   content, so it gets the app's existing flat --violet-surface-soft token
   (see the base rule earlier in the file) instead of the same heavy
   gradient every card/panel uses. One quiet surface here gives the actual
   task list somewhere to visually stand out against. */

.taskInput,
.matrixSelect,
.difficultySelect,
.recurrenceSelect,
.durationInput,
.deadlineInput,
.typePill,
.durationChip,
.detailsToggleBtn,
.sortOnceBtn,
.alertToggleBtn,
.deadlinePresetBtn{
    background:
        linear-gradient(145deg, rgba(39, 27, 92, 0.9), rgba(27, 18, 72, 0.9));
}

/* Filter buttons (All/Focus Now/Overdue/...) stay flat and quiet at rest,
   deliberately excluded from every gradient pass above (there were three
   layered on this same selector group over time, all now consolidated to
   the two above) - .taskViewBtn.active still gets a clear, bold treatment
   further down so the current filter stays obvious; every other pill just
   needs to read as a plain, low-emphasis toggle so the task list itself is
   what stands out. */
.taskViewBtn{
    background: var(--violet-surface-soft);
}

/* Dark outlined pills, not solid pastel fills - consulting.com's small
   stat pills ("13.1% ↗") are a dark/transparent chip with a colored border
   and colored text, not a solid light fill; neutral badges use the violet
   brand tokens, urgency badges reuse the semantic --color-warning/-danger
   tokens already defined at :root (previously hardcoded their own hex
   instead of using them). */
.matrixBadge,
.difficultyBadge,
.effortBadge,
.deadlineBadge,
.countdownBadge,
.subtaskProgressBadge,
.scheduleBadge{
    background: rgba(181, 139, 255, 0.1);
    color: var(--violet-muted);
    border: 1px solid var(--violet-border);
}

.recurrenceBadge{
    background: rgba(181, 139, 255, 0.1);
    color: var(--violet-muted);
    border: 1px solid var(--violet-border);
}

.matrix-do,
.matrix-schedule,
.matrix-delegate,
.matrix-eliminate,
.difficulty-1,
.difficulty-2,
.difficulty-3,
.difficulty-4,
.difficulty-5,
.deadline-none,
.countdown-none,
.deadline-normal,
.countdown-normal{
    background: rgba(181, 139, 255, 0.1);
    color: var(--violet-muted);
    border: 1px solid var(--violet-border);
}

.deadline-soon,
.countdown-soon{
    background: var(--color-warning-soft);
    color: var(--color-warning);
    border-color: rgba(255, 184, 77, 0.45);
}

.deadline-critical,
.countdown-critical{
    background: rgba(255, 140, 66, 0.16);
    color: #ff9a52;
    border-color: rgba(255, 140, 66, 0.48);
}

.deadline-overdue,
.countdown-overdue{
    background: var(--color-danger-soft);
    color: var(--color-danger);
    border-color: rgba(255, 107, 107, 0.48);
}

/* Final control icon clarity */
.matrixSelect,
.difficultySelect,
.recurrenceSelect,
.editorRecurrenceSelect{
    appearance: auto;
    -webkit-appearance: menulist;
    -moz-appearance: auto;
    padding-right: 12px;
}

.deadlineInput{
    color-scheme: dark;
}

.deadlineInput::-webkit-calendar-picker-indicator{
    filter: invert(90%) sepia(22%) saturate(315%) hue-rotate(205deg) brightness(108%) contrast(102%) !important;
    opacity: 0.92;
    cursor: pointer;
}

.deadlineInput::-webkit-calendar-picker-indicator:hover{
    opacity: 1;
}

/* Final compact UX refinements */
.durationWrap{
    gap: 10px;
}

.durationInput{
    width: 132px;
    min-width: 132px;
}

.durationChips{
    gap: 8px;
}

.durationChip{
    min-width: 48px;
    text-align: center;
}

.priorityToggleLabel{
    gap: 10px;
}

.priorityToggle{
    appearance: none;
    -webkit-appearance: none;
    width: 44px;
    height: 24px;
    border-radius: 999px;
    border: 1px solid rgba(184, 167, 255, 0.62);
    background: linear-gradient(135deg, rgba(50, 35, 115, 0.92), rgba(33, 23, 82, 0.94));
    cursor: pointer;
    position: relative;
    display: inline-grid;
    align-items: center;
    padding: 2px;
    transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.priorityToggle::before{
    content: '';
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: linear-gradient(140deg, #f5f0ff, #e1d3ff);
    box-shadow: 0 2px 6px rgba(11, 7, 34, 0.45);
    transform: translateX(0);
    transition: transform 0.2s ease;
}

.priorityToggle:checked{
    background: linear-gradient(120deg, rgba(182, 141, 255, 0.95), rgba(126, 138, 255, 0.95));
    border-color: rgba(232, 225, 255, 0.82);
    box-shadow: 0 0 0 3px rgba(173, 145, 255, 0.26);
}

.priorityToggle:checked::before{
    transform: translateX(20px);
    background: linear-gradient(140deg, #ffffff, #f1e8ff);
}

.priorityToggle:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(173, 145, 255, 0.3);
}

/* Overdue notification badge */
.taskViewBtn[data-view="overdue"]{
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.overdueCountBadge{
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 999px;
    display: none;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    line-height: 1;
    font-weight: 800;
    color: #fff4ed;
    background: linear-gradient(135deg, #ff864d, #ff4b31 58%, #b9152b);
    border: 1px solid rgba(255, 199, 173, 0.9);
    box-shadow: 0 3px 10px rgba(167, 35, 23, 0.42), inset 0 1px 0 rgba(255, 230, 210, 0.4);
}

.overdueCountBadge.visible{
    display: inline-flex;
    animation: overdueBadgePulse 1.9s ease-in-out infinite;
}

.taskViewBtn.active .overdueCountBadge{
    background: linear-gradient(135deg, #ff9967, #ff5a3b 60%, #c31c35);
    border-color: rgba(255, 224, 206, 0.95);
}

@keyframes overdueBadgePulse{
    0%, 100%{
        transform: scale(1);
        box-shadow: 0 3px 10px rgba(167, 35, 23, 0.42), inset 0 1px 0 rgba(255, 230, 210, 0.4);
    }
    50%{
        transform: scale(1.08);
        box-shadow: 0 5px 14px rgba(188, 36, 20, 0.5), inset 0 1px 0 rgba(255, 240, 228, 0.48);
    }
}

/* Final editor modal theming (prevents legacy light overrides) */
.taskEditorOverlay{
    background: rgba(6, 4, 24, 0.68);
    backdrop-filter: blur(4px);
}

.taskEditorCard{
    background:
        linear-gradient(160deg, var(--card-1) 0%, var(--card-2) 52%, var(--card-3) 100%);
    border: 1px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    box-shadow: var(--card-shadow);
}

.taskEditorCard h2,
.taskEditorCard label{
    color: #f4efff;
}

.taskEditorCard .editorTextInput,
.taskEditorCard .editorMatrixSelect,
.taskEditorCard .editorTaskTypeSelect,
.taskEditorCard .editorDifficultySelect,
.taskEditorCard .editorRecurrenceSelect,
.taskEditorCard .editorDurationInput,
.taskEditorCard .editorDeadlineInput{
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    border-color: rgba(185, 167, 255, 0.48);
    color: #f7f3ff;
}

.taskEditorCard .editorTextInput::placeholder,
.taskEditorCard .editorDurationInput::placeholder{
    color: rgba(217, 206, 255, 0.72);
}

.taskEditorCard .editorTextInput:hover,
.taskEditorCard .editorMatrixSelect:hover,
.taskEditorCard .editorTaskTypeSelect:hover,
.taskEditorCard .editorDifficultySelect:hover,
.taskEditorCard .editorDurationInput:hover,
.taskEditorCard .editorDeadlineInput:hover,
.taskEditorCard .editorTextInput:focus,
.taskEditorCard .editorMatrixSelect:focus,
.taskEditorCard .editorTaskTypeSelect:focus,
.taskEditorCard .editorDifficultySelect:focus,
.taskEditorCard .editorDurationInput:focus,
.taskEditorCard .editorDeadlineInput:focus,
.taskEditorCard .editorTextInput:focus-visible,
.taskEditorCard .editorMatrixSelect:focus-visible,
.taskEditorCard .editorTaskTypeSelect:focus-visible,
.taskEditorCard .editorDifficultySelect:focus-visible,
.taskEditorCard .editorDurationInput:focus-visible,
.taskEditorCard .editorDeadlineInput:focus-visible{
    background: linear-gradient(145deg, rgba(61, 45, 133, 0.98), rgba(41, 29, 108, 0.99));
    border-color: rgba(223, 213, 255, 0.74);
    color: #ffffff;
    box-shadow: 0 0 0 3px rgba(170, 143, 255, 0.3);
}

.taskEditorCard .editorDeadlineWrap:hover{
    background: rgba(58, 42, 132, 0.56);
    box-shadow: 0 0 0 3px rgba(171, 145, 255, 0.2);
}

.taskEditorCard .editorCancelBtn,
.taskEditorCard .editorSaveBtn{
    border-radius: var(--radius-sm);
    border: 2px solid rgba(194, 178, 255, 0.58);
    transition: transform 0.16s ease, background 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}

.taskEditorCard .editorCancelBtn{
    background: linear-gradient(145deg, rgba(40, 51, 75, 0.95), rgba(27, 36, 58, 0.96));
    color: #e6ecff;
}

.taskEditorCard .editorSaveBtn{
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    border-color: rgba(231, 222, 255, 0.9);
    color: #120b30;
}

.taskEditorCard .editorCancelBtn:hover,
.taskEditorCard .editorSaveBtn:hover{
    transform: translateY(-1px);
}

.taskEditorCard .editorCancelBtn:hover{
    background: linear-gradient(145deg, rgba(53, 66, 95, 0.98), rgba(36, 46, 73, 0.99));
    color: #ffffff;
    border-color: rgba(214, 201, 255, 0.78);
}

.taskEditorCard .editorSaveBtn:hover{
    background: linear-gradient(120deg, rgba(212, 181, 255, 0.99), rgba(154, 161, 255, 0.99));
    color: #10082b;
    border-color: rgba(246, 240, 255, 0.96);
    box-shadow: 0 6px 18px rgba(93, 67, 176, 0.38);
}

.taskEditorCard .editorCancelBtn:active,
.taskEditorCard .editorSaveBtn:active{
    transform: translateY(0);
}

.taskEditorCard .editorCancelBtn:focus-visible,
.taskEditorCard .editorSaveBtn:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.32);
}

/* Final dropdown popup theming */
.matrixSelect,
.difficultySelect,
.recurrenceSelect,
.editorMatrixSelect,
.editorTaskTypeSelect,
.editorDifficultySelect,
.editorRecurrenceSelect,
.groupCreatePrivacySelect,
.groupSettingsPrivacySelect,
.brainDumpTaskCardMatrix,
.brainDumpTaskCardDifficulty,
.brainDumpTaskCardDeadline{
    color-scheme: dark;
    /* Real contrast bug: .matrixSelect/.difficultySelect/.recurrenceSelect
       and the editor/brain-dump-card variants never got their text color
       repainted when the app moved to this dark violet theme, so they were
       still showing #1e1e1e (near-black) on a dark violet background -
       effectively unreadable. .groupCreatePrivacySelect/
       .groupSettingsPrivacySelect/.brainDumpTaskCardDeadline were built
       after the dark theme and already set their own correct light color
       further down the file, which still wins over this (later + equal
       specificity); this line only changes the selects that were missed. */
    color: var(--violet-text, #f6f4ff);
}

.matrixSelect option,
.difficultySelect option,
.recurrenceSelect option,
.editorMatrixSelect option,
.editorTaskTypeSelect option,
.editorDifficultySelect option,
.editorRecurrenceSelect option,
.groupCreatePrivacySelect option,
.groupSettingsPrivacySelect option,
.brainDumpTaskCardMatrix option,
.brainDumpTaskCardDifficulty option{
    background: #1a1143;
    color: #f7f3ff;
    font-weight: 600;
}

/* Clarity + guidance UI */
.onboardingHint{
    width: 92%;
    margin-top: 10px;
    padding: 10px 12px;
    border-radius: 12px;
    border: 1px solid rgba(188, 170, 255, 0.5);
    background: linear-gradient(135deg, rgba(66, 50, 143, 0.84), rgba(43, 31, 105, 0.88));
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.onboardingHint.hidden{
    display: none;
}

.onboardingHintText{
    font-size: 12px;
    line-height: 1.4;
    color: #f6f0ff;
}

.onboardingDismissBtn{
    border: 1px solid rgba(221, 208, 255, 0.75);
    border-radius: 999px;
    height: 30px;
    padding: 0 11px;
    background: rgba(233, 222, 255, 0.2);
    color: #f8f3ff;
    font-weight: 700;
    cursor: pointer;
}

.onboardingDismissBtn:hover{
    background: rgba(245, 238, 255, 0.28);
}

.detailsHelp{
    margin-bottom: 8px;
    font-size: 12px;
    color: rgba(232, 224, 255, 0.9);
    font-weight: 600;
}

.nextTaskPanel{
    width: 92%;
    margin-top: 10px;
    border-radius: 12px;
    border: 1px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    background: linear-gradient(155deg, var(--card-1), var(--card-2));
    padding: 10px 12px;
}

.nextTaskPanel.hidden{
    display: none;
}

.nextTaskLabel{
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.3px;
    color: rgba(220, 209, 255, 0.92);
    text-transform: uppercase;
}

.nextTaskTitle{
    margin-top: 4px;
    font-size: 15px;
    font-weight: 700;
    color: #ffffff;
}

.nextTaskReasonWrap{
    margin-top: 8px;
}

.nextTaskReasonLabel{
    font-size: 12px;
    color: rgba(231, 221, 255, 0.92);
    margin-bottom: 4px;
}

.nextTaskReasons{
    margin-left: 16px;
    color: rgba(245, 240, 255, 0.95);
    font-size: 12px;
    line-height: 1.4;
    display: grid;
    gap: 3px;
}

.nextTaskActions{
    margin-top: 9px;
    display: flex;
    gap: 8px;
}

.rankNowBtn,
.focusNextBtn{
    border: 1px solid rgba(192, 174, 255, 0.62);
    background: linear-gradient(145deg, rgba(46, 33, 109, 0.95), rgba(31, 22, 82, 0.95));
    color: #f4efff;
    border-radius: 999px;
    height: 32px;
    padding: 0 12px;
    font-size: 12px;
    font-weight: 700;
}

.rankNowBtn,
.focusNextBtn{
    cursor: pointer;
}

.rankNowBtn:hover,
.focusNextBtn:hover{
    border-color: rgba(223, 212, 255, 0.84);
    background: linear-gradient(145deg, rgba(61, 45, 132, 0.96), rgba(42, 30, 108, 0.96));
}

/* Usability fixes for new controls */
.rankNowBtn,
.focusNextBtn,
.onboardingDismissBtn{
    white-space: nowrap;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.rankNowBtn{
    min-width: 92px;
}

.onboardingDismissBtn{
    min-width: 72px;
}

.priorityHeaderRow{
    flex-wrap: wrap;
    align-items: center;
    row-gap: 8px;
}

.priorityToggleLabel{
    flex: 1 1 190px;
    min-width: 180px;
}

.sortOnceBtn,
.alertToggleBtn{
    flex: 0 0 auto;
}

/* Use desktop space better: split into main + side rail */
@media (min-width: 1060px){
    .container{
        width: min(1160px, 96vw);
    }

    .title,
    .motivatorContainer,
    .inputContainer,
    .taskDetailsPanel,
    .onboardingHint,
    .urgencyAlert,
    .taskViews,
    .tasks{
        grid-column: 1;
        width: 100%;
    }

    .activityPanel,
    .nextTaskPanel,
    .priorityControls{
        grid-column: 2;
        width: 100%;
    }

    .activityPanel{
        margin-top: 4px;
    }

    .tasks{
        margin-top: 2px;
    }

    .priorityControls{
        position: static;
        margin-top: 10px;
    }
}

@media (max-width: 700px){
    .onboardingHint{
        flex-direction: column;
        align-items: flex-start;
    }

    .priorityHeaderRow{
        flex-wrap: wrap;
    }

    .nextTaskActions{
        flex-wrap: wrap;
    }
}

/* Structural layout split: not one centered block */
.container{
    width: min(1280px, 97vw);
    min-height: auto;
    height: auto;
    background: transparent;
    border: none;
    box-shadow: none;
    backdrop-filter: none;
}

.appShell{
    width: 100%;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 430px;
    gap: 18px;
    align-items: stretch;
}

.mainColumn,
.sideColumn{
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.mainColumn{
    margin-top: 10px;
}

.sideColumn{
    margin-top: 100px;
}

.mainColumn .title,
.mainColumn .motivatorContainer,
.mainColumn .inputContainer,
.mainColumn .onboardingHint,
.mainColumn .taskDetailsPanel,
.mainColumn .urgencyAlert,
.mainColumn .nextTaskPanel,
.mainColumn .taskViews,
.mainColumn .tasks,
.sideColumn .priorityControls{
    width: 100%;
    margin-top: 0;
}

.sideColumn .activityPanel{
    width: 100%;
    margin-top: 0;
    min-height: 0;
}

.mainColumn .tasks{
    transform: none;
}

.mainColumn .title{
    margin-bottom: 4px;
    text-align: center;
}

.sideColumn .priorityControls{
    position: static;
}

@media (max-width: 1060px){
    .appShell{
        grid-template-columns: 1fr;
    }

    .mainColumn{
        margin-top: 0;
    }

    .sideColumn{
        margin-top: 0;
    }

    .sideColumn .priorityControls{
        position: static;
    }

    .sideColumn .activityPanel{
        margin-top: 0;
        min-height: 0;
    }
}

/* Navigation: view tabs (section A of the UI/UX rework). Reuses .taskViewBtn's
   pill visual language (--radius-pill, same border/active-gradient pattern)
   since it's the same "pick one of a few views" interaction, just one level
   up - Jakob's Law: don't invent a second tab pattern the eye has to learn. */
.viewTabs{
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    /* Base: fills whatever normal-flow width its actual parent provides -
       correct for group's .viewTabs, which sits nested inside
       .groupDashboard/.container. Solo's is a direct child of body instead
       (a sibling of .container, not a descendant of it), so it needs the
       separate body > .viewTabs override below to match .container's own
       width rather than overflow/undersize against the viewport. */
    width: 100%;
    margin: 14px 0 4px;
    z-index: 1;
    position: relative;
}

/* Solo only (see the comment above) - matches .container's own final width
   (min(1280px, 97vw), set later in this file) so the tab bar's edges line
   up with the panel below it instead of sizing against the full viewport. */
body > .viewTabs{
    width: min(1280px, 97vw);
}

.viewTab{
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    border: 2px solid var(--violet-border-soft, rgba(170, 152, 255, 0.28));
    background: linear-gradient(145deg, rgba(39, 27, 92, 0.9), rgba(27, 18, 72, 0.9));
    color: var(--violet-text, #f6f4ff);
    border-radius: var(--radius-pill);
    padding: var(--space-2) var(--space-5);
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
    transition: all 0.2s ease;
}

.viewTab:hover{
    border-color: rgba(205, 194, 255, 0.62);
    background: rgba(42, 30, 100, 0.96);
    color: #ffffff;
}

.viewTab.active{
    border-color: rgba(232, 225, 255, 0.8);
    background: linear-gradient(120deg, rgba(193, 152, 255, 0.98), rgba(132, 140, 255, 0.98));
    color: #fdfcff;
}

/* Avatar chips for group's member-scope tabs (section E): reuses .taskViewBtn
   for the pill shape/color, adding icon+text layout and a small circular
   initial avatar so this row reads as a person-picker, a genuinely
   different control type from the plain-text deadline-filter row right
   below it (Law of Similarity). */
.groupScopeTabBtn{
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding-left: 5px;
}

.scopeTabAvatar{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: var(--radius-circle);
    background: rgba(255, 255, 255, 0.35);
    font-size: 9px;
    font-weight: 800;
    flex-shrink: 0;
}

.groupScopeTabBtn.active .scopeTabAvatar{
    background: rgba(255, 255, 255, 0.55);
}

.scopeTabAvatar i{
    font-size: 9px;
}

.viewPanel{
    width: 100%;
}

.viewPanel[data-view-panel="activity"] .activityPanel{
    width: 100%;
    /* Was 0, left over from when Activity shared a two-column layout with
       a side column and needed to align flush with something else there -
       now that it's its own full-width tab, that 0 was exactly why it sat
       crammed right up against the Tasks/Calendar/Activity tabs above it,
       reported live. var(--space-4) matches the breathing room Calendar's
       own panel already gets for the same reason (see .calendarPanel). */
    margin-top: var(--space-4);
    min-height: 0;
}

/* Group's Team view (member roster, leaderboard, "Recently finished" trigger)
   - previously .sideColumn's own content, now its own full-width view/tab
   instead of sharing a column with the task list. Replicates .sideColumn's
   own flex/gap (style.css ~2841) minus its 100px margin-top, which existed
   only to vertically line the column up next to mainColumn's header - not
   meaningful now that this is a standalone view. */
.viewPanel[data-view-panel="team"]{
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    /* Same breathing-room fix as solo's Activity/Calendar tabs (see
       .viewPanel[data-view-panel="activity"] .activityPanel) - Team has no
       heading of its own above its content either, so without this it sat
       flush against the Tasks/Team/Leaderboard/Activity tabs above it. */
    margin-top: var(--space-4);
}

/* .viewPanel.hidden MUST be declared after every .viewPanel[data-view-panel=
   "..."] display override above (not just alongside the base .viewPanel
   rule) - [data-view-panel="team"]'s own display:flex has the exact same
   specificity as .viewPanel.hidden's display:none (one class-equivalent
   selector each), so whichever is later in the file wins regardless of
   which element actually has the hidden class at runtime. Declaring this
   first (its original position) meant the Team panel's own display:flex
   permanently outranked .hidden by source order alone - it rendered
   visible on every view, Tasks included, no matter what switchGroupView
   actually toggled. Real bug, reported live: the roster/leaderboard/
   history content was showing on both tabs simultaneously. */
.viewPanel.hidden{
    display: none;
}

/* Prioritize panel layout: avoid flat full-width stack */
.mainColumn .taskDetailsPanel.open{
    padding: 10px;
    border-radius: 12px;
    border: 1px solid rgba(169, 152, 245, 0.38);
    background: linear-gradient(160deg, rgba(41, 28, 104, 0.5), rgba(26, 18, 79, 0.54));
}

.mainColumn .taskDetailsPanel .detailsGrid{
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    gap: 10px 12px;
    align-items: start;
}

/* Two-tier disclosure (section C, Hick's Law): Matrix and Difficulty are the
   only two fields that actually drive auto-sort order, so they're the ones
   visible the instant the panel opens - .detailsFieldGroup wraps each
   select with its own plain-language subtitle. Everything else (estimate,
   deadline, schedule) sits behind .detailsMoreToggleBtn below. .matrixSelect/
   .difficultySelect are no longer direct grid items themselves (their
   wrapping .detailsFieldGroup is), so they no longer need explicit
   grid-column - .detailsGridPrimary's 2-column template auto-places its two
   .detailsFieldGroup children into column 1 and 2 on its own. */
.detailsFieldGroup{
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.detailsFieldSubtitle{
    margin: 0;
    font-size: var(--text-2xs);
    color: var(--violet-muted, #d7d0ff);
    opacity: 0.85;
}

/* Deadline as a third primary field (see index.html/group/index.html) -
   its own row below Matrix/Difficulty since its field (icon + label +
   input) is wider than a plain select, not crammed into the same 2-column
   row as them. */
.detailsDeadlinePrimary{
    margin-top: var(--space-3);
}

.detailsRecurrencePrimary{
    margin-top: var(--space-3);
}

.detailsRecurrencePrimary .recurrenceSelect,
.detailsRecurrencePrimary .editorRecurrenceSelect{
    width: 100%;
}

/* Steps at creation time (.detailsStepsGroup) - both solo (app.html/
   script.js) and group (group/index.html/group.js) now build this with the
   shared createSubtaskRowsEditor (task-shared.js, .pendingStepsEditorMount
   hosts its .stepDraftRowsWrap element, which supplies its own layout) and
   it sits always-visible right under .inputContainer on both pages, not
   inside .detailsMoreOptions anymore - margin-top here still reads fine as
   the first thing after the input row. The older plain-text
   .pendingStepsList/.pendingStepItem markup (reusing .subtaskItem/
   .subtaskAddRow/.subtaskInput/.subtaskAddBtn from the per-task steps UI)
   group used to have is gone from both markup and here - nothing left
   referencing it. */
.detailsStepsGroup{
    margin-top: var(--space-3);
}

/* Real bug found and fixed while adding the above: .editorPrimaryGrid
   (task editor overlay, initializeTaskEditor/initializeGroupTaskEditor)
   never actually carried the base .detailsGrid class the way the inline
   Prioritize panel's own .detailsGridPrimary does, and the inline panel's
   2-column grid rule is scoped to .mainColumn .taskDetailsPanel anyway -
   a completely different DOM context from .taskEditorCard, a dynamically
   created overlay. Matrix and Difficulty have been rendering stacked full-
   width, one above the other, instead of side by side, since step 5 of
   this rework first built the editor's two-tier disclosure. */
.taskEditorCard .editorPrimaryGrid{
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-3);
}

@media (max-width: 500px){
    .taskEditorCard .editorPrimaryGrid{
        grid-template-columns: 1fr;
    }
}

.detailsMoreToggleBtn{
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    margin-top: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--violet-border-soft, rgba(170, 152, 255, 0.28));
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.04);
    color: var(--violet-muted, #d7d0ff);
    font-size: var(--text-xs);
    font-weight: 700;
    cursor: pointer;
}

.detailsMoreToggleBtn:hover{
    background: rgba(255, 255, 255, 0.08);
    color: var(--violet-text, #f6f4ff);
}

.detailsMoreToggleBtn i{
    transition: transform 0.2s ease;
}

.detailsMoreToggleBtn[aria-expanded="true"] i{
    transform: rotate(180deg);
}

.detailsMoreOptions{
    display: none;
    margin-top: var(--space-3);
}

.detailsMoreOptions.open{
    display: block;
}

.mainColumn .taskDetailsPanel .effortContainer,
.mainColumn .taskDetailsPanel .deadlineContainer{
    border: 1px solid rgba(173, 156, 246, 0.32);
    border-radius: 12px;
    background: rgba(30, 20, 84, 0.44);
    padding: 10px;
}

.mainColumn .taskDetailsPanel .effortContainer{
    grid-column: 1;
    gap: 10px;
}

.mainColumn .taskDetailsPanel .deadlineContainer{
    grid-column: 2;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 8px;
}

.mainColumn .taskDetailsPanel .deadlineTag{
    height: 36px;
}

.mainColumn .taskDetailsPanel .deadlineInput{
    height: 46px;
}

.mainColumn .taskDetailsPanel .durationWrap{
    align-items: flex-start;
    flex-direction: column;
}

@media (max-width: 1060px){
    .mainColumn .taskDetailsPanel .detailsGrid{
        grid-template-columns: 1fr;
    }

    .mainColumn .taskDetailsPanel .detailsFieldGroup,
    .mainColumn .taskDetailsPanel .effortContainer,
    .mainColumn .taskDetailsPanel .deadlineContainer{
        grid-column: 1;
    }
}

/* Activity panel refinements */
.activityPanel{
    padding: 10px 12px 10px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.activityHeader{
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
}

.activitySummary{
    width: 100%;
    min-width: 0;
    font-size: 11px;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.activityLegend{
    margin-top: 2px;
}

@media (max-width: 740px){
    .activitySummary{
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
    }
}

/* Streak pill: a small badge overlapping the corner of the existing
   .taskAmountContainer circle (which is already position: relative) rather
   than a new flex child in .motivatorContainer - that row's spacing is
   hand-tuned with relative/absolute offsets on each of its three children
   (see .motivatorText/.progressBarContainer above), so a badge attached to
   an existing element is far less likely to knock that math out than a
   fourth sibling squeezed into the same flex row. Hidden entirely below a
   2-day streak - see refreshSoloStreakPill in script.js. */
.streakPill{
    position: absolute;
    top: -6px;
    right: -8px;
    display: flex;
    align-items: center;
    gap: 2px;
    background: linear-gradient(135deg, #ff9a4d, #ff5b3d);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    padding: 3px 7px;
    border-radius: 999px;
    border: 2px solid rgba(255, 255, 255, 0.92);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.28);
    white-space: nowrap;
    cursor: default;
}
.streakPill.hidden{ display: none; }

/* Achievements: a compact earned/locked badge row appended below the
   heatmap/legend in the existing Activity tab - see the plan's no-clutter
   notes on why this isn't a new nav tab. Purple family to match the rest
   of this app's current accent (see settings.js's #b58bff), not the
   heatmap's blue-scale colors above. */
.achievementsHeading{
    margin: 4px 0 0;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #6a4fa8;
}

.achievementsRow{
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.achievementChip{
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    border: 1.5px solid rgba(170, 145, 235, 0.4);
    background: rgba(255, 255, 255, 0.5);
    color: #6a4fa8;
    font-size: 15px;
    cursor: pointer;
    padding: 0;
}

.achievementChip.isEarned{
    background: linear-gradient(135deg, rgba(201, 165, 255, 0.95), rgba(141, 148, 255, 0.95));
    border-color: rgba(225, 205, 255, 0.96);
    color: #fff;
}

.achievementChip.isLocked{
    opacity: 0.45;
}

.achievementsTooltip{
    position: fixed;
    transform: translate(-50%, -100%) translateY(-8px);
    background: rgba(20, 10, 46, 0.94);
    color: #f6f4ff;
    font-size: 12px;
    padding: 6px 10px;
    border-radius: 8px;
    border: 1px solid rgba(170, 152, 255, 0.4);
    max-width: 240px;
    text-align: center;
    z-index: 960;
    pointer-events: none;
}
.achievementsTooltip.hidden{ display: none; }

/* Themed tooltip replaces native black tooltip */
.activityTooltip{
    position: fixed;
    left: 0;
    top: 0;
    z-index: 1200;
    pointer-events: none;
    border: 1px solid rgba(220, 207, 255, 0.72);
    border-radius: 9px;
    padding: 7px 9px;
    font-size: 12px;
    font-weight: 700;
    color: #f6efff;
    background: linear-gradient(145deg, rgba(67, 50, 143, 0.98), rgba(40, 28, 103, 0.99));
    box-shadow: 0 8px 22px rgba(17, 9, 49, 0.5);
}

.activityTooltip.hidden{
    display: none;
}

/* ---------------------------------------------------------------------
   Calendar view - the same tasks already on the list, laid out by day.
   .calendarChip deliberately carries no color of its own; it composes
   with the existing .deadline-normal/-soon/-critical/-overdue/-none
   classes (already used on every task row's own badge) so a calendar
   chip's color means exactly the same thing everywhere else in the app
   already does - one urgency language, not a second invented one.
   --------------------------------------------------------------------- */

.calendarPanel{
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    /* Breathing room under the Tasks/Calendar/Activity tab row above -
       Tasks gets this implicitly from its own leading title element;
       Calendar and Activity both needed it added explicitly (see
       .viewPanel[data-view-panel="activity"] .activityPanel for the
       Activity side of this same fix), since neither has a heading of its
       own sitting above its content the way Tasks does. */
    margin-top: var(--space-4);
}

.calendarHeader{
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3);
}

.calendarNav{
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.calendarLabel{
    min-width: 148px;
    text-align: center;
    font-size: var(--text-md);
    font-weight: 800;
    color: var(--violet-text);
}

.calendarPrevBtn,
.calendarNextBtn{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-circle);
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface-soft);
    color: var(--violet-text);
    cursor: pointer;
}

.calendarPrevBtn:hover,
.calendarNextBtn:hover{
    background: rgba(255, 255, 255, 0.1);
}

.calendarControls{
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.calendarTodayBtn{
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface-soft);
    color: var(--violet-text);
    border-radius: var(--radius-sm);
    padding: 6px 10px;
    font-size: var(--text-xs);
    font-weight: 700;
    cursor: pointer;
}

.calendarTodayBtn:hover{
    background: rgba(255, 255, 255, 0.1);
}

/* Same pill-toggle shape as .viewTab/.taskViewBtn - a calendar-specific
   control, but it should read as the same kind of control, not a new one. */
.calendarModeToggle{
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    border-radius: var(--radius-pill);
    background: var(--violet-surface-soft);
    border: 1px solid var(--violet-border-soft);
}

.calendarModeBtn{
    border: none;
    background: transparent;
    color: var(--violet-muted);
    border-radius: var(--radius-pill);
    padding: 5px 12px;
    font-size: var(--text-xs);
    font-weight: 700;
    cursor: pointer;
}

.calendarModeBtn.active{
    background: linear-gradient(120deg, var(--violet-accent), var(--violet-accent-2));
    color: #150a34;
}

.calendarWeekdayRow{
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--space-2);
    padding: 0 2px;
    font-size: var(--text-2xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--violet-muted);
    text-align: center;
}

.calendarGrid{
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    grid-auto-rows: minmax(88px, auto);
    gap: var(--space-2);
    /* A cell that expands (see .calendarDayCell.expanded) should only grow
       itself, not stretch every other cell sharing its grid row along with
       it - the default stretch would make an unrelated empty day look
       tall too, just because a neighbor in the same row expanded. */
    align-items: start;
}

.calendarGrid.calendarGridWeek{
    /* Was 220px - with only a chip or two (the common case), that read as
       a huge empty box with one line of text floating near the top, not
       "more room for detail." A little taller than month's 88px is still
       useful (Week is meant to show more before overflowing to "+N more"),
       but the row should grow to fit real content (the "auto" side of this
       minmax already does that), not reserve height nothing is using. */
    grid-auto-rows: minmax(104px, auto);
}

/* Week's cap is CALENDAR_MAX_VISIBLE_CHIPS_WEEK (6, script.js), so its
   uniform floor needs to be taller than month's - same reasoning as
   .calendarDayCell's min-height above, just sized for up to 6 chips
   instead of 3. */
.calendarGrid.calendarGridWeek .calendarDayCell{
    min-height: 190px;
}

/* A white-based overlay tint (not a flat violet rgba) so every cell lifts
   off the page by the same relative amount no matter where it sits on the
   page's own background gradient - a fixed violet fill happened to blend
   into the gradient in some corners and not others, which is what made the
   grid read as "can't tell the cells apart." Border bumped from -soft to a
   clearly visible full-strength violet line so the grid itself is legible,
   not just implied by gaps. */
/* min-height raised to comfortably fit the capped default case (3 chips,
   see CALENDAR_MAX_VISIBLE_CHIPS in script.js) - at 88px a 0-chip day sat
   at the floor while a 3-chip day grew past it, so every row looked
   uneven ("ruined the rhythm"). Every un-expanded cell now clamps to the
   same floor regardless of chip count (0-3 all fit under it); only a
   cell a visitor actually expands (.expanded, see script.js's "+N more")
   grows past this floor on its own, without dragging its row-mates
   (align-items:start on .calendarGrid, above). */
.calendarDayCell{
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px;
    border-radius: var(--radius-md);
    border: 1px solid var(--violet-border);
    background: rgba(255, 255, 255, 0.045);
    min-height: 116px;
}

.calendarDayCell.outOfMonth{
    opacity: 0.4;
}

.calendarDayCell.today{
    border-color: var(--violet-accent);
    background: rgba(181, 139, 255, 0.22);
}

.calendarDayCell.empty{
    cursor: pointer;
}

.calendarDayCell.empty:hover{
    border-color: var(--violet-accent);
    background: rgba(255, 255, 255, 0.08);
}

.calendarDayNumber{
    font-size: var(--text-sm);
    font-weight: 800;
    color: var(--violet-text);
}

.calendarDayCell.today .calendarDayNumber{
    color: var(--violet-accent);
}

/* Desktop grid gets just the bare day number (the weekday header row above
   already gives column context); the mobile single-column agenda (below)
   needs the full date on every row instead, since there's no header row to
   supply it once everything's stacked vertically. */
.calendarDayFullLabel{
    display: none;
}

.calendarChipList{
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.calendarChip{
    display: flex;
    align-items: center;
    gap: 5px;
    width: 100%;
    padding: 3px 6px;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    font-size: var(--text-2xs);
    font-weight: 700;
    text-align: left;
    cursor: pointer;
    overflow: hidden;
}

.calendarChip span{
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.calendarChip i{
    flex: 0 0 auto;
    font-size: 9px;
}

/* A projected (not-yet-real) future occurrence of a recurring task - reads
   as "this repeats here" rather than a second real task, since clicking it
   opens the one real one either way. */
.calendarChip-projected{
    border-style: dashed;
    opacity: 0.8;
}

.calendarChip.completed span{
    text-decoration: line-through;
}

/* A step's own deadline - visually reads as "part of a bigger task", not a
   second real task in its own right (dotted, not the projected chip's
   dashed, and italic label) - clicking it still opens the real parent task,
   same as every other chip type. */
.calendarChip-step{
    border-style: dotted;
}

.calendarChip-step span{
    font-style: italic;
    font-weight: 600;
}

/* Group calendar only (group.js) - a chip for a teammate's task instead of
   your own: no edit permission exists for it anywhere else in the app
   either, so it stays visually present but inert rather than pretending
   to be clickable. */
.calendarChip.notEditable{
    cursor: default;
    opacity: 0.82;
}

/* Small per-member color dot, prepended to a group calendar chip before its
   icon - a second, independent visual channel from the chip's own urgency
   border/background (due/soon/critical/overdue), which stays exactly as
   themed for everyone. 8 fixed hues (getGroupMemberColorIndex in group.js
   deterministically hashes each ownerId onto one of them), chosen to read
   clearly against the dark cards and to stay distinct from each other. */
.calendarChipMemberDot{
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 auto;
}

/* Evenly spaced around the full hue wheel (45deg apart, fixed saturation/
   lightness) rather than 8 hand-picked hex values - two of the old picks
   (violet/blue-violet) sat only ~25deg apart and read as "the same color"
   at a 7px dot size, which is the actual bug report. 45deg steps keep
   every neighbor clearly distinct regardless of which two members end up
   next to each other. */
.calendarMemberColor-0{ background: hsl(0, 78%, 64%); }
.calendarMemberColor-1{ background: hsl(45, 78%, 58%); }
.calendarMemberColor-2{ background: hsl(90, 55%, 52%); }
.calendarMemberColor-3{ background: hsl(150, 60%, 52%); }
.calendarMemberColor-4{ background: hsl(190, 70%, 55%); }
.calendarMemberColor-5{ background: hsl(220, 80%, 68%); }
.calendarMemberColor-6{ background: hsl(265, 78%, 72%); }
.calendarMemberColor-7{ background: hsl(320, 75%, 68%); }

/* Legend row above the grid - color alone doesn't say whose task is whose,
   so the mapping gets spelled out once here instead of left to memory. */
.calendarMemberLegend{
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-bottom: var(--space-3);
}

.calendarMemberLegendItem{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--text-xs);
    color: var(--violet-muted);
}

.calendarMoreBtn{
    align-self: flex-start;
    border: none;
    background: none;
    color: var(--violet-accent);
    font-size: var(--text-2xs);
    font-weight: 700;
    cursor: pointer;
    padding: 2px 0;
}

.calendarMoreBtn:hover{
    text-decoration: underline;
}

.calendarMoreBtn.hidden{
    display: none;
}

.calendarLegendHint{
    font-size: var(--text-2xs);
    color: var(--violet-muted);
    text-align: center;
}

/* Mobile: a 7-column grid doesn't work in a phone's width, so the exact
   same .calendarDayCell markup collapses into a single-column agenda list
   instead - one DOM tree, two layouts, driven entirely by CSS (no JS
   re-render needed on resize). Out-of-month padding cells are hidden
   outright here rather than dimmed, since a long scrolling list of mostly-
   empty adjacent-month days adds scroll with no value; navigate months
   with Prev/Next instead. */
@media (max-width: 900px){
    .calendarWeekdayRow{
        display: none;
    }

    .calendarGrid,
    .calendarGrid.calendarGridWeek{
        grid-template-columns: 1fr;
        grid-auto-rows: auto;
    }

    .calendarDayCell.outOfMonth{
        display: none;
    }

    .calendarDayCell{
        flex-direction: row;
        align-items: flex-start;
        flex-wrap: wrap;
        min-height: 0;
    }

    .calendarDayNumber{
        display: none;
    }

    .calendarDayFullLabel{
        display: block;
        flex: 0 0 100%;
        font-size: var(--text-xs);
        font-weight: 800;
        color: var(--violet-text);
    }

    .calendarDayCell.today .calendarDayFullLabel{
        color: var(--violet-accent);
    }

    .calendarChipList{
        flex: 1 1 100%;
    }
}


/* Task slot visual separation: active vs completed */
.tasks li{
    background:
        linear-gradient(160deg, var(--card-1) 0%, var(--card-2) 52%, var(--card-3) 100%);
    border-color: var(--card-border);
    border-top: 2px solid var(--card-top-accent);
}

.tasks li.completed{
    background:
        linear-gradient(160deg, rgba(28, 22, 52, 0.82) 0%, rgba(20, 16, 40, 0.85) 52%, rgba(10, 8, 26, 0.88) 100%);
    border-color: rgba(137, 136, 175, 0.32);
    border-top-color: rgba(181, 139, 255, 0.3);
    box-shadow: inset 0 1px 0 rgba(221, 214, 255, 0.06);
}

/* Skeleton rows shown while the first Firestore snapshot is still in
   flight (see renderTaskListSkeleton in script.js) - same size/shape as
   a real .tasks li so the list doesn't visibly jump once real data
   replaces these, just a shimmering placeholder instead of real content. */
.taskSkeletonRow{
    width: 90%;
    padding: 10px;
    background: var(--violet-surface-soft);
    border-radius: 10px;
    border: 2px solid var(--violet-border-soft);
    display: flex;
    align-items: center;
    gap: 10px;
}

.taskSkeletonCheck{
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border-radius: var(--radius-circle);
    background: linear-gradient(90deg, rgba(170, 152, 255, 0.14) 25%, rgba(170, 152, 255, 0.3) 37%, rgba(170, 152, 255, 0.14) 63%);
    background-size: 400% 100%;
}

.taskSkeletonLines{
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.taskSkeletonBar{
    height: 12px;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg, rgba(170, 152, 255, 0.14) 25%, rgba(170, 152, 255, 0.3) 37%, rgba(170, 152, 255, 0.14) 63%);
    background-size: 400% 100%;
}

.taskSkeletonBar--text{ width: 60%; }
.taskSkeletonBar--meta{ width: 34%; height: 9px; }

.taskSkeletonRow:nth-child(2) .taskSkeletonBar--text{ width: 78%; }
.taskSkeletonRow:nth-child(3) .taskSkeletonBar--text{ width: 45%; }

@media (prefers-reduced-motion: no-preference){
    .taskSkeletonCheck,
    .taskSkeletonBar{
        animation: skeletonShimmer 1.6s ease-in-out infinite;
    }

    .taskSkeletonRow:nth-child(2) .taskSkeletonCheck,
    .taskSkeletonRow:nth-child(2) .taskSkeletonBar{ animation-delay: 0.15s; }
    .taskSkeletonRow:nth-child(3) .taskSkeletonCheck,
    .taskSkeletonRow:nth-child(3) .taskSkeletonBar{ animation-delay: 0.3s; }
}

.tasks li.completed .taskText,
.tasks li.completed .taskMeta{
    opacity: 0.66;
}

/* Keep popup-alert ON state in theme colors (not green) */
.alertToggleBtn.enabled{
    border-color: rgba(203, 176, 255, 0.86);
    background: linear-gradient(120deg, rgba(201, 165, 255, 0.94), rgba(141, 148, 255, 0.95));
    color: #f7f1ff;
}

.alertToggleBtn.enabled:hover{
    border-color: rgba(225, 205, 255, 0.96);
    background: linear-gradient(120deg, rgba(212, 181, 255, 0.98), rgba(154, 161, 255, 0.98));
    color: #ffffff;
}

/* Activity heatmap: purple scale */
.heatCell{
    border: 1px solid rgba(170, 145, 235, 0.32);
    background: rgba(214, 204, 243, 0.74);
}

.heatCell.level-0{ background: rgba(211, 200, 240, 0.7); }
.heatCell.level-1{ background: rgba(192, 170, 241, 0.78); }
.heatCell.level-2{ background: rgba(170, 138, 239, 0.84); }
.heatCell.level-3{ background: rgba(145, 102, 232, 0.9); }
.heatCell.level-4{ background: rgba(119, 72, 218, 0.96); }

/* Mobile-only usability layer (desktop unchanged) */
@media (max-width: 900px){
    html,
    body{
        overflow-x: hidden;
    }

    body{
        padding: 10px 0 16px;
    }

    .container{
        width: min(100%, calc(100vw - 12px));
        border-radius: 14px;
    }

    .appShell{
        grid-template-columns: 1fr;
        gap: 12px;
    }

    .mainColumn,
    .sideColumn{
        gap: 10px;
        margin-top: 0;
        min-width: 0;
    }

    .mainColumn .title{
        margin-bottom: 2px;
    }

    .mainColumn .motivatorContainer{
        min-height: 86px;
        height: auto;
        padding: 14px;
    }

    .mainColumn .inputContainer{
        gap: 8px;
        align-items: center;
    }

    .mainColumn .taskInput{
        height: 46px;
        padding: 12px;
    }

    .mainColumn .detailsToggleBtn,
    .sideColumn .sortOnceBtn,
    .sideColumn .alertToggleBtn,
    .mainColumn .taskViewBtn,
    .mainColumn .typePill{
        min-height: 40px;
    }

    /* .editBtn/.deleteBtn deliberately excluded here - they get a text
       label at this same breakpoint (see the width:auto rule above) and
       must be free to size to their content, not forced back into a
       fixed circle that clips the label. addBtn/checkBtn stay icon-only,
       so a fixed circular touch target is correct for them. */
    .mainColumn .addBtn,
    .mainColumn .checkBtn{
        width: 42px;
        height: 42px;
        min-width: 42px;
    }

    .mainColumn .taskViews{
        flex-wrap: wrap;
        overflow: visible;
        padding-bottom: 0;
        row-gap: 8px;
    }

    .mainColumn .taskViewBtn{
        flex: 0 0 auto;
        padding: 0 10px;
        font-size: 10px;
    }

    .mainColumn .activityPanel,
    .sideColumn .activityPanel{
        width: 100%;
        max-width: 100%;
        min-width: 0;
    }

    .mainColumn .activityGridWrap,
    .sideColumn .activityGridWrap{
        --day-label-width: 22px;
        --cell-gap: 1px;
        overflow-x: hidden;
    }

    .mainColumn .activityMonthLabel,
    .sideColumn .activityMonthLabel{
        font-size: 8px;
    }

    .mainColumn .activityDayLabel,
    .sideColumn .activityDayLabel{
        font-size: 8px;
        padding-right: 1px;
    }

    .mainColumn .activityLegend,
    .sideColumn .activityLegend{
        flex-wrap: wrap;
        justify-content: flex-start;
        gap: 4px;
    }

    .mainColumn .tasks li{
        padding: 12px 10px;
        gap: 10px;
    }

    .mainColumn .taskButtons{
        gap: 8px;
    }

    .mainColumn .taskDetailsPanel.open{
        padding: 8px;
    }

    .mainColumn .taskDetailsPanel .detailsGrid{
        gap: 8px;
    }

    .mainColumn .taskDetailsPanel .taskTypePills{
        width: 100%;
        flex-wrap: wrap;
    }

    .mainColumn .taskDetailsPanel .deadlineContainer{
        grid-template-columns: 1fr;
        gap: 7px;
    }

    .mainColumn .priorityControls,
    .sideColumn .priorityControls{
        width: 100%;
        margin-top: 6px;
        padding: 10px;
        min-height: 0;
        display: flex;
        flex-direction: column;
        justify-content: flex-start;
        align-items: stretch;
        gap: 6px;
    }

    .mainColumn .priorityHeaderRow,
    .sideColumn .priorityHeaderRow{
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "toggle sort";
        align-items: start;
        column-gap: 10px;
        row-gap: 8px;
    }

    .mainColumn .priorityToggleLabel,
    .sideColumn .priorityToggleLabel{
        grid-area: toggle;
        min-width: 0;
        align-self: start;
        margin-top: 2px;
    }

    .mainColumn .sortOnceBtn,
    .sideColumn .sortOnceBtn{
        grid-area: sort;
        justify-self: end;
    }

    .mainColumn .priorityModeHint,
    .sideColumn .priorityModeHint{
        margin-top: 0;
    }

    /* .alertToggleBtn and .metaVisibilityRow used to live in this same grid
       (see the removed "alert" grid-area above) - both now live in Settings
       instead (section A of the UI/UX rework, see settings.js's
       buildOverlay and the unconditional .settingsAlertsSection rules near
       .metaVisibilityRow's base rule, not gated to this breakpoint since
       Settings is reachable regardless of viewport width). */

    .sideColumn .activitySummary{
        white-space: normal;
    }
}

@media (max-width: 560px){
    .mainColumn .inputContainer{
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "task add"
            "prioritize prioritize";
    }

    .mainColumn .taskInput{
        grid-area: task;
    }

    .mainColumn .addBtn{
        grid-area: add;
    }

    .mainColumn .detailsToggleBtn{
        grid-area: prioritize;
        width: 100%;
    }

    .mainColumn .taskDetailsPanel .durationWrap{
        align-items: stretch;
    }
}

/* Activity details, undo, and guided tutorial */
.onboardingActions{
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.onboardingStartTourBtn{
    border: 1px solid rgba(210, 194, 255, 0.76);
    border-radius: 999px;
    height: 30px;
    padding: 0 11px;
    background: linear-gradient(130deg, rgba(191, 162, 255, 0.82), rgba(135, 146, 255, 0.84));
    color: #100829;
    font-weight: 800;
    cursor: pointer;
    white-space: nowrap;
}

.onboardingStartTourBtn:hover{
    filter: brightness(1.06);
}

.activityDetailsOverlay{
    position: fixed;
    inset: 0;
    background: rgba(7, 4, 30, 0.62);
    backdrop-filter: blur(3px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    z-index: 1400;
}

.activityDetailsOverlay.hidden{
    display: none;
}

.activityDetailsCard{
    width: min(540px, 96vw);
    max-height: min(78vh, 620px);
    overflow-y: auto;
    overflow-x: hidden;
    border-radius: 14px;
    border: 1px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    background: linear-gradient(165deg, var(--card-1), var(--card-3));
    box-shadow: var(--card-shadow);
    padding: 14px;
}

.activityDetailsHeader{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.activityDetailsTitle{
    font-size: 16px;
    font-weight: 800;
    color: #f6f2ff;
}

.activityDetailsCloseBtn{
    border: 1px solid rgba(205, 194, 255, 0.64);
    border-radius: 999px;
    height: 30px;
    padding: 0 10px;
    background: rgba(91, 72, 170, 0.5);
    color: #f2edff;
    font-weight: 700;
    cursor: pointer;
}

.activityDetailsMeta{
    margin-top: 8px;
    font-size: 12px;
    color: rgba(218, 208, 255, 0.92);
}

.activityDetailsList{
    margin-top: 10px;
    list-style: none;
    display: grid;
    gap: 8px;
    min-width: 0;
}

.activityDetailsItem,
.activityDetailsEmpty{
    border: 1px solid rgba(181, 162, 245, 0.42);
    border-radius: 10px;
    background: rgba(45, 31, 112, 0.54);
    padding: 9px 10px;
    min-width: 0;
}

.activityDetailsTaskText{
    color: #f5f1ff;
    font-size: 13px;
    line-height: 1.35;
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.activityDetailsTaskTime,
.activityDetailsEmpty{
    margin-top: 4px;
    color: rgba(214, 203, 255, 0.9);
    font-size: 11px;
}

.undoToast{
    position: fixed;
    left: 50%;
    bottom: 18px;
    transform: translateX(-50%);
    z-index: 1450;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    max-width: min(94vw, 560px);
    border: 1px solid rgba(203, 184, 255, 0.55);
    border-radius: 12px;
    background: linear-gradient(155deg, rgba(58, 42, 131, 0.97), rgba(34, 24, 92, 0.98));
    box-shadow: 0 12px 36px rgba(8, 5, 30, 0.55);
    padding: 10px 12px;
}

.undoToast.hidden{
    display: none;
}

.undoToastText{
    color: #f4efff;
    font-size: 13px;
    line-height: 1.35;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.badgeEarnedToast{
    position: fixed;
    left: 50%;
    bottom: 18px;
    transform: translateX(-50%);
    z-index: 1450;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    max-width: min(94vw, 560px);
    border: 1px solid rgba(203, 184, 255, 0.55);
    border-radius: 12px;
    background: linear-gradient(155deg, rgba(58, 42, 131, 0.97), rgba(34, 24, 92, 0.98));
    box-shadow: 0 12px 36px rgba(8, 5, 30, 0.55);
    padding: 10px 14px;
}

.badgeEarnedToast.hidden{
    display: none;
}

.badgeEarnedToastIcon{
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: linear-gradient(135deg, #ffe08a, #d7a83a);
    color: #3a2a05;
    font-size: 12px;
}

.badgeEarnedToastText{
    color: #f4efff;
    font-size: 13px;
    line-height: 1.35;
}

.undoDeleteBtn{
    border: 1px solid rgba(206, 193, 255, 0.82);
    border-radius: 999px;
    height: 30px;
    padding: 0 12px;
    background: linear-gradient(120deg, rgba(198, 168, 255, 0.96), rgba(145, 154, 255, 0.97));
    color: #120a32;
    font-weight: 800;
    cursor: pointer;
    white-space: nowrap;
}


/* The overlay element itself no longer paints or blocks anything - it's
   just a positioning root for its children now. Real bug, reported live:
   a single full-screen dark rect here, with the target merely raised via
   z-index, only works when nothing between the target and <body> creates
   its own stacking context - .container does (position:relative + a real
   z-index, for its own ambient-glow layering), which silently traps every
   z-index set inside it, .tourTarget's 1510 included. The target rendered
   UNDER the dark rect and was completely unclickable as a result, not just
   visually dim. Four independently positioned "curtain" panels (below) that
   tile the viewport minus a real rectangular hole around the current
   target fix this properly - there's no darkness painted over the target
   at all, so there's no stacking context to win against, and the hole is a
   genuine gap in pointer-events coverage, not a z-index illusion. */
.tourOverlay{
    position: fixed;
    inset: 0;
    z-index: 1500;
    pointer-events: none;
}

.tourOverlay.hidden{
    display: none;
}

/* Positioned individually in JS (createTourController's positionCurtains)
   from the current target's live getBoundingClientRect, recomputed on every
   step change, resize, and scroll - same triggers positionCard already
   uses to keep the tour card itself lined up. */
.tourCurtain{
    position: fixed;
    left: 0;
    top: 0;
    width: 0;
    height: 0;
    /* Darkened from 0.56 - the whole point of a spotlight is real contrast
       between "the one thing you're looking at" and everything else, and
       the old value read as a mild dim rather than a clear foreground/
       background split. */
    background: rgba(5, 4, 20, 0.7);
    pointer-events: auto;
}

.tourCard{
    position: fixed;
    left: 12px;
    top: 12px;
    width: min(340px, calc(100vw - 24px));
    border-radius: var(--radius-lg);
    border: 1px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    background: linear-gradient(165deg, var(--card-1), var(--card-3));
    box-shadow: var(--card-shadow);
    padding: 12px;
    color: #f7f4ff;
    /* .tourOverlay (this card's parent) is pointer-events:none now that the
       curtains do the actual blocking - pointer-events is inherited, so
       this needs its own explicit auto or Skip/Next would be inert too. */
    pointer-events: auto;
}

/* Dusty hosts the tour now, not a generic "Tutorial" label - same portrait
   markup the chat FAB/header already use (buildDustyAvatarMarkup), just
   smaller, so it's recognizably the same character talking. */
.tourHeader{
    display: flex;
    align-items: center;
    gap: 8px;
}

.tourDustyAvatar{
    flex: 0 0 auto;
    display: flex;
    line-height: 0;
}

.tourHeaderText{
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.tourDustyName{
    font-size: var(--text-sm);
    font-weight: 800;
    color: #f7f4ff;
}

.tourStepLabel{
    font-size: var(--text-xs);
    font-weight: 700;
    color: rgba(225, 217, 255, 0.9);
}

.tourTitle{
    margin-top: 8px;
    font-size: var(--text-md);
    font-weight: 800;
}

.tourText{
    margin-top: 6px;
    font-size: var(--text-sm);
    line-height: 1.4;
    color: rgba(235, 230, 255, 0.95);
}

/* Shown only for an action-gated step (see createTourController's
   `action` field) - a plain, low-key nudge that this one step wants you
   to actually do the thing, not just read about it. */
.tourActionHint{
    margin-top: 8px;
    font-size: var(--text-xs);
    font-weight: 700;
    color: rgba(214, 201, 255, 0.85);
    font-style: italic;
}

.tourActionHint.hidden{
    display: none;
}

/* Swapped in for .tourActionHint the instant the real action fires - the
   "yes, that's it" moment before auto-advancing. */
.tourActionConfirmed{
    margin-top: 8px;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--text-xs);
    font-weight: 800;
    color: #7fe0a3;
}

.tourActionConfirmed.hidden{
    display: none;
}

.tourActions{
    margin-top: 10px;
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

.tourSkipBtn,
.tourNextBtn{
    border-radius: var(--radius-pill);
    height: 31px;
    padding: 0 var(--space-3);
    font-weight: 800;
    font-size: var(--text-sm);
    cursor: pointer;
}

/* Section K: Skip goes fully ghost/text-only, Next stays the one filled,
   styled primary action - accidentally tapping Skip instead of Next was
   specifically named in the user feedback that drove this whole rework,
   and the two previously shared near-identical weight (same border, both
   with a solid-ish fill), differentiated only by color. */
.tourSkipBtn{
    border: 1px solid transparent;
    background: transparent;
    color: rgba(225, 217, 255, 0.75);
}

.tourSkipBtn:hover{
    color: #ece4ff;
    background: rgba(255, 255, 255, 0.06);
}

.tourNextBtn{
    border: 1px solid rgba(206, 194, 255, 0.76);
    background: linear-gradient(120deg, rgba(198, 168, 255, 0.98), rgba(145, 154, 255, 0.98));
    color: #120a32;
}

/* The one element the current tour step is about. The 4 .tourCurtain panels
   (see .tourOverlay above) already leave a real, undarkened hole around it,
   so this needs no z-index trick to "beat" the overlay - it was never
   covered in the first place. position/z-index stay here only as cheap
   insurance against ordinary same-page siblings that might otherwise
   overlap it, not against the tour overlay itself. filter:brightness makes
   it read as genuinely lit up rather than just outlined against the dark
   backdrop, and the ring itself pulses rather than sitting static, so it
   reads as "this is alive, interact with me" instead of just "this is
   circled." */
.tourTarget{
    position: relative;
    z-index: 1;
    border-radius: 12px;
    filter: brightness(1.12) saturate(1.08);
    animation: tourTargetPulse 1.8s ease-in-out infinite;
}

@keyframes tourTargetPulse{
    0%, 100%{
        box-shadow: 0 0 0 3px rgba(214, 201, 255, 0.85), 0 0 0 8px rgba(133, 111, 224, 0.4), 0 0 22px 4px rgba(180, 156, 255, 0.35);
    }
    50%{
        box-shadow: 0 0 0 4px rgba(214, 201, 255, 1), 0 0 0 12px rgba(133, 111, 224, 0.22), 0 0 32px 8px rgba(180, 156, 255, 0.5);
    }
}

/* The instant an action-gated step's real action fires (see
   armActionListener) - a brief green confirmation ring replaces the
   violet pulse for the ~900ms pause before the tour moves on, the visual
   half of the same "yes, that's it" moment .tourActionConfirmed's text
   gives. */
.tourTargetConfirmed{
    animation: none !important;
    box-shadow: 0 0 0 3px rgba(127, 224, 163, 0.9), 0 0 0 9px rgba(127, 224, 163, 0.32), 0 0 26px 6px rgba(127, 224, 163, 0.45) !important;
}

@media (prefers-reduced-motion: reduce){
    .tourTarget{
        animation: none;
        box-shadow: 0 0 0 3px rgba(214, 201, 255, 0.85), 0 0 0 8px rgba(133, 111, 224, 0.4), 0 0 22px 4px rgba(180, 156, 255, 0.35);
    }
}

.rewardOverlay{
    position: fixed;
    inset: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px;
    background: rgba(8, 18, 38, 0.5);
    z-index: 1500;
}

.rewardOverlay.hidden{
    display: none;
}

.rewardCard{
    position: relative;
    width: min(380px, 92vw);
    background: rgba(247, 252, 255, 0.95);
    border: 2px solid rgba(74, 146, 246, 0.5);
    border-radius: 18px;
    box-shadow: 0 24px 54px rgba(28, 67, 128, 0.32);
    padding: 30px 22px 26px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 4px;
    overflow: hidden;
}

.confettiField{
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}

.confettiPiece{
    position: absolute;
    top: -14px;
    width: 8px;
    height: 14px;
    border-radius: 2px;
    animation-name: confettiFall;
    animation-timing-function: ease-in;
    animation-fill-mode: forwards;
}

@keyframes confettiFall{
    0%{
        transform: translateY(-20px) rotate(0deg);
        opacity: 1;
    }
    100%{
        transform: translateY(360px) rotate(320deg);
        opacity: 0;
    }
}

.rewardKicker{
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: #8a6112;
}

.rewardTitle{
    font-size: 22px;
    font-weight: 800;
    color: #1f2d4a;
}

.rewardReelViewport{
    position: relative;
    width: 100%;
    height: 84px;
    margin-top: 16px;
    overflow: hidden;
    border-radius: 12px;
    background: rgba(15, 30, 55, 0.08);
    -webkit-mask-image: linear-gradient(90deg, transparent, black 14%, black 86%, transparent);
    mask-image: linear-gradient(90deg, transparent, black 14%, black 86%, transparent);
    transition: opacity 0.3s ease, max-height 0.3s ease, margin-top 0.3s ease;
}

.rewardCard.revealed .rewardReelViewport{
    opacity: 0;
    max-height: 0;
    height: 0;
    margin-top: 0;
    pointer-events: none;
}

.rewardReelTrack{
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
}

.rewardReelPointer{
    position: absolute;
    left: 50%;
    top: 0;
    bottom: 0;
    width: 2px;
    transform: translateX(-50%);
    background: #2f8fff;
    opacity: 0.8;
    z-index: 2;
}

.rewardReelPointer::before,
.rewardReelPointer::after{
    content: '';
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
}

.rewardReelPointer::before{
    top: -1px;
    border-top: 6px solid #2f8fff;
}

.rewardReelPointer::after{
    bottom: -1px;
    border-bottom: 6px solid #2f8fff;
}

.rewardTile{
    flex: 0 0 auto;
    width: 108px;
    height: 68px;
    border-radius: 10px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 6px;
    font-size: 10px;
    font-weight: 700;
    line-height: 1.2;
    text-align: center;
    color: #23375f;
}

.rewardTile i{
    font-size: 16px;
}

.rewardTile-tier-1{ background: rgba(233, 238, 255, 0.95); border: 1px solid rgba(184, 198, 232, 0.9); }
.rewardTile-tier-2{ background: rgba(214, 233, 255, 0.95); border: 1px solid rgba(140, 190, 245, 0.9); }
.rewardTile-tier-3{ background: rgba(228, 214, 255, 0.95); border: 1px solid rgba(181, 139, 255, 0.9); color: #3a2a6e; }
.rewardTile-tier-4{ background: rgba(255, 238, 205, 0.95); border: 1px solid rgba(215, 183, 120, 0.95); color: #7a5a12; }

.rewardTile.landed{
    animation: rewardTileLanded 0.6s ease-out;
    box-shadow: 0 0 0 3px rgba(47, 143, 255, 0.55), 0 0 22px rgba(47, 143, 255, 0.45);
}

@keyframes rewardTileLanded{
    0%{ transform: scale(1); }
    40%{ transform: scale(1.16); }
    100%{ transform: scale(1); }
}

.rewardResult{
    max-height: 0;
    margin-top: 0;
    overflow: hidden;
    opacity: 0;
    transform: translateY(6px);
    pointer-events: none;
    transition: opacity 0.35s ease, transform 0.35s ease, max-height 0.35s ease, margin-top 0.35s ease;
}

.rewardCard.revealed .rewardResult{
    max-height: 140px;
    margin-top: 10px;
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.rewardSuggestionLabel{
    margin-top: 10px;
    font-size: 12px;
    font-weight: 700;
    color: #4d617f;
}

.rewardSuggestionText{
    font-size: 17px;
    font-weight: 700;
    color: #1f2d4a;
}

.rewardCloseBtn{
    margin-top: 0;
    height: 40px;
    max-height: 0;
    padding: 0 24px;
    border-radius: 999px;
    border: 2px solid #58a4ff;
    background: #2f8fff;
    color: #ffffff;
    font-weight: 700;
    cursor: pointer;
    overflow: hidden;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease, max-height 0.35s ease, margin-top 0.35s ease;
}

.rewardCard.revealed .rewardCloseBtn{
    margin-top: 16px;
    max-height: 40px;
    opacity: 1;
    pointer-events: auto;
}

.rewardCloseBtn:hover{
    filter: brightness(1.06);
}

@media (prefers-reduced-motion: reduce){
    .confettiPiece{
        animation: none;
        display: none;
    }

    .rewardReelViewport,
    .rewardResult,
    .rewardCloseBtn{
        transition: none;
    }

    .rewardTile.landed{
        animation: none;
    }
}

/* Sign-in gate + signed-in user badge */
body.authGateActive .container,
body.authChecking .container,
body.authGateActive > .viewTabs,
body.authChecking > .viewTabs{
    display: none;
}

body.authGateActive .userBadge,
body.authChecking .userBadge{
    display: none;
}

/* Shown only while the first onAuthChange callback hasn't fired yet, so we
   never flash the full sign-in form for someone who's actually signed in. */
.authLoadingScreen{
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1900;
    align-items: flex-start;
    justify-content: center;
    overflow: hidden;
    overflow-y: auto;
    /* Matches body's real clamp(12px, 2.6vh, 24px) top padding exactly -
       an earlier version of this guessed at a much bigger value, which is
       exactly why the title sat with a large gap above it that the real
       page doesn't have. */
    padding-top: clamp(12px, 2.6vh, 24px);
}

/* Fixed top-right placeholder mirroring the real .userBadge (position,
   size, shape) exactly - the earlier skeleton omitted it entirely, even
   though it's one of the first things visible on every real page. */
.authSkeletonUserBadge{
    position: fixed;
    top: 14px;
    right: 14px;
    z-index: 1901;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    height: 30px;
}

.authSkeletonUserBadgeAvatar,
.authSkeletonUserBadgePill{
    background: linear-gradient(90deg, rgba(170, 152, 255, 0.14) 25%, rgba(170, 152, 255, 0.3) 37%, rgba(170, 152, 255, 0.14) 63%);
    background-size: 400% 100%;
}

.authSkeletonUserBadgeAvatar{
    width: 26px;
    height: 26px;
    border-radius: var(--radius-circle);
}

.authSkeletonUserBadgePill{
    height: 22px;
    width: 64px;
    border-radius: var(--radius-pill);
}

body.authChecking .authLoadingScreen{
    display: flex;
}

/* Skeleton instead of a spinner, and specifically one that previews the
   real page underneath in roughly its real position - a first attempt at
   this was one generic set of centered bars reused on every page (wrong:
   flagged directly as not previewing anything, just decoration in the
   middle of the screen). Each page below gets its own shape, aligned near
   the top the way the real content will be, not vertically centered.
   Still can't know sign-in vs. dashboard on app.html specifically, but a
   returning user (the common case) sees their real dashboard next, so
   that's the shape to preview - the sign-in card is its own full overlay
   on top of this either way, not a shape this needs to guess at too. */
.authSkeletonPage{
    position: relative;
    z-index: 1;
    /* Matches .container's real, always-applying width exactly (see the
       "Structural layout split" rule - it looks media-query-scoped to
       1060px+ at a glance, but that's dead code superseded by this same
       unconditional value at every viewport). Was hardcoded to a flat
       600px before, so on any normal desktop window the real page (up to
       1280px) rendered roughly half the real width - the "tiny centered
       skeleton vs. full-width real content" bug. */
    width: min(1280px, 97vw);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}

/* The real page's actual content (title/input/cards/task rows) isn't
   .container's full width either - at 1060px+ it's the main column of a
   two-column grid (.appShell), narrower than .container itself. Not
   attempting to replicate that grid's exact math here (a bigger lift than
   a loading placeholder needs); this caps content at a plausible width
   instead of either extreme (full 1280px or the old flat 600px). */
.authSkeletonMain{
    width: min(700px, 100%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}

.authSkeletonTitleBar{
    height: 26px;
    width: 150px;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg, rgba(170, 152, 255, 0.14) 25%, rgba(170, 152, 255, 0.3) 37%, rgba(170, 152, 255, 0.14) 63%);
    background-size: 400% 100%;
}

/* App.html/group dashboard shape: title, then the task-input row (a long
   bar plus two button-shaped placeholders), then a few task rows - reuses
   .taskSkeletonRow/-Check/-Bar exactly, same markup as the real skeleton
   rows shown once the page itself takes over post-auth (see script.js's
   renderTaskListSkeleton / group.js's renderGroupTasks), so there's no
   visible shape change at the handoff. */
.authSkeletonInputRow{
    display: flex;
    align-items: center;
    gap: 8px;
}

.authSkeletonInputBar{
    flex: 1;
    height: 44px;
    border-radius: var(--radius-sm);
}

.authSkeletonPillBtn{
    width: 92px;
    height: 36px;
    border-radius: var(--radius-pill);
}

.authSkeletonCircleBtn{
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-circle);
}

/* Placeholders for the two cards that sit between the input row and the
   task list on the real page - the "Keep it up!" progress/streak card
   (.motivatorContainer) and the "Do This Next" recommendation
   (.nextTaskPanel). Both hidden/collapsed states aside, a returning user
   with tasks already added sees both, so they belong in the preview. */
.authSkeletonMotivatorCard,
.authSkeletonNextTaskCard{
    width: 92%;
    border-radius: 10px;
    background: linear-gradient(90deg, rgba(170, 152, 255, 0.1) 25%, rgba(170, 152, 255, 0.2) 37%, rgba(170, 152, 255, 0.1) 63%);
    background-size: 400% 100%;
}

.authSkeletonMotivatorCard{ height: 64px; }
.authSkeletonNextTaskCard{ height: 46px; }

.authSkeletonTaskRows{
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}

/* Group dashboard shape only: a row of tab-shaped pills between the title
   and the task input, matching the real Tasks/Team/Calendar/Leaderboard/
   Activity tab row. */
.authSkeletonTabRow{
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.authSkeletonTabPill{
    height: 30px;
    width: 84px;
    border-radius: var(--radius-pill);
}

/* group/browse.html ("My Groups") shape: a card grid instead of task rows -
   that page has no task input or task list at all. */
.authSkeletonCardGrid{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
}

.authSkeletonCard{
    height: 88px;
    border-radius: var(--radius-md);
    background: linear-gradient(90deg, rgba(170, 152, 255, 0.1) 25%, rgba(170, 152, 255, 0.2) 37%, rgba(170, 152, 255, 0.1) 63%);
    background-size: 400% 100%;
}

@media (prefers-reduced-motion: no-preference){
    .authSkeletonTitleBar,
    .authSkeletonInputBar,
    .authSkeletonPillBtn,
    .authSkeletonCircleBtn,
    .authSkeletonTabPill,
    .authSkeletonCard,
    .authSkeletonUserBadgeAvatar,
    .authSkeletonUserBadgePill,
    .authSkeletonMotivatorCard,
    .authSkeletonNextTaskCard{
        animation: skeletonShimmer 1.6s ease-in-out infinite;
    }
}

@keyframes skeletonShimmer{
    0%{ background-position: 100% 50%; }
    100%{ background-position: 0% 50%; }
}

.userBadge{
    position: fixed;
    top: 14px;
    right: 14px;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.5);
    border: 2px solid rgba(103, 159, 255, 0.6);
    backdrop-filter: blur(8px);
}

.userBadge.hidden{
    display: none;
}

.userBadgeAvatar{
    width: 26px;
    height: 26px;
    border-radius: var(--radius-circle);
    object-fit: cover;
}

.userBadgeAvatar.hidden{
    display: none;
}

.userBadgeAvatar.isLoadingAvatar{
    background: linear-gradient(90deg, rgba(170, 152, 255, 0.14) 25%, rgba(170, 152, 255, 0.3) 37%, rgba(170, 152, 255, 0.14) 63%);
    background-size: 400% 100%;
}

@media (prefers-reduced-motion: no-preference){
    .userBadgeAvatar.isLoadingAvatar{
        animation: skeletonShimmer 1.6s ease-in-out infinite;
    }
}

.userBadgeName{
    font-size: var(--text-sm);
    font-weight: 700;
    color: #1e1e1e;
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.groupNavLink{
    border: 1px solid rgba(103, 159, 255, 0.6);
    background: rgba(255, 255, 255, 0.6);
    border-radius: var(--radius-pill);
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-xs);
    font-weight: 700;
    color: #2f557f;
    text-decoration: none;
}

.groupNavLink:hover{
    background: rgba(255, 255, 255, 0.85);
}

.userSignOutBtn{
    border: 1px solid rgba(103, 159, 255, 0.6);
    background: rgba(255, 255, 255, 0.6);
    border-radius: var(--radius-pill);
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-xs);
    font-weight: 700;
    color: #2f557f;
    cursor: pointer;
}

.userSignOutBtn:hover{
    background: rgba(255, 255, 255, 0.85);
}

.authOverlay{
    display: none;
    position: fixed;
    inset: 0;
    z-index: 2000;
    flex-direction: column;
    align-items: center;
    padding: clamp(28px, 8vh, 72px) 20px 20px;
    overflow: hidden;
    /* Was its own standalone navy palette (#070b16/#131a30/#0a0e1c),
       unrelated to the app's violet tokens - unified here so the sign-in
       gate reads as the same canvas as everything else, not a different
       product. */
    background: linear-gradient(160deg, var(--violet-bg-1) 0%, var(--violet-bg-2) 55%, var(--violet-bg-3) 100%);
}

body.authGateActive .authOverlay{
    display: flex;
}

.authOverlay::before,
.authOverlay::after{
    content: '';
    position: absolute;
    width: 55vmax;
    height: 55vmax;
    border-radius: var(--radius-circle);
    filter: blur(78px);
    opacity: 0.24;
    pointer-events: none;
}

.authOverlay::before{
    top: -24vmax;
    left: -20vmax;
    background: radial-gradient(circle, rgba(170, 130, 250, 0.85) 0%, rgba(0, 0, 0, 0) 70%);
    animation: authOrbFloatA 20s ease-in-out infinite alternate;
}

.authOverlay::after{
    bottom: -26vmax;
    right: -22vmax;
    background: radial-gradient(circle, rgba(130, 140, 240, 0.8) 0%, rgba(0, 0, 0, 0) 70%);
    animation: authOrbFloatB 24s ease-in-out infinite alternate;
}

@keyframes authOrbFloatA{
    0%{ transform: translate3d(0, 0, 0) scale(1); }
    50%{ transform: translate3d(10vmax, 8vmax, 0) scale(1.12); }
    100%{ transform: translate3d(-6vmax, 14vmax, 0) scale(0.94); }
}

@keyframes authOrbFloatB{
    0%{ transform: translate3d(0, 0, 0) scale(1); }
    50%{ transform: translate3d(-12vmax, -6vmax, 0) scale(1.1); }
    100%{ transform: translate3d(6vmax, -16vmax, 0) scale(0.92); }
}

.authGlow{
    position: absolute;
    top: 55%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: min(620px, 100vw);
    height: min(620px, 100vw);
    border-radius: var(--radius-circle);
    background: radial-gradient(circle, rgba(170, 130, 250, 0.4) 0%, rgba(0, 0, 0, 0) 70%);
    filter: blur(45px);
    animation: authGlowPulse 4.5s ease-in-out infinite;
    pointer-events: none;
    z-index: 0;
}

@keyframes authGlowPulse{
    0%, 100%{ opacity: 0.7; transform: translate(-50%, -50%) scale(1); }
    50%{ opacity: 1; transform: translate(-50%, -50%) scale(1.14); }
}

@media (prefers-reduced-motion: reduce){
    .authOverlay::before,
    .authOverlay::after,
    .authGlow{
        animation: none;
    }
}

.authBrand{
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4);
    flex: 0 0 auto;
}

.authLogo{
    width: 76px;
    height: 76px;
    border-radius: var(--radius-lg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-2xl);
    background: linear-gradient(135deg, var(--violet-accent, #b58bff), var(--violet-accent-2, #7f86ff));
    color: #120b30;
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.4);
}

.authBrandTitle{
    font-family: 'Playfair Display', serif;
    font-size: clamp(var(--text-2xl), 6vw, 48px);
    font-weight: 700;
    color: #f7f4ff;
    letter-spacing: 0.3px;
}

.authCardWrap{
    position: relative;
    z-index: 1;
    flex: 1;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.authCard{
    width: min(340px, 90vw);
    background: rgba(247, 252, 255, 0.95);
    border: 2px solid rgba(74, 146, 246, 0.5);
    border-radius: var(--radius-lg);
    box-shadow: 0 24px 54px rgba(28, 67, 128, 0.32);
    padding: var(--space-6);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    text-align: center;
}

.authGoogleBtn{
    height: 44px;
    border-radius: var(--radius-pill);
    border: 2px solid rgba(103, 159, 255, 0.7);
    background: #ffffff;
    color: #1f2d4a;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
}

.authGoogleBtn:hover{
    background: rgba(240, 246, 255, 1);
}

.authGoogleBtn i{
    font-size: var(--text-md);
    color: #4285f4;
}

.authDivider{
    display: flex;
    align-items: center;
    gap: var(--space-3);
    color: #8a99b3;
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    margin: var(--space-1) 0;
}

.authDivider::before,
.authDivider::after{
    content: '';
    flex: 1;
    height: 1px;
    background: rgba(103, 159, 255, 0.3);
}

.authEmailForm{
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.authEmailInput,
.authPasswordInput{
    height: 44px;
    padding: 0 var(--space-4);
    border-radius: var(--radius-sm);
    border: 2px solid rgba(103, 159, 255, 0.5);
    background: #ffffff;
    color: #1e1e1e;
    font-size: var(--text-base);
    outline: none;
}

.authEmailInput:focus,
.authPasswordInput:focus{
    border-color: rgba(47, 143, 255, 1);
    box-shadow: 0 0 0 3px rgba(47, 143, 255, 0.16);
}

.authErrorText{
    font-size: var(--text-sm);
    font-weight: 700;
    color: #b3261e;
    text-align: left;
}

.authErrorText.hidden{
    display: none;
}

.authInfoText{
    font-size: var(--text-sm);
    font-weight: 700;
    color: #1f7a3f;
    text-align: left;
}

.authInfoText.hidden{
    display: none;
}

.authForgotPasswordBtn{
    align-self: flex-end;
    margin-top: -2px;
    background: transparent;
    border: none;
    color: #2f8fff;
    font-size: var(--text-xs);
    font-weight: 700;
    cursor: pointer;
}

.authForgotPasswordBtn:hover{
    text-decoration: underline;
}

.authForgotPasswordBtn:disabled{
    opacity: 0.6;
    cursor: not-allowed;
}

.authSubmitBtn{
    height: 44px;
    border-radius: var(--radius-pill);
    border: 2px solid #58a4ff;
    background: #2f8fff;
    color: #ffffff;
    font-weight: 700;
    cursor: pointer;
}

.authSubmitBtn:hover{
    filter: brightness(1.05);
}

.authSubmitBtn:disabled{
    opacity: 0.6;
    cursor: not-allowed;
}

.authModeRow{
    margin-top: 2px;
    font-size: var(--text-sm);
    color: #4d617f;
}

.authModeLeadText{
    color: #4d617f;
}

.authModeToggleBtn{
    background: transparent;
    border: none;
    padding: 0;
    color: #2f8fff;
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
}

.authModeToggleBtn:hover{
    text-decoration: underline;
}

@media (max-width: 900px){
    .activityDetailsOverlay{
        align-items: flex-end;
        padding: 10px;
    }

    .activityDetailsCard{
        width: 100%;
        max-height: min(74vh, 520px);
        border-radius: 14px 14px 10px 10px;
    }

    .undoToast{
        bottom: 10px;
        width: min(96vw, 560px);
    }

    .undoToastText{
        white-space: normal;
    }

    /* .userBadge only ever had `right` set, no `left`/max-width, so on a
       narrow screen its row of 5-7 items (Groups/My Tasks, Tutorial, the
       notification bell on group, avatar+name, the Settings gear, Sign
       out) simply grew past the LEFT edge of the viewport with nowhere to
       wrap to - not visually cramped, actually cut off and unreadable,
       reported live. Constraining both left and right forces a real box
       width, which is what makes flex-wrap actually trigger instead of
       silently doing nothing. Labels stay (Tutorial's text label was
       added earlier this session specifically to fix a discoverability
       problem - removing it again here to save space would undo that),
       wrapping to a second row is the fix, not hiding things. */
    .userBadge{
        left: 8px;
        right: 8px;
        flex-wrap: wrap;
        justify-content: flex-end;
        gap: 6px;
        padding: 6px 8px;
    }

    .userBadgeName{
        max-width: 90px;
    }
}

/* Micro-tasks (subtasks): theme this in line with the violet dark palette */
.subtasksToggleBtn{
    color: var(--violet-muted);
}

.subtasksToggleBtn:hover{
    color: #ffffff;
}

.subtaskItem{
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(168, 154, 243, 0.35);
}

.subtaskCheckBtn{
    border-color: rgba(188, 173, 255, 0.68);
    background: #1a123f;
}

.subtaskItem.completed .subtaskCheckBtn{
    color: #f3edff;
    background: linear-gradient(140deg, rgba(180, 132, 255, 0.98), rgba(122, 128, 255, 0.98));
    border-color: rgba(229, 218, 255, 0.85);
}

.subtaskDeleteBtn{
    color: rgba(215, 208, 255, 0.6);
}

.subtaskDeleteBtn:hover{
    color: #ff9d9d;
}

.subtaskDeadlineBtn{
    color: rgba(215, 208, 255, 0.6);
}

.subtaskDeadlineBtn:hover{
    color: var(--violet-accent);
}

.subtaskRenameBtn{
    color: rgba(215, 208, 255, 0.6);
}

.subtaskRenameBtn:hover{
    color: var(--violet-accent);
}

.subtaskRenameInput{
    background: var(--violet-surface);
    border-color: rgba(188, 173, 255, 0.42);
    color: var(--violet-text);
    color-scheme: dark;
}

.subtaskDeadlineClearBtn{
    color: rgba(215, 208, 255, 0.6);
}

.subtaskDeadlineClearBtn:hover{
    color: #ff9d9d;
}

.subtaskText{
    color: var(--violet-text);
}

.subtaskDeadlineInput{
    background: var(--violet-surface);
    border-color: rgba(188, 173, 255, 0.42);
    color: var(--violet-text);
    color-scheme: dark;
}

.subtaskDeadlineInput:focus,
.subtaskDeadlineInput:focus-visible{
    outline: none;
    background: rgba(45, 33, 106, 0.98);
    border-color: rgba(225, 217, 255, 0.72);
    box-shadow: 0 0 0 3px rgba(171, 145, 255, 0.3);
}

.subtaskInput{
    background: var(--violet-surface);
    border-color: rgba(188, 173, 255, 0.42);
    color: var(--violet-text);
}

.subtaskInput::placeholder{
    color: rgba(215, 208, 255, 0.6);
}

.subtaskInput:focus,
.subtaskInput:focus-visible{
    outline: none;
    background: rgba(45, 33, 106, 0.98);
    border-color: rgba(225, 217, 255, 0.72);
    box-shadow: 0 0 0 3px rgba(171, 145, 255, 0.3);
}

.subtaskAddBtn{
    background: #1a123f;
    border-color: rgba(188, 173, 255, 0.68);
}

.subtaskAddBtn:hover{
    background: #2b1f69;
}

/* Faster capture, snooze, and time-block scheduling */
.quickAddHint{
    color: var(--violet-muted);
}

.snoozeSection{
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(168, 154, 243, 0.35);
}

.snoozeLabel{
    color: var(--violet-muted);
}

.editorScheduleWrap:hover{
    background: rgba(232, 243, 255, 0.12);
}

/* Reward / milestone celebration */
.rewardOverlay{
    background: rgba(6, 4, 24, 0.68);
    backdrop-filter: blur(4px);
}

.rewardCard{
    background: linear-gradient(165deg, var(--card-1), var(--card-3));
    border-color: var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    box-shadow: var(--card-shadow);
}

.rewardKicker{
    color: var(--violet-accent, #b58bff);
}

.rewardTitle,
.rewardSuggestionText{
    color: #f7f4ff;
}

.rewardSuggestionLabel{
    color: var(--violet-muted);
}

.rewardCloseBtn{
    border-color: rgba(206, 194, 255, 0.76);
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    color: #120b30;
}

.rewardReelViewport{
    background: rgba(0, 0, 0, 0.25);
}

.rewardReelPointer{
    background: var(--violet-accent, #d7b778);
    opacity: 0.9;
}

.rewardReelPointer::before{
    border-top-color: var(--violet-accent, #d7b778);
}

.rewardReelPointer::after{
    border-bottom-color: var(--violet-accent, #d7b778);
}

.rewardTile{
    color: #f2edff;
}

.rewardTile-tier-1{ background: rgba(255, 255, 255, 0.08); border-color: rgba(190, 190, 210, 0.3); }
.rewardTile-tier-2{ background: rgba(90, 150, 230, 0.22); border-color: rgba(140, 190, 245, 0.5); }
.rewardTile-tier-3{ background: rgba(150, 110, 230, 0.28); border-color: rgba(181, 139, 255, 0.55); }
.rewardTile-tier-4{ background: rgba(215, 183, 120, 0.26); border-color: rgba(215, 183, 120, 0.7); }

.rewardTile.landed{
    box-shadow: 0 0 0 3px rgba(215, 183, 120, 0.7), 0 0 24px rgba(215, 183, 120, 0.5);
}

/* Weekly recap: same card design tokens as .rewardCard/.authCard above,
   own layout - a calm, factual summary, not a celebration, so no confetti/
   reel/kicker-gold styling here. */
.weeklyRecapOverlay{
    position: fixed;
    inset: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px;
    background: rgba(6, 4, 24, 0.68);
    backdrop-filter: blur(4px);
    z-index: 1500;
}
.weeklyRecapOverlay.hidden{ display: none; }

.weeklyRecapCard{
    width: min(380px, 92vw);
    background: linear-gradient(165deg, var(--card-1), var(--card-3));
    border: 2px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    box-shadow: var(--card-shadow);
    border-radius: 18px;
    padding: 26px 22px 22px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 4px;
}

.weeklyRecapKicker{
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: var(--violet-accent, #b58bff);
    margin: 0;
}

.weeklyRecapTitle{
    font-size: 20px;
    font-weight: 800;
    color: #f7f4ff;
    margin: 2px 0 0;
}

.weeklyRecapStats{
    display: flex;
    width: 100%;
    gap: 8px;
    margin-top: 18px;
}

.weeklyRecapStat{
    flex: 1;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid var(--card-border);
    border-radius: 12px;
    padding: 10px 6px;
}

.weeklyRecapStatValue{
    font-size: 22px;
    font-weight: 800;
    color: #f7f4ff;
    margin: 0;
    font-variant-numeric: tabular-nums;
}

.weeklyRecapStatLabel{
    font-size: 11px;
    color: var(--violet-muted, #d7d0ff);
    margin: 2px 0 0;
}

.weeklyRecapNewBadges{
    width: 100%;
    margin-top: 16px;
}
.weeklyRecapNewBadges.hidden{ display: none; }

.weeklyRecapNewBadgesLabel{
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--violet-muted, #d7d0ff);
    margin: 0 0 6px;
}

.weeklyRecapNewBadgesRow{
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 8px;
}

.weeklyRecapNewBadgesRow .achievementChip{
    cursor: default;
}

.weeklyRecapCloseBtn{
    margin-top: 20px;
    border: 1px solid rgba(206, 194, 255, 0.76);
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    color: #120b30;
    font: inherit;
    font-weight: 700;
    font-size: 14px;
    padding: 10px 28px;
    border-radius: 999px;
    cursor: pointer;
}

/* Sign-in gate + signed-in user badge */
.authCard{
    background: linear-gradient(165deg, var(--card-1), var(--card-3));
    border-color: var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    box-shadow: var(--card-shadow);
}

.authGoogleBtn{
    background: rgba(255, 255, 255, 0.95);
    border-color: rgba(170, 152, 255, 0.4);
}

.authDivider{
    color: rgba(215, 208, 255, 0.6);
}

.authDivider::before,
.authDivider::after{
    background: rgba(188, 173, 255, 0.3);
}

.authEmailInput,
.authPasswordInput{
    background: var(--violet-surface, rgba(20, 13, 56, 0.82));
    border-color: rgba(188, 173, 255, 0.42);
    color: var(--violet-text, #f6f4ff);
}

.authEmailInput::placeholder,
.authPasswordInput::placeholder{
    color: rgba(215, 208, 255, 0.6);
}

.authEmailInput:focus,
.authPasswordInput:focus{
    background: rgba(45, 33, 106, 0.98);
    border-color: rgba(225, 217, 255, 0.72);
    box-shadow: 0 0 0 3px rgba(171, 145, 255, 0.3);
}

.authSubmitBtn{
    border-color: rgba(206, 194, 255, 0.76);
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    color: #120b30;
}

.authModeToggleBtn{
    color: var(--violet-accent, #d7b778);
}

.userBadge{
    background: var(--violet-surface);
    border-color: var(--violet-border-soft);
}

.userBadgeName{
    color: #f2edff;
}

/* .groupNavLink/.userSignOutBtn/.helpTourBtn used to hardcode their own
   separate navy-gray family (rgba(20,30,45,...)), unrelated to the rest of
   the app's violet tokens - folded into the shared surface/border tokens
   here so this floating badge reads as the same system as everything else. */
.groupNavLink{
    background: var(--violet-surface);
    border-color: var(--violet-border-soft);
    color: #dce8fb;
}

.groupNavLink:hover{
    background: var(--violet-surface-soft);
}

.userSignOutBtn{
    background: var(--violet-surface);
    border-color: var(--violet-border-soft);
    color: #dce8fb;
}

.userSignOutBtn:hover{
    background: var(--violet-surface-soft);
}

.helpTourBtn{
    height: 32px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-sm);
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface);
    color: #dce8fb;
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

/* Group page only (see group.js's renderApp) - there's no group tour to
   restart before a group dashboard is actually showing, so this hides
   rather than sitting there doing nothing/pointing at elements that don't
   exist yet. Solo never applies this class - its tour is always available. */
.helpTourBtn.hidden{
    display: none;
}

.helpTourBtn:hover{
    background: var(--violet-surface-soft);
    border-color: var(--violet-accent);
}

/* Dusty - the Brain Dump mascot. Fixed bottom-right on both Solo and Group
   pages. Kept as the SAME .brainDumpToggleBtn class/selector script.js and
   group.js already query - group.js's existing renderApp() gating
   (.hidden while no group is selected) and both files' click -> open()
   wiring need no changes; only this element's shape/position/content
   changed. brain-dump.js's mountFab() injects Dusty's SVG portrait and the
   first-visit hint bubble into it at controller-creation time, and toggles
   .brainDumpFabHidden/.dustyGreet from open()/close(). */
.brainDumpToggleBtn{
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 1420;
    width: 68px;
    height: 68px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: radial-gradient(circle at 35% 28%, rgba(255, 250, 240, 0.98), rgba(120, 92, 200, 0.92));
    box-shadow: 0 0 0 3px rgba(178, 161, 255, 0.5), 0 14px 30px rgba(12, 6, 40, 0.55);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: visible;
    transition: transform 0.25s ease, opacity 0.25s ease, box-shadow 0.2s ease;
}

.brainDumpToggleBtn:hover{
    box-shadow: 0 0 0 4px rgba(203, 176, 255, 0.72), 0 16px 34px rgba(12, 6, 40, 0.6);
}

.brainDumpToggleBtn .dustyArt{
    animation: dustyBounce 3.2s ease-in-out infinite;
}

.brainDumpToggleBtn:hover .dustyArt{
    animation-duration: 1.6s;
}

/* One-shot "happy to see you" burst played from playGreetBurst() when
   Dusty reappears after the chat closes - not a literal wave (a bust
   portrait has no arm), a quick perk/bounce instead. */
.brainDumpToggleBtn.dustyGreet .dustyArt{
    animation: dustyGreetPulse 0.6s ease-out;
}

/* While the chat card is open, Dusty is already branded into its header -
   the FAB tucks away instead of floating over the open card. */
.brainDumpToggleBtn.brainDumpFabHidden{
    transform: scale(0.4);
    opacity: 0;
    pointer-events: none;
    box-shadow: none;
}

/* Group page only (see group.js's renderApp) - same reasoning as
   .helpTourBtn.hidden above: nothing to add tasks to without a selected
   group. Solo never applies this class - always available there. */
.brainDumpToggleBtn.hidden{
    display: none;
}

@keyframes dustyBounce{
    0%, 100%{ transform: translateY(0) rotate(0deg); }
    30%{ transform: translateY(-6px) rotate(-4deg); }
    50%{ transform: translateY(0) rotate(0deg); }
    72%{ transform: translateY(-3px) rotate(3deg); }
}

@keyframes dustyGreetPulse{
    0%{ transform: scale(1) rotate(0deg); }
    35%{ transform: scale(1.18) rotate(-6deg); }
    65%{ transform: scale(0.94) rotate(4deg); }
    100%{ transform: scale(1) rotate(0deg); }
}

/* Blink - targets the eyelid rects baked into every Dusty portrait
   (buildDustyAvatarMarkup in brain-dump.js), wherever it's used (FAB,
   chat header, message avatars all blink in sync). transform-box: fill-box
   makes "center" resolve to each rect's own geometry rather than the SVG
   viewport, so no per-instance transform-origin math is needed. */
@keyframes dustyBlink{
    0%, 92%, 100%{ transform: scaleY(0); }
    95%, 97%{ transform: scaleY(1); }
}

.dustyEyelid{
    transform-box: fill-box;
    transform-origin: center;
    animation: dustyBlink 4.6s ease-in-out infinite;
}

.dustyEyelidR{
    animation-delay: 0.05s;
}

/* First-visit-only speech bubble, shown/dismissed by
   maybeShowIntroHint() in brain-dump.js (localStorage-tracked, once ever). */
.dustyHint{
    position: absolute;
    right: calc(100% + 10px);
    bottom: 8px;
    width: max-content;
    max-width: 190px;
    padding: 8px 12px;
    border-radius: 12px;
    border: 1px solid rgba(178, 161, 255, 0.5);
    background: linear-gradient(155deg, rgba(58, 42, 131, 0.97), rgba(34, 24, 92, 0.98));
    color: #f4efff;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.35;
    text-align: left;
    box-shadow: 0 10px 26px rgba(8, 5, 30, 0.5);
    animation: dustyHintIn 0.3s ease-out;
}

.dustyHint::after{
    content: '';
    position: absolute;
    left: 100%;
    bottom: 14px;
    border: 6px solid transparent;
    border-left-color: rgba(34, 24, 92, 0.98);
}

.dustyHint.dustyHintHide{
    animation: dustyHintOut 0.4s ease-in forwards;
}

@keyframes dustyHintIn{
    from{ opacity: 0; transform: translateY(6px); }
    to{ opacity: 1; transform: translateY(0); }
}

@keyframes dustyHintOut{
    from{ opacity: 1; transform: translateY(0); }
    to{ opacity: 0; transform: translateY(6px); }
}

@media (max-width: 620px){
    .brainDumpToggleBtn{
        right: 12px;
        bottom: 12px;
        width: 56px;
        height: 56px;
    }

    .dustyHint{
        max-width: 150px;
        font-size: 11px;
    }
}

/* Brain Dump chat - built dynamically by brain-dump.js, same overlay/.open
   convention as .taskEditorOverlay, sized for a scrolling chat thread
   instead of a short form. */
.brainDumpOverlay{
    position: fixed;
    inset: 0;
    z-index: 1400;
    display: none;
    justify-content: center;
    align-items: center;
    padding: 16px;
    background: rgba(6, 4, 24, 0.68);
    backdrop-filter: blur(4px);
}

.brainDumpOverlay.open{
    display: flex;
}

.brainDumpCard{
    width: min(480px, 100%);
    height: min(680px, 92vh);
    display: flex;
    flex-direction: column;
    border-radius: 16px;
    border: 1px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    background: linear-gradient(160deg, var(--card-1) 0%, var(--card-2) 52%, var(--card-3) 100%);
    box-shadow: var(--card-shadow);
    padding: 16px;
    overflow: hidden;
}

.brainDumpHeader{
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex: 0 0 auto;
    /* .brainDumpCard has no gap between its direct children (header,
       messages, composer), and .brainDumpMessages' own 10px gap only
       applies BETWEEN message bubbles, not above the first one - so
       without this, the header sat flush against Dusty's first message
       with no breathing room at all. */
    margin-bottom: 12px;
}

.brainDumpHeaderIdentity{
    display: flex;
    align-items: center;
    gap: 10px;
}

.brainDumpHeaderAvatar{
    flex: 0 0 auto;
    display: flex;
    line-height: 0;
}

.brainDumpHeaderText{
    display: flex;
    flex-direction: column;
}

.brainDumpHeader h2{
    margin: 0;
    font-size: 18px;
    color: #f4efff;
}

.brainDumpHeaderSubtitle{
    margin: 0;
    font-size: 11px;
    color: rgba(217, 206, 255, 0.72);
}

.brainDumpCloseBtn{
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.08);
    color: #e5dcff;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.brainDumpCloseBtn:hover{
    background: rgba(255, 255, 255, 0.16);
}

.brainDumpMessages{
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-right: 2px;
}

/* Assistant messages/typing are wrapped in a .brainDumpMsgRow (avatar +
   bubble) by appendAssistantBubble()/appendTypingIndicator(); user
   messages and error bubbles are not (no avatar makes sense for either). */
.brainDumpMsgRow{
    display: flex;
    align-items: flex-end;
    gap: 8px;
    align-self: flex-start;
    max-width: 90%;
}

.brainDumpMsgAvatar{
    flex: 0 0 auto;
    line-height: 0;
}

/* Tappable version of a multiple-choice-style question Dusty just asked -
   see appendQuickReplies in brain-dump.js. Left-margin roughly lines the
   chips up under the bubble text rather than under the avatar (24px
   avatar + 8px row gap). */
.brainDumpQuickReplies{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-self: flex-start;
    max-width: 90%;
    margin: -4px 0 0 32px;
}

/* width:100% forces this onto its own line within .brainDumpQuickReplies's
   flex-wrap row, ahead of the chip buttons that follow it in the DOM,
   rather than sitting inline next to the first chip (section J). */
.brainDumpQuickReplyCue{
    width: 100%;
    margin: 0 0 2px;
    font-size: var(--text-2xs);
    color: var(--violet-muted, #d7d0ff);
    opacity: 0.85;
}

.brainDumpQuickReplyChip{
    border: 1px solid rgba(178, 161, 255, 0.5);
    border-radius: 999px;
    padding: 6px 12px;
    background: rgba(255, 255, 255, 0.06);
    color: #dce8fb;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.brainDumpQuickReplyChip:hover{
    background: rgba(198, 168, 255, 0.2);
    border-color: rgba(203, 176, 255, 0.85);
}

.brainDumpMsg{
    min-width: 0;
    padding: 8px 12px;
    border-radius: 12px;
    font-size: 13px;
    line-height: 1.4;
}

.brainDumpMsg p{
    margin: 0;
    /* Renders a real \n a reply keeps within one paragraph (e.g. a numbered
       list the model didn't blank-line-separate) as an actual line break -
       default white-space collapses it to a space, which is a real part of
       why a multi-part reply used to read as one dense block. */
    white-space: pre-wrap;
}

/* appendAssistantBubble (brain-dump.js) now splits a reply into one <p> per
   paragraph (blank-line-separated) instead of always one - this is the
   actual visual gap between them; margin:0 above only zeroes the DEFAULT
   browser paragraph margin, not spacing between sibling paragraphs here. */
.brainDumpMsg p + p{
    margin-top: 8px;
}

.brainDumpMsgUser{
    align-self: flex-end;
    max-width: 88%;
    background: linear-gradient(120deg, rgba(198, 168, 255, 0.98), rgba(145, 154, 255, 0.98));
    color: #120a32;
}

.brainDumpMsgAttachments{
    margin-top: 4px !important;
    font-size: 11px;
    opacity: 0.8;
}

.brainDumpMsgAssistant{
    flex: 1 1 auto;
    background: rgba(255, 255, 255, 0.08);
    color: #f4efff;
}

.brainDumpTyping{
    display: flex;
    align-items: center;
    gap: 6px;
    color: rgba(217, 206, 255, 0.72);
    font-style: italic;
}

/* Cycles through BRAIN_DUMP_THINKING_STAGES (brain-dump.js) - not real
   progress (one request/response, not a stream), just visible motion +
   changing status so a slower reply doesn't read as stuck. */
.brainDumpTypingText{
    transition: opacity 0.2s ease;
}

.brainDumpTypingDots{
    display: inline-flex;
    align-items: center;
    gap: 3px;
    flex: 0 0 auto;
}

.brainDumpTypingDots span{
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.35;
    animation: brainDumpTypingBounce 1.1s ease-in-out infinite;
}

.brainDumpTypingDots span:nth-child(2){
    animation-delay: 0.15s;
}

.brainDumpTypingDots span:nth-child(3){
    animation-delay: 0.3s;
}

@keyframes brainDumpTypingBounce{
    0%, 60%, 100%{ opacity: 0.35; transform: translateY(0); }
    30%{ opacity: 1; transform: translateY(-3px); }
}

@media (prefers-reduced-motion: reduce){
    .brainDumpTypingDots span{
        animation: none;
        opacity: 0.7;
    }
}

.brainDumpMsgError{
    align-self: center;
    background: rgba(255, 90, 90, 0.14);
    border: 1px solid rgba(255, 120, 120, 0.4);
    color: #ffb3b3;
    font-size: 12px;
}

.brainDumpTaskReview{
    align-self: stretch;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px;
    border-radius: 12px;
    border: 1px solid rgba(178, 161, 255, 0.4);
    background: rgba(255, 255, 255, 0.04);
}

/* Section J: only rendered when a reply mixed more than one review-card
   type together (see the presentTypeCount check in sendMessage) - chunks
   a mixed reply visually instead of leaving four card types to read as one
   undifferentiated scroll. */
.brainDumpReviewTypeLabel{
    align-self: flex-start;
    margin: 0;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    background: var(--color-info-soft, rgba(127, 134, 255, 0.16));
    color: var(--violet-accent-2, #7f86ff);
    font-size: var(--text-2xs);
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.4px;
}

.brainDumpTaskCard{
    display: flex;
    gap: 8px;
    padding: 8px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.05);
}

.brainDumpTaskCardHeader{
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding-top: 2px;
}

.brainDumpTaskCardCheck{
    flex: 0 0 auto;
}

/* Hand-styled rather than relying on accent-color alone - accent-color's
   actual rendered weight/contrast varies enough across browsers that it
   was reading as a plain, barely-there checkbox. Shared by every review
   card type (task/suggestion/comment/memory - they all use this same
   .brainDumpTaskCardCheck class), so this one fix covers all of them. */
.brainDumpTaskCardCheck input{
    appearance: none;
    -webkit-appearance: none;
    width: 22px;
    height: 22px;
    margin: 0;
    flex-shrink: 0;
    position: relative;
    border-radius: 6px;
    border: 2px solid rgba(178, 161, 255, 0.5);
    background: rgba(255, 255, 255, 0.06);
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.brainDumpTaskCardCheck input:hover{
    border-color: rgba(203, 176, 255, 0.85);
}

.brainDumpTaskCardCheck input:checked{
    background: linear-gradient(120deg, rgba(198, 168, 255, 0.98), rgba(145, 154, 255, 0.98));
    border-color: rgba(203, 176, 255, 0.92);
}

.brainDumpTaskCardCheck input:checked::after{
    content: '';
    position: absolute;
    left: 6px;
    top: 2px;
    width: 6px;
    height: 11px;
    border: solid #120a32;
    border-width: 0 2.5px 2.5px 0;
    transform: rotate(45deg);
}

.brainDumpTaskCardCheck input:disabled{
    opacity: 0.45;
    cursor: not-allowed;
}

.brainDumpTaskCardCheck input:focus-visible{
    outline: 2px solid rgba(203, 176, 255, 0.9);
    outline-offset: 2px;
}

.brainDumpTaskCardAddBtn{
    height: 22px;
    padding: 0 8px;
    border: none;
    border-radius: 999px;
    background: linear-gradient(120deg, rgba(198, 168, 255, 0.98), rgba(145, 154, 255, 0.98));
    color: #120a32;
    font-size: 10px;
    font-weight: 800;
    cursor: pointer;
    white-space: nowrap;
}

.brainDumpTaskCardAddBtn:disabled{
    opacity: 0.6;
    cursor: not-allowed;
}

.brainDumpTaskCardAddedLabel{
    font-size: 10px;
    font-weight: 700;
    color: #7fe0a3;
    white-space: nowrap;
}

/* Shown instead of .brainDumpTaskCardAddedLabel when commitTaskEdits
   reports a draft actually failed to apply (see createTaskEditReviewCard) -
   e.g. a taskId that no longer matches a real task. Stays next to a
   re-enabled "Try again" button, unlike the success label which replaces
   the button entirely. */
.brainDumpTaskCardFailedLabel{
    font-size: 10px;
    font-weight: 700;
    color: #ff9d9d;
    white-space: normal;
}

/* A memory just auto-saved from chat (see brain-dump.js's
   appendMemorySavedNotice) - a plain inline row, not a card, since there's
   nothing left to confirm, only a real Forget (undo) if it's wrong. */
.brainDumpMemorySaved{
    align-self: stretch;
    display: flex;
    align-items: center;
    gap: 8px;
    background: rgba(181, 139, 255, 0.1);
    border: 1px solid rgba(181, 139, 255, 0.32);
    border-radius: var(--radius-md, 12px);
    padding: 8px 12px;
    font-size: var(--text-sm, 12px);
}

.brainDumpMemorySavedIcon{
    flex: 0 0 auto;
}

.brainDumpMemorySavedText{
    flex: 1 1 auto;
    min-width: 0;
    color: var(--violet-muted, #d7d0ff);
}

.brainDumpMemoryForgetBtn{
    flex: 0 0 auto;
    background: transparent;
    border: none;
    color: var(--violet-accent, #b58bff);
    font-size: var(--text-2xs, 10px);
    font-weight: 700;
    cursor: pointer;
    padding: 2px 4px;
}

.brainDumpMemoryForgetBtn:hover{
    text-decoration: underline;
}

.brainDumpMemorySaved.forgotten{
    opacity: 0.55;
}

.brainDumpMemorySaved.forgotten .brainDumpMemorySavedText{
    text-decoration: line-through;
    text-decoration-color: rgba(215, 208, 255, 0.4);
}

.brainDumpTaskCardFields{
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* Read-only "Suggesting to: X" / "Commenting on X's task: ..." line on
   the teammate-suggestion/comment review cards - see
   createSuggestionReviewCard/createCommentReviewCard in brain-dump.js. */
.brainDumpTaskCardTarget{
    margin: 0;
    font-size: 11px;
    font-weight: 700;
    color: rgba(217, 206, 255, 0.85);
}

/* One row per field Dusty actually proposed changing (createTaskEditReviewCard)
   - only ever the fields present on the draft, never a full form, so a
   one-field edit ("push the deadline") shows exactly one row, not five. */
.brainDumpTaskEditRow{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    font-size: var(--text-xs);
    font-weight: 700;
    color: rgba(217, 206, 255, 0.85);
}

.brainDumpTaskEditRow select{
    height: 30px;
    padding: 0 6px;
    border: 1px solid rgba(178, 161, 255, 0.5);
    border-radius: var(--radius-sm);
    background: rgba(53, 39, 120, 0.95);
    color: #f7f3ff;
    font-size: var(--text-xs);
}

.brainDumpTaskEditRow .brainDumpTaskCardDeadlineWrap{
    flex: 1 1 auto;
    max-width: 220px;
}

/* .brainDumpTaskCardText/.brainDumpTaskCardSubtasks are shared with the
   new-task review card (width:100%, meant to be the sole field in its own
   row) - narrowed back down here so they sit next to their label instead of
   fighting it for space in this row's justify-content:space-between. */
.brainDumpTaskEditRow .brainDumpTaskCardText{
    width: auto;
    flex: 1 1 auto;
    max-width: 220px;
    height: 30px;
}

/* Steps is a multi-line field - stacked (label above, full-width textarea
   below) instead of the side-by-side row every other field here uses,
   since a textarea fighting a label for horizontal space reads cramped. */
.brainDumpTaskEditSubtasksRow{
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
}

.brainDumpTaskEditCompletedRow{
    justify-content: flex-start;
}

.brainDumpTaskEditCompletedRow input[type="checkbox"]{
    accent-color: var(--violet-accent, #b58bff);
}

.brainDumpTaskCardText{
    width: 100%;
    height: 32px;
    padding: 0 8px;
    border: 1px solid rgba(185, 167, 255, 0.4);
    border-radius: 8px;
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    color: #f7f3ff;
    font-size: 12px;
}

.brainDumpTaskCardSubtasks{
    width: 100%;
    padding: 6px 8px;
    border: 1px solid rgba(185, 167, 255, 0.4);
    border-radius: 8px;
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    color: #f7f3ff;
    font-family: inherit;
    font-size: 11px;
    resize: vertical;
}

.brainDumpTaskCardSubtasks::placeholder{
    color: rgba(217, 206, 255, 0.55);
}

/* Per-step draft rows with their own deadline - originally built for Dusty's
   review cards only (createSubtaskRowsEditor lived in brain-dump.js), now
   moved into task-shared.js so the same component drives the always-visible
   Steps field on manual task creation too (see .detailsStepsGroup in
   app.html/script.js) - renamed from the old .brainDumpSubtaskRow* names
   since it's no longer brain-dump-specific, just kept its existing
   dark-purple palette, which was already self-contained (each row supplies
   its own background) rather than depending on a specific parent card.
   (The old names briefly lived here too during the migration - removed now
   that brain-dump.js calls the shared version and nothing sets them.) */
.stepDraftRowsWrap{
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.stepDraftRows{
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.stepDraftRow{
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
}

.stepDraftRowText{
    flex: 1 1 auto;
    min-width: 0;
    height: 30px;
    padding: 0 8px;
    border: 1px solid rgba(185, 167, 255, 0.4);
    border-radius: 8px;
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    color: #f7f3ff;
    font-size: 11px;
}

.stepDraftRowDeadlineBtn,
.stepDraftRowRemoveBtn{
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: none;
    background: transparent;
    color: rgba(217, 206, 255, 0.6);
    font-size: 11px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}

.stepDraftRowDeadlineBtn:hover{
    color: var(--violet-accent, #b58bff);
}

.stepDraftRowDeadlineBtn.hasDeadline{
    color: var(--violet-accent, #b58bff);
}

.stepDraftRowRemoveBtn:hover{
    color: #ff9d9d;
}

.stepDraftRowDeadlineInput{
    flex: 1 1 100%;
    height: 30px;
    padding: 0 8px;
    border: 1px solid rgba(185, 167, 255, 0.4);
    border-radius: 8px;
    background: rgba(35, 24, 92, 0.96);
    color: #f7f3ff;
    font-size: 11px;
    color-scheme: dark;
}

.stepDraftRowDeadlineInput.hidden{
    display: none;
}

.stepDraftAddRowBtn{
    align-self: flex-start;
    background: transparent;
    border: none;
    color: var(--violet-accent, #b58bff);
    font: inherit;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
    padding: 2px 0;
}

.stepDraftAddRowBtn:hover{
    text-decoration: underline;
}

.brainDumpTaskCardRow{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.brainDumpTaskCardMatrix,
.brainDumpTaskCardDifficulty,
.brainDumpTaskCardRecurrence{
    flex: 1 1 100px;
    height: 30px;
    padding: 0 6px;
    border: 1px solid rgba(185, 167, 255, 0.4);
    border-radius: 8px;
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    color: #f7f3ff;
    font-size: 11px;
    color-scheme: dark;
}

.brainDumpTaskCardDeadlineWrap{
    flex: 1 1 140px;
    display: flex;
    align-items: stretch;
    gap: 4px;
}

.brainDumpTaskCardDeadline{
    flex: 1 1 auto;
    min-width: 0;
    height: 30px;
    padding: 0 6px;
    border: 1px solid rgba(185, 167, 255, 0.4);
    border-radius: 8px;
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    color: #f7f3ff;
    font-size: 11px;
    color-scheme: dark;
}

.brainDumpTaskCardDeadlineBtn{
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    border: 1px solid rgba(185, 167, 255, 0.4);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.06);
    color: #e5dcff;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
}

.brainDumpTaskCardDeadlineBtn:hover{
    background: rgba(255, 255, 255, 0.14);
    border-color: var(--violet-accent, #d7b778);
}

.brainDumpTaskReviewFooter{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.brainDumpTaskReviewStatus{
    margin: 0;
    font-size: 11px;
    color: #ffb3b3;
}

.brainDumpTaskReviewActions{
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
}

/* Ghost/secondary treatment next to .brainDumpAddBtn's filled pill - same
   primary-vs-secondary weighting the tour's Next/Skip pair already uses,
   so "I don't want any of these" reads as the lighter, less-committal
   action without competing with the real confirm button. */
.brainDumpDismissReviewBtn{
    height: 32px;
    padding: 0 12px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 999px;
    background: transparent;
    color: var(--violet-muted, #d7d0ff);
    font-weight: 700;
    font-size: 12px;
    cursor: pointer;
}

.brainDumpDismissReviewBtn:hover{
    background: rgba(255, 255, 255, 0.08);
    color: #f2edff;
}

.brainDumpAddBtn{
    height: 32px;
    padding: 0 14px;
    border: none;
    border-radius: 999px;
    background: linear-gradient(120deg, rgba(198, 168, 255, 0.98), rgba(145, 154, 255, 0.98));
    color: #120a32;
    font-weight: 800;
    font-size: 12px;
    cursor: pointer;
}

.brainDumpAddBtn:disabled{
    opacity: 0.6;
    cursor: not-allowed;
}

.brainDumpTaskReviewDone{
    margin: 0;
    font-size: 12px;
    color: #7fe0a3;
    font-weight: 700;
}

.brainDumpAttachmentsRow{
    flex: 0 0 auto;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}

.brainDumpAttachmentsRow.hidden{
    display: none;
}

.brainDumpAttachmentChip{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 6px 3px 8px;
    /* Already pill-shaped, which is the right look for a filename chip - the
       token that actually matches its existing design is --radius-pill, not
       a literal forcing onto --radius-sm just because the plan's radius
       table lists "chips" there in the general case. */
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.08);
    color: #dce8fb;
    font-size: var(--text-xs);
    max-width: 200px;
}

/* Truncates on its own - the remove button (a flex sibling, not part of
   this) stays outside the clipped area so it's always clickable regardless
   of filename length. */
.brainDumpAttachmentChipName{
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.brainDumpAttachmentChip button{
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: inherit;
    cursor: pointer;
    font-size: 10px;
}

.brainDumpAttachmentChip button:hover{
    background: rgba(255, 255, 255, 0.16);
}

/* Live session-budget status - see updateRateStatus in brain-dump.js.
   Subtle while there's budget left, turns urgent/red once the composer's
   actually locked so it reads as a real blocker, not ambient trivia. */
.brainDumpRateStatus{
    flex: 0 0 auto;
    margin: 8px 0 0;
    font-size: var(--text-2xs);
    text-align: center;
    color: rgba(217, 206, 255, 0.65);
}

.brainDumpRateStatus.hidden{
    display: none;
}

.brainDumpRateStatus.blocked{
    color: #ffb3b3;
    font-weight: 700;
}

.brainDumpComposer{
    flex: 0 0 auto;
    margin-top: 10px;
    display: flex;
    align-items: flex-end;
    gap: 8px;
}

.brainDumpAttachBtn,
.brainDumpSendBtn{
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-circle);
    border: 1px solid rgba(185, 167, 255, 0.4);
    background: rgba(255, 255, 255, 0.06);
    color: #e5dcff;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.brainDumpSendBtn{
    background: linear-gradient(120deg, rgba(198, 168, 255, 0.98), rgba(145, 154, 255, 0.98));
    color: #120a32;
    border-color: transparent;
}

.brainDumpAttachBtn:hover,
.brainDumpSendBtn:hover{
    filter: brightness(1.1);
}

.brainDumpAttachBtn:disabled,
.brainDumpSendBtn:disabled{
    opacity: 0.6;
    cursor: not-allowed;
    filter: none;
}

.brainDumpTextInput{
    flex: 1 1 auto;
    min-height: 34px;
    max-height: 160px;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(185, 167, 255, 0.4);
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    color: #f7f3ff;
    font-family: inherit;
    font-size: var(--text-base);
    resize: none;
    overflow-y: auto;
}

.brainDumpTextInput::placeholder{
    color: rgba(217, 206, 255, 0.6);
}

.brainDumpTextInput:focus{
    outline: none;
    border-color: rgba(223, 213, 255, 0.74);
    box-shadow: 0 0 0 3px rgba(170, 143, 255, 0.3);
}

.brainDumpTextInput:disabled{
    opacity: 0.6;
    cursor: not-allowed;
}

/* Aggregate "needs attention" indicator - see computeAttentionSummary/
   updateNavAttentionBadge. Real bug, reported live: this used to be a
   plain <span>, not even a button - not clickable, not keyboard-reachable,
   and its only explanation of what was pending was the title attribute,
   invisible on any touch device. Now a real button that opens
   .navAttentionMenu (below), one row per pending category, each row a
   real jump straight to the thing it's naming - see jumpToUnreadComments/
   jumpToSuggestionsForYou/jumpToJoinRequests. title stays as a bonus
   desktop-hover hint, no longer the only way to see what's pending.
   Hidden entirely at 0 - nothing to click through to when there's nothing
   pending. */
.navAttentionWrap{
    position: relative;
    display: inline-flex;
    align-items: center;
}

.navAttentionBadge{
    display: none;
    align-items: center;
    gap: 3px;
    font-size: 12px;
    color: var(--violet-muted, #b5a8d9);
    background: none;
    border: none;
    padding: 4px;
    border-radius: var(--radius-sm, 8px);
    cursor: pointer;
}

.navAttentionBadge.visible{
    display: inline-flex;
}

.navAttentionBadge:hover,
.navAttentionBadge:focus-visible{
    color: #f2edff;
    background: rgba(255, 255, 255, 0.1);
}

.navAttentionCount{
    min-width: 14px;
    height: 14px;
    padding: 0 4px;
    border-radius: 999px;
    background: #ff5a5a;
    color: #fff;
    font-size: 9px;
    font-weight: 800;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.navAttentionMenu{
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 60;
    min-width: 220px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px;
    border-radius: var(--radius-md, 12px);
    border: 1px solid rgba(220, 207, 255, 0.34);
    background: linear-gradient(165deg, rgba(60, 44, 136, 0.98), rgba(34, 24, 95, 0.99));
    box-shadow: 0 18px 40px rgba(6, 3, 25, 0.5);
}

.navAttentionMenu.hidden{
    display: none;
}

.navAttentionMenuRow{
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    border: none;
    border-radius: var(--radius-sm, 8px);
    background: none;
    color: #f2edff;
    font-size: var(--text-sm, 12px);
    text-align: left;
    cursor: pointer;
}

.navAttentionMenuRow i{
    color: var(--violet-muted, #b5a8d9);
    width: 14px;
    text-align: center;
}

.navAttentionMenuRow:hover,
.navAttentionMenuRow:focus-visible{
    background: rgba(255, 255, 255, 0.1);
}

/* One-shot "look here" pulse for whatever a notification row jumped you
   to - a task row's comment thread, or the suggestions panel. Fades out
   on its own; the class is removed afterward (see flashAttentionTarget)
   purely so it can be re-triggered later without a forced-reflow hack. */
@keyframes attentionFlashPulse{
    0%{
        box-shadow: 0 0 0 3px rgba(198, 168, 255, 0.9), 0 0 24px 4px rgba(180, 156, 255, 0.5);
    }
    100%{
        box-shadow: 0 0 0 3px rgba(198, 168, 255, 0);
    }
}

.attentionFlash{
    animation: attentionFlashPulse 1.6s ease-out;
}

@media (prefers-reduced-motion: reduce){
    .attentionFlash{
        animation: none;
        box-shadow: 0 0 0 3px rgba(198, 168, 255, 0.7);
    }
}

.authModeRow,
.authModeLeadText{
    color: var(--violet-muted);
}

.authInfoText{
    color: #7fe0a3;
}

.authForgotPasswordBtn{
    color: var(--violet-accent, #d7b778);
}

.authPasswordWrap{
    position: relative;
}

.authPasswordWrap .authPasswordInput{
    width: 100%;
    padding-right: 42px;
}

.authPasswordToggleBtn{
    position: absolute;
    right: 5px;
    top: 50%;
    transform: translateY(-50%);
    width: 30px;
    height: 30px;
    border: none;
    background: transparent;
    color: rgba(215, 208, 255, 0.65);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-base);
    border-radius: var(--radius-sm);
}

.authPasswordToggleBtn:hover{
    color: #f6f4ff;
    background: rgba(255, 255, 255, 0.08);
}

.authPasswordStrength{
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-top: -4px;
}

.authPasswordStrength.hidden{
    display: none;
}

.authPasswordStrengthBar{
    height: 5px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.12);
    overflow: hidden;
}

.authPasswordStrengthFill{
    display: block;
    height: 100%;
    width: 0%;
    border-radius: var(--radius-pill);
    transition: width 0.2s ease, background 0.2s ease;
    background: #ff5c5c;
}

.authPasswordStrengthFill.strength-1{ background: #ff5c5c; }
.authPasswordStrengthFill.strength-2{ background: #ffa64d; }
.authPasswordStrengthFill.strength-3{ background: #d7c74d; }
.authPasswordStrengthFill.strength-4{ background: #57d17b; }

.authPasswordStrengthLabel{
    font-size: var(--text-xs);
    font-weight: 700;
    text-align: left;
    color: rgba(215, 208, 255, 0.75);
    margin: 0;
}

/* ===================================================================
   Group workspace (group/index.html). New concepts with no solo
   equivalent - switcher, member roster, invite codes - get their own
   styling here; everything that IS shared with solo (buttons, badges,
   .inputContainer, .taskDetailsPanel, .tasks li) reuses the rules above
   as-is, since group/index.html loads this same stylesheet directly.
   =================================================================== */

.groupStatusMsg{
    color: var(--violet-muted);
    font-size: 14px;
    margin-top: 10px;
}

.groupStatusMsg.hidden{
    display: none;
}

.groupPageWrap{
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding-bottom: 60px;
}

/* Group tasks reuse the exact .appShell/.mainColumn/.sideColumn layout
   solo's page uses (see index.html), which is what makes the Prioritize
   panel/task list sit at the same proportions as solo's instead of
   stretching full-bleed across a much wider single-column page. A couple
   of small overrides for the parts that don't apply here (no effort/
   schedule panel, no tall solo header above it). */
.groupDashboard .sideColumn{
    margin-top: 0;
}

/* No override needed for .scheduleContainer here: it shares the
   .deadlineContainer class, so solo's own shared rule (column 2) applies
   to it too, and grid auto-flow stacks deadline then schedule underneath
   each other in that column - same width, same as solo's real layout -
   rather than side by side. */

/* Two stacked rows of identical-looking pills (whose tasks vs. which
   deadline filter) read as one confusing row without a caption telling
   you what each is choosing between. */
.taskViewsLabel{
    margin: 14px 0 4px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: var(--violet-muted);
}

.taskViewsLabel:first-of-type{
    margin-top: 10px;
}

/* Condensed until there are enough tasks to actually filter through - see
   the groupTasks.length check in renderApp(). All/Overdue stay put (not
   in this :not() list) since Overdue is meaningful even at 1 task. */
.deadlineViewTabs.condensed .taskViewBtn:not([data-view="all"]):not([data-view="overdue"]){
    display: none;
}

/* Solo (1-member) group: "Whose tasks" is just Everyone/Me, which is
   redundant - hidden until a 2nd member makes it meaningful. See
   renderGroupMemberScopeTabs(). */
.whoseTasksLabel.hidden,
.groupMemberScopeTabs.hidden{
    display: none;
}

.yourNameRow{
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.yourNameRow label{
    font-size: 12px;
    font-weight: 700;
    color: var(--violet-muted);
}

.yourNameInputRow{
    display: flex;
    align-items: center;
    gap: 8px;
}

.yourNameInput{
    height: 38px;
    padding: 0 12px;
    border: none;
    outline: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.12);
    color: var(--violet-text);
    font-size: 13px;
    width: min(240px, 60vw);
}

.yourNameSaveBtn{
    height: 34px;
    padding: 0 14px;
    border: none;
    border-radius: 10px;
    background: var(--violet-accent);
    color: #1a1330;
    font-weight: 700;
    font-size: 12px;
    cursor: pointer;
}

.yourNameSaveBtn:hover{
    filter: brightness(1.08);
}

.yourNameSavedMsg{
    font-size: 12px;
    color: #7fe0a3;
    font-weight: 700;
}

.yourNameSavedMsg.hidden{
    display: none;
}

.memberCardFocus{
    margin: 8px 0 0;
    font-size: 12px;
    color: var(--violet-text);
    line-height: 1.4;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.memberCardFocusLabel{
    color: var(--violet-accent);
    font-weight: 700;
}

.groupPageWrap.hidden{
    display: none;
}

/* The sole way to switch/browse groups now (see group.js's removed
   renderGroupSwitcher() - a full pills-per-group row didn't scale once
   someone's in more than a handful of groups). Styled as a small pill
   button rather than a bare text link, since it's carrying that whole job
   alone now. */
.groupBrowseAllLink{
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    border-radius: 999px;
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface-soft);
    font-size: 12px;
    font-weight: 700;
    color: var(--violet-accent);
    text-decoration: none;
}

.groupBrowseAllLink:hover{
    border-color: var(--violet-accent);
    background: var(--violet-surface);
}

.groupBrowseAllLink.hidden{
    display: none;
}

.groupSetupSection{
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.groupSetupSection.hidden{
    display: none;
}

.groupSetupIntro{
    color: var(--violet-muted);
    font-size: 14px;
}

.groupSetupForms{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 14px;
}

.groupCreateForm,
.groupJoinForm{
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 16px;
    border-radius: 14px;
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface-soft);
}

.groupCreateForm h2,
.groupJoinForm h2{
    font-size: 15px;
    color: var(--violet-text);
    margin: 0;
}

.groupCreateNameInput,
.groupJoinCodeInput{
    height: 42px;
    padding: 0 12px;
    border: none;
    outline: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.12);
    color: var(--violet-text);
    font-size: 14px;
}

.groupCreateNameInput::placeholder,
.groupJoinCodeInput::placeholder{
    color: var(--violet-muted);
}

.groupCreateBtn,
.groupJoinBtn{
    height: 40px;
    border: none;
    border-radius: 10px;
    background: var(--violet-accent);
    color: #1a1330;
    font-weight: 700;
    cursor: pointer;
}

.groupCreateBtn:hover,
.groupJoinBtn:hover{
    filter: brightness(1.08);
}

.groupFormError{
    color: #ff9f9f;
    font-size: 13px;
    margin: 0;
}

.groupFormError.hidden{
    display: none;
}

.groupFormInfo{
    color: #7fe0a3;
    font-size: 13px;
    margin: 0;
}

.groupFormInfo.hidden{
    display: none;
}

.groupCreatePrivacyLabel{
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 12px;
    font-weight: 700;
    color: var(--violet-muted);
}

.groupCreatePrivacySelect{
    height: 42px;
    padding: 0 12px;
    border: none;
    outline: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.12);
    color: var(--violet-text);
    font-size: 13px;
    font-weight: 400;
}

.groupSettingsBtn{
    height: 32px;
    padding: 0 14px;
    border: 1px solid var(--violet-border-soft);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.06);
    color: var(--violet-muted);
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.groupSettingsBtn:hover{
    color: var(--violet-accent);
    border-color: var(--violet-accent);
}

.groupSettingsBtn.hidden{
    display: none;
}

/* Desktop popup alert toggle for the group dashboard - a self-contained
   final rule (not the older layered .alertToggleBtn cascade solo's version
   predates), matching this session's other group-header buttons. */
.groupAlertToggleBtn{
    height: 32px;
    padding: 0 14px;
    border: 1px solid var(--violet-border-soft);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.06);
    color: var(--violet-muted);
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
}

.groupAlertToggleBtn:hover{
    color: var(--violet-accent);
    border-color: var(--violet-accent);
}

.groupAlertToggleBtn.enabled{
    border-color: rgba(203, 176, 255, 0.86);
    background: linear-gradient(120deg, rgba(201, 165, 255, 0.94), rgba(141, 148, 255, 0.95));
    color: #120a32;
}

.groupAlertToggleBtn.enabled:hover{
    color: #120a32;
    border-color: rgba(212, 181, 255, 0.98);
    background: linear-gradient(120deg, rgba(212, 181, 255, 0.98), rgba(154, 161, 255, 0.98));
}

.groupAlertToggleBtn:disabled{
    opacity: 0.6;
    cursor: not-allowed;
}

.groupAlertToggleBtn.hidden{
    display: none;
}

/* Pending-join-request count, following .overdueCountBadge's convention
   (a numeric pill, not a plain dot) - see ensureJoinRequestsSubscription/
   updateGroupSettingsBadge. Same red as the unread dots for "needs a
   look," just numeric since more than one request can be pending. */
.groupSettingsCountBadge{
    display: none;
    min-width: 16px;
    height: 16px;
    padding: 0 5px;
    border-radius: 999px;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    font-weight: 800;
    line-height: 1;
    color: #fff;
    background: #ff5a5a;
}

.groupSettingsCountBadge.visible{
    display: inline-flex;
}

/* Group settings modal - built on the shared .taskEditorOverlay/.taskEditorCard
   base (layout, "Close" button via .editorCancelBtn) with its own internals
   for the privacy select and the pending-join-requests list. */
.groupSettingsPrivacyLabel{
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 12px;
    font-weight: 700;
    color: #f4efff;
}

.groupSettingsPrivacySelect{
    width: 100%;
    height: 44px;
    padding: 0 10px;
    border: 2px solid rgba(185, 167, 255, 0.48);
    border-radius: 10px;
    outline: none;
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    color: #f7f3ff;
    font-weight: 500;
}

.groupSettingsPrivacySelect:disabled{
    opacity: 0.6;
    cursor: not-allowed;
}

.groupSettingsPrivacyNote{
    margin: -4px 0 0;
    font-size: 11px;
    color: rgba(217, 206, 255, 0.72);
}

.groupSettingsPrivacyNote.hidden{
    display: none;
}

.groupSettingsRequestsList{
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 220px;
    overflow-y: auto;
}

.groupSettingsRequestsEmpty{
    margin: 0;
    font-size: 12px;
    color: rgba(217, 206, 255, 0.72);
}

.groupSettingsRequestRow{
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
    padding: 8px 10px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.06);
}

.groupSettingsRequestName{
    font-size: 13px;
    color: #f4efff;
    overflow-wrap: anywhere;
}

.groupSettingsRequestActions{
    display: flex;
    gap: 6px;
    flex: 0 0 auto;
}

.groupSettingsApproveBtn,
.groupSettingsDenyBtn{
    height: 28px;
    padding: 0 10px;
    border-radius: 8px;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
}

.groupSettingsApproveBtn{
    border: none;
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    color: #120b30;
}

.groupSettingsApproveBtn:hover{
    filter: brightness(1.08);
}

.groupSettingsDenyBtn{
    border: 1px solid rgba(255, 120, 120, 0.4);
    background: rgba(255, 90, 90, 0.12);
    color: #ffb3b3;
}

.groupSettingsDenyBtn:hover{
    background: rgba(255, 90, 90, 0.22);
}

.groupDashboard{
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.groupDashboard.hidden{
    display: none;
}

.groupDashboardHeader{
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
}

/* Settings/leave/delete clustered together on the right, in that order
   (settings first, delete last) - rather than each spreading out to its
   own evenly-spaced slot next to the invite-code row under the header's
   own space-between, which left "Group settings" drifting away from
   "Delete group" instead of sitting immediately to its left. */
.groupDashboardHeaderActions{
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

.pageTitleRow{
    display: flex;
    align-items: center;
    gap: 12px;
}

.pageTitleRow .title{
    margin-bottom: 0;
}

/* Section X: gains a visible label - a title tooltip alone isn't reachable
   on touch, the same discoverability gap already fixed for .helpTourBtn/
   .brainDumpToggleBtn earlier in this rework. Low-frequency, owner-only,
   so a small pill next to the title rather than reworking the title
   itself into an inline-editable field (a real behavior change with its
   own focus/blur/escape-to-cancel surface, not just a visual one). */
.groupRenameBtn{
    height: 32px;
    padding: 0 var(--space-3);
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    border-radius: var(--radius-pill);
    border: 1px solid var(--violet-border-soft);
    background: rgba(255, 255, 255, 0.06);
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 700;
    cursor: pointer;
}

.groupRenameBtn:hover{
    color: var(--violet-accent);
    border-color: var(--violet-accent);
}

.groupRenameBtn.hidden{
    display: none;
}

.groupLeaveBtn,
.groupDeleteBtn{
    height: 32px;
    padding: 0 14px;
    border: 1px solid rgba(255, 120, 120, 0.4);
    border-radius: 10px;
    background: rgba(255, 90, 90, 0.12);
    color: #ffb3b3;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
}

.groupLeaveBtn:hover,
.groupDeleteBtn:hover{
    background: rgba(255, 90, 90, 0.22);
}

.groupLeaveBtn.hidden,
.groupDeleteBtn.hidden{
    display: none;
}

.groupDashboardName{
    margin: 0;
    font-size: 22px;
    color: var(--violet-text);
}

.groupInviteRow{
    margin: 4px 0 0;
    font-size: 13px;
    color: var(--violet-muted);
    display: flex;
    align-items: center;
    gap: 8px;
}

.groupInviteCode{
    font-family: monospace;
    font-size: 14px;
    letter-spacing: 1px;
    color: var(--violet-text);
    background: var(--violet-surface);
    padding: 2px 8px;
    border-radius: 6px;
}

.groupCopyInviteBtn{
    width: 26px;
    height: 26px;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--violet-muted);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.groupCopyInviteBtn:hover{
    color: var(--violet-text);
}

/* Was rendering with default browser button styling (no dedicated rule
   existed at all) - gray and looking disabled right next to the properly
   styled invite code pill and icon button beside it. Same small-pill
   language as .groupCatchUpDismissBtn (translucent violet, pill radius),
   just with room for the icon + label this one carries instead of being
   icon-only like .groupCopyInviteBtn above. */
.groupCopyInviteLinkBtn{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 30px;
    padding: 0 14px;
    border: 1px solid rgba(221, 208, 255, 0.75);
    border-radius: 999px;
    background: rgba(233, 222, 255, 0.2);
    color: #f8f3ff;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
}

.groupCopyInviteLinkBtn:hover{
    background: rgba(245, 238, 255, 0.28);
}

/* New-member catch-up card (C.4) - same card-token family .nextTaskPanel
   already established (gradient body, accent top border) so it reads as
   part of the same visual system, not a one-off; the icon badge in its
   own header row is what actually differentiates it from that panel and
   from .groupOnboardingHint below, since this is a distinct message (what
   already happened) with a distinct lifetime (once, ever, per member,
   never the tutorial-style "haven't dismissed this session" reset). */
.groupCatchUpCard{
    position: relative;
    width: 92%;
    margin-top: 10px;
    padding: 14px 16px;
    border-radius: 12px;
    border: 1px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    background: linear-gradient(155deg, var(--card-1), var(--card-2));
}

.groupCatchUpCard.hidden{
    display: none;
}

.groupCatchUpHeader{
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 6px;
}

.groupCatchUpIcon{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--violet-accent), var(--violet-accent-2));
    color: #120b30;
    font-size: 12px;
}

.groupCatchUpTitle{
    margin: 0;
    font-size: 14px;
    font-weight: 800;
    color: var(--violet-text);
}

.groupCatchUpGroupName{
    color: var(--violet-accent);
}

.groupCatchUpText{
    margin: 0 0 10px;
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--violet-muted);
    /* Each fact (recent completion, current leader, overdue count) is its
       own line - a joined \n from group.js's buildCatchUpSummaryLines,
       not one run-together sentence - so it reads as a short scannable
       list, not a paragraph to parse. */
    white-space: pre-line;
}

.groupCatchUpDismissBtn{
    height: 30px;
    padding: 0 14px;
    border: 1px solid rgba(221, 208, 255, 0.75);
    border-radius: 999px;
    background: rgba(233, 222, 255, 0.2);
    color: #f8f3ff;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
}

.groupCatchUpDismissBtn:hover{
    background: rgba(245, 238, 255, 0.28);
}

.memberRoster{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px;
}

/* Shown only for a solo (1-member) group - see renderMemberRoster. Same
   family as .leaderboardEmpty/.leaderboardTeaser: small, muted, one line. */
.memberRosterInviteHint{
    margin: 6px 0 0;
    font-size: 12px;
    line-height: 1.4;
    color: var(--violet-muted);
}

.memberRosterInviteHint.hidden{
    display: none;
}

.memberCard{
    display: block;
    width: 100%;
    min-width: 0;
    text-align: left;
    font-family: inherit;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface-soft);
    cursor: pointer;
    overflow: hidden;
}

.memberCard:hover{
    border-color: var(--violet-border);
}

.memberCard.isYou{
    border-color: var(--violet-accent);
}

.memberCard.active{
    border-color: var(--violet-accent);
    box-shadow: 0 0 0 1px var(--violet-accent) inset;
}

/* Suggesting a task moved from a per-roster-card button (Team is roster-
   only now) into this contextual banner in the Tasks view, shown only
   once whose-tasks has a specific teammate selected - see
   renderSuggestForMemberBanner in group.js. */
.suggestForMemberBanner{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    width: 92%;
    margin-top: -4px;
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-sm);
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface-soft);
    color: var(--violet-muted);
    font-size: var(--text-sm);
}

.suggestForMemberBanner.hidden{
    display: none;
}

/* Part B: outcome of creating a group, joining one by code, or a ?join=CODE
   link (see showJoinLinkBanner/maybeHandleJoinLink in group.js) - same
   bounded-banner shape as .suggestForMemberBanner above, but sits at the
   page level above .groupPageWrap since it can fire before a dashboard even
   exists yet (a first-time creator/joiner) as easily as after one does. */
.joinLinkBanner{
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 92%;
    margin: 10px 0;
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-sm);
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface-soft);
    color: var(--violet-text);
    font-size: var(--text-sm);
}

.joinLinkBanner.hidden{
    display: none;
}

.joinLinkBannerText{
    margin: 0;
}

.joinLinkBanner.joinLinkBannerSuccess{
    border-color: rgba(127, 224, 163, 0.4);
}

.joinLinkBanner.joinLinkBannerSuccess .joinLinkBannerText{
    color: #7fe0a3;
}

.joinLinkBanner.joinLinkBannerError{
    border-color: rgba(255, 159, 159, 0.4);
}

.joinLinkBanner.joinLinkBannerError .joinLinkBannerText{
    color: #ff9f9f;
}

.suggestForMemberBtn{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--violet-border-soft);
    background: rgba(255, 255, 255, 0.06);
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 700;
    cursor: pointer;
}

.suggestForMemberBtn:hover{
    color: var(--violet-accent);
    border-color: var(--violet-accent);
}

.memberCardRoleBadge{
    display: inline-block;
    margin-left: 6px;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    vertical-align: middle;
}

.memberCardRoleBadge.role-owner{
    background: linear-gradient(140deg, #ffe08a, #d7a83a);
    color: #3a2a05;
}

.memberCardRoleBadge.role-admin{
    background: rgba(181, 139, 255, 0.28);
    color: #e5d9ff;
}

/* Informational awareness about a teammate's overdue work - amber, not the
   red used for "unread" elsewhere, since this isn't your own inbox. */
.memberCardOverdueFlag{
    margin-left: 6px;
    font-size: 10px;
    color: #e0a63e;
    opacity: 0.85;
    vertical-align: middle;
}

/* A teammate's streak - the one place streaks touch group at all (see the
   plan's reasoning on why this replaces a general friend/profile system).
   Deliberately plain text, not a badge/pill like role or overdue above -
   this is the same "🔥 N" treatment as solo's own streak pill, just inline
   with the name instead of overlapping a counter circle that doesn't exist
   on this card. */
.memberCardStreakFlame{
    margin-left: 6px;
    font-size: 11px;
    font-weight: 700;
    color: #f7f4ff;
    vertical-align: middle;
}

.memberCardModActions{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}

.memberCardRoleBtn,
.memberCardKickBtn{
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
}

.memberCardRoleBtn{
    border: 1px solid var(--violet-border-soft);
    background: rgba(255, 255, 255, 0.06);
    color: var(--violet-muted);
}

.memberCardRoleBtn:hover{
    color: var(--violet-accent);
    border-color: var(--violet-accent);
}

.memberCardKickBtn{
    display: inline-flex;
    align-items: center;
    gap: 5px;
    border: 1px solid var(--color-danger, #ff6b6b);
    background: var(--color-danger-soft, rgba(255, 107, 107, 0.16));
    color: #ffb3b3;
}

.memberCardKickBtn:hover{
    background: var(--color-danger-soft, rgba(255, 107, 107, 0.28));
}

.suggestionsForYouPanel,
.handoffRequestsForYouPanel{
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 4px;
}

.suggestionsForYouPanel.hidden,
.handoffRequestsForYouPanel.hidden{
    display: none;
}

.suggestionRow{
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
    padding: 10px 14px;
    border-radius: 12px;
    border: 1px solid rgba(181, 139, 255, 0.4);
    background: rgba(181, 139, 255, 0.1);
}

.suggestionRowText{
    margin: 0;
    font-size: 13px;
    color: var(--violet-text);
    flex: 1;
    min-width: 200px;
}

.suggestionRowBadges{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    flex: 0 1 100%;
}

/* C.1: outcome of a suggestion YOU sent (renderSuggestionOutcomes in
   group.js) - reuses the pill shape every other badge in this row family
   already uses, just with the same green/red pairing groupFormInfo/
   groupFormError already established elsewhere on this page, so "good"
   and "not accepted" read consistently across the whole dashboard. */
.suggestionOutcomeBadge{
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: var(--radius-pill);
    font-size: var(--text-2xs);
    font-weight: 700;
}

.suggestionOutcomeAccepted{
    background: rgba(127, 224, 163, 0.16);
    color: #7fe0a3;
}

.suggestionOutcomeDismissed{
    background: rgba(255, 159, 159, 0.16);
    color: #ff9f9f;
}

/* Section W: given real visual weight, since "who this is for" is the one
   piece of context this form has that the task editor/Prioritize panel
   don't - previously no more prominent than any other field despite being
   the whole point of this specific modal. */
.suggestForLabel{
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin: -4px 0 4px;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    background: var(--color-info-soft, rgba(127, 134, 255, 0.16));
    font-size: var(--text-md);
    font-weight: 800;
    color: var(--violet-accent);
}

.suggestForLabel i{
    font-size: var(--text-sm);
}

.suggestionRowFrom{
    font-weight: 700;
    color: var(--violet-accent);
}

.suggestionRowActions{
    display: flex;
    gap: 8px;
    flex: 0 0 auto;
}

.suggestionAcceptBtn,
.suggestionDismissBtn{
    height: 30px;
    padding: 0 12px;
    border-radius: 8px;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
}

.suggestionAcceptBtn{
    border: none;
    background: var(--violet-accent);
    color: #1a1330;
}

.suggestionAcceptBtn:hover{
    filter: brightness(1.08);
}

.suggestionDismissBtn{
    border: 1px solid var(--violet-border-soft);
    background: transparent;
    color: var(--violet-muted);
}

.suggestionDismissBtn:hover{
    color: var(--violet-text);
}

/* Handoff picker (Feature 9): reuses .taskEditorOverlay/.taskEditorCard and
   .editorActions/.editorCancelBtn from the suggest-task modal almost
   entirely - only the member-picker list itself is genuinely new markup,
   modeled after the member-scope tabs' avatar-chip button (.scopeTabAvatar,
   reused as-is below) since that's the closest existing "avatar + name,
   click to act" control already in the app. */
.handoffPickerHint{
    margin: 0 0 4px;
    font-size: var(--text-sm);
    color: var(--violet-muted);
}

.handoffPickerList{
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 260px;
    overflow-y: auto;
}

.handoffPickerRow{
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: 10px 14px;
    border-radius: 10px;
    border: 1px solid var(--violet-border-soft);
    background: rgba(181, 139, 255, 0.08);
    color: var(--violet-text);
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    text-align: left;
}

.handoffPickerRow:hover{
    border-color: var(--violet-accent);
    background: rgba(181, 139, 255, 0.16);
}

.handoffPickerRow .scopeTabAvatar{
    width: 24px;
    height: 24px;
    font-size: 11px;
    background: var(--violet-accent);
    color: #1a1330;
    flex-shrink: 0;
}

/* Timezone picker (openTimezonePicker in group.js) - reuses the handoff
   picker's list/row chrome, plus a live local-time column per zone. */
.timezonePickerList{
    max-height: min(360px, 50vh);
    /* dvh shrinks with the on-screen keyboard on iOS, vh doesn't. */
    max-height: min(360px, 45dvh);
}

.timezonePickerRow{
    text-align: left;
}

.timezonePickerRow.selected{
    border-color: var(--violet-accent);
    background: rgba(181, 139, 255, 0.2);
}

.timezonePickerName{
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
}

.timezonePickerTag{
    flex-shrink: 0;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--violet-accent);
    color: #1a1330;
    font-size: 11px;
}

.timezonePickerTime{
    flex-shrink: 0;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--violet-muted);
}

.memberCardName{
    margin: 0 0 4px;
    font-size: 13px;
    font-weight: 700;
    color: var(--violet-text);
    overflow-wrap: anywhere;
}

.memberCardProgress{
    margin: 0 0 8px;
    font-size: 12px;
    color: var(--violet-muted);
}

.memberProgressBarOuter{
    width: 100%;
    height: 6px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.1);
    overflow: hidden;
}

.memberProgressBarInner{
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--violet-accent-2), var(--violet-accent));
}

.groupBrowseGrid{
    width: 100%;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
    margin-top: 16px;
    padding-bottom: 60px;
}

.groupBrowseGrid.hidden{
    display: none;
}

.groupBrowseCard{
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 16px;
    border-radius: 14px;
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface-soft);
    min-width: 0;
}

.groupBrowseCardName{
    margin: 0;
    font-size: 18px;
    color: var(--violet-text);
    overflow-wrap: anywhere;
}

.groupBrowseCardInvite{
    margin: 0;
    font-size: 12px;
    color: var(--violet-muted);
    font-family: monospace;
}

.groupBrowseCardMembers{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.groupBrowseMemberChip{
    padding: 3px 9px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.1);
    color: var(--violet-text);
    font-size: 11px;
    font-weight: 600;
}

.groupBrowseMemberChip.isOwnerChip{
    background: rgba(181, 139, 255, 0.22);
    color: var(--violet-accent);
}

.groupBrowseCardActions{
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: auto;
    padding-top: 6px;
}

.groupBrowseOpenBtn{
    flex: 1;
    text-align: center;
    height: 34px;
    line-height: 34px;
    border-radius: 10px;
    background: var(--violet-accent);
    color: #1a1330;
    font-weight: 700;
    font-size: 12px;
    text-decoration: none;
}

.groupBrowseOpenBtn:hover{
    filter: brightness(1.08);
}

.groupBrowseCardActions .groupLeaveBtn,
.groupBrowseCardActions .groupDeleteBtn{
    height: 34px;
}

.groupBrowseNewCard{
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 8px;
    color: var(--violet-accent);
    text-decoration: none;
    border-style: dashed;
    font-weight: 700;
    min-height: 120px;
}

.groupBrowseNewCard i{
    font-size: 20px;
}

/* Activity is its own always-visible tab now (not a modal opened from a
   trigger button - see the viewTabs restructure and switchGroupView's
   'activity' branch in group.js), so .groupHistoryPanel is just a plain
   card sitting directly in that view, not an overlay. */
.groupHistoryPanel{
    /* Same breathing-room fix as solo's Activity panel and group's own
       Team tab (see .viewPanel[data-view-panel="activity"] .activityPanel) -
       matches .groupLeaderboardPanel's existing margin-top, which never had
       this gap to begin with. */
    margin-top: var(--space-4);
    border-radius: var(--radius-lg);
    border: 1px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    background: linear-gradient(165deg, var(--card-1), var(--card-3));
    box-shadow: var(--card-shadow);
    padding: 16px;
}

.groupHistoryPanelTitle{
    margin: 0 0 12px;
    font-size: var(--text-md);
    font-weight: 800;
    color: #f6f2ff;
}

/* Height-capped and scrolls internally, same reasoning the old modal card
   had - a group with a long completion history shouldn't grow the whole
   tab past the viewport. */
.groupHistoryList{
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    align-content: start;
    gap: 10px;
    max-height: min(60vh, 520px);
    overflow-y: auto;
    padding-right: 4px;
}

.groupHistoryEmpty{
    grid-column: 1 / -1;
    font-size: 12px;
    color: var(--violet-muted);
}

.groupHistoryError{
    color: #ffb3b3;
}

.groupHistoryItem{
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface);
}

.groupHistoryItemText{
    font-size: var(--text-sm);
    color: var(--violet-text);
    overflow-wrap: anywhere;
}

/* tabular-nums: this line carries the completion date/time (section Z,
   same reasoning as the leaderboard's own rank/score columns). */
.groupHistoryItemMeta{
    font-size: var(--text-xs);
    color: var(--violet-muted);
    font-variant-numeric: tabular-nums;
}

/* Leaderboard member modal - opened by clicking a row in the leaderboard,
   a drill-down detail view (one person's completed tasks) rather than one
   of the four main tabs, so it stays a modal - unlike .groupHistoryPanel
   above, which used to be this same overlay pattern before Activity became
   its own tab. */
.leaderboardMemberOverlay{
    position: fixed;
    inset: 0;
    z-index: 1400;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(7, 4, 30, 0.62);
    backdrop-filter: blur(3px);
}

.leaderboardMemberOverlay.hidden{
    display: none;
}

.leaderboardMemberModalCard{
    width: min(440px, 96vw);
    max-height: min(80vh, 560px);
    display: flex;
    flex-direction: column;
    border-radius: var(--radius-lg);
    border: 1px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    background: linear-gradient(165deg, var(--card-1), var(--card-3));
    box-shadow: var(--card-shadow);
    padding: 16px;
}

.leaderboardMemberModalHeader{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 12px;
}

.leaderboardMemberModalTitle{
    margin: 0;
    font-size: 15px;
    font-weight: 800;
    color: #f6f2ff;
    overflow-wrap: anywhere;
}

.leaderboardMemberCloseBtn{
    flex: 0 0 auto;
    border: 1px solid rgba(205, 194, 255, 0.64);
    border-radius: 999px;
    height: 30px;
    padding: 0 12px;
    background: rgba(91, 72, 170, 0.5);
    color: #f2edff;
    font-weight: 700;
    cursor: pointer;
}

.leaderboardMemberList{
    display: flex;
    flex-direction: column;
    gap: 8px;
    overflow-y: auto;
    padding-right: 4px;
}

.leaderboardMemberEmpty{
    font-size: 12px;
    color: var(--violet-muted);
}

.leaderboardMemberItem{
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface);
}

.leaderboardMemberItemText{
    font-size: var(--text-sm);
    color: var(--violet-text);
    overflow-wrap: anywhere;
}

.leaderboardMemberItemMeta{
    font-size: var(--text-xs);
    color: var(--violet-muted);
    font-variant-numeric: tabular-nums;
}

.groupLeaderboardPanel{
    margin-top: 16px;
    padding: 14px;
    border-radius: 12px;
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface-soft);
}

.groupLeaderboardHeader{
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}

.groupLeaderboardTitle{
    margin: 0;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: var(--violet-muted);
}

.leaderboardTabs{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Section I: same pill treatment as the main filter tabs (.taskViewBtn) -
   previously a near-identical but independently-sized component (4px/9px
   padding vs .taskViewBtn's 5px/11px), now one shared shape instead of two
   similar-but-different ones. */
.leaderboardTabBtn{
    border: 1px solid var(--violet-border-soft);
    background: transparent;
    color: var(--violet-muted);
    border-radius: var(--radius-pill);
    padding: 5px 11px;
    font-size: var(--text-xs);
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
    transition: all 0.2s ease;
}

.leaderboardTabBtn:hover{
    color: var(--violet-text);
    border-color: var(--violet-border);
}

.leaderboardTabBtn.active{
    border-color: var(--violet-accent);
    background: var(--violet-accent);
    color: #1a1330;
}

.leaderboardList{
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.leaderboardEmpty{
    font-size: 12px;
    color: var(--violet-muted);
}

/* Solo-group-with-no-history teaser, shown instead of the tabs/list (see
   the soloNoHistory branch in renderGroupLeaderboard) - same tokens as
   .leaderboardEmpty so it reads as part of the same family, not a
   different component. */
.leaderboardTeaser{
    margin: 0;
    font-size: 12px;
    line-height: 1.4;
    color: var(--violet-muted);
}

.leaderboardTeaser.hidden,
.leaderboardTabs.hidden,
.leaderboardList.hidden{
    display: none;
}

.leaderboardRow{
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.leaderboardRow:hover,
.leaderboardRow:focus-visible{
    background: rgba(255, 255, 255, 0.09);
}

.leaderboardRow:focus-visible{
    outline: 2px solid var(--violet-accent);
    outline-offset: 1px;
}

.leaderboardRow.isYou{
    border: 1px solid var(--violet-accent);
    background: rgba(181, 139, 255, 0.1);
}

.leaderboardRow.isYou:hover,
.leaderboardRow.isYou:focus-visible{
    background: rgba(181, 139, 255, 0.16);
}

.leaderboardRank{
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-circle);
    background: rgba(255, 255, 255, 0.08);
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* Top 3 carry an icon plus the ordinal itself ("1st"/"2nd"/"3rd") rather
   than just a numberless icon, so a pill (auto width) instead of the fixed
   22px circle the plain-numbered ranks (4th on) use. */
.leaderboardRank.rank-1,
.leaderboardRank.rank-2,
.leaderboardRank.rank-3{
    width: auto;
    height: 20px;
    padding: 0 8px;
    border-radius: 999px;
    gap: 4px;
    font-size: 10px;
    letter-spacing: 0.2px;
}

.leaderboardRank.rank-1{
    background: linear-gradient(140deg, #ffe08a, #d7a83a);
    color: #3a2a05;
}

.leaderboardRank.rank-2{
    background: linear-gradient(140deg, #e6e6ef, #b6b8c7);
    color: #2a2a33;
}

.leaderboardRank.rank-3{
    background: linear-gradient(140deg, #e3ab7b, #a9713f);
    color: #2f1c0a;
}

.leaderboardName{
    flex: 1;
    min-width: 0;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--violet-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* tabular-nums so scores align in a column instead of jittering as digit
   width changes (section I, same reasoning as the rank badges above). */
.leaderboardCount{
    flex: 0 0 auto;
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--violet-accent);
    font-variant-numeric: tabular-nums;
}

.commentsSection{
    width: 100%;
    margin-top: 4px;
}

.commentsToggleBtn{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: none;
    background: transparent;
    color: var(--violet-muted);
    font-size: 11px;
    font-weight: 700;
    padding: 2px 0;
    cursor: pointer;
}

.commentsToggleBtn:hover{
    color: var(--violet-text);
}

.commentsUnreadDot{
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ff5a5a;
    box-shadow: 0 0 0 2px rgba(255, 90, 90, 0.25);
}

/* Same look as .commentsUnreadDot above, for a completion logged since you
   last opened "Recently finished" - see hasUnreadHistory(). */
.historyUnreadDot{
    width: 8px;
    height: 8px;
    border-radius: var(--radius-circle);
    background: #ff5a5a;
    box-shadow: 0 0 0 2px rgba(255, 90, 90, 0.25);
    flex: 0 0 auto;
}

/* Now sitting inline inside the Activity tab itself (viewTabs restructure),
   not a sidebar trigger button - a little breathing room from the label
   text it directly follows. */
.viewTab .historyUnreadDot{
    margin-left: 2px;
}

.historyUnreadDot.hidden{
    display: none;
}

.commentsBody{
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 6px;
    padding-left: 4px;
}

.commentsBody.hidden{
    display: none;
}

.commentsEmpty{
    font-size: 12px;
    color: var(--violet-muted);
    margin: 0;
}

.commentsError{
    color: #ffb3b3;
}

.commentsList{
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.commentItem{
    position: relative;
    padding: 8px 28px 8px 10px;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(168, 154, 243, 0.3);
}

.commentItemMeta{
    margin: 0 0 2px;
    font-size: 11px;
    font-weight: 700;
    color: var(--violet-accent);
}

.commentItemText{
    margin: 0;
    font-size: 12px;
    color: var(--violet-text);
    overflow-wrap: anywhere;
}

.commentDeleteBtn{
    position: absolute;
    top: 6px;
    right: 6px;
    background: transparent;
    border: none;
    color: rgba(215, 208, 255, 0.5);
    font-size: 11px;
    cursor: pointer;
}

.commentDeleteBtn:hover{
    color: #ff9d9d;
}

.commentAddRow{
    display: flex;
    align-items: center;
    gap: 8px;
}

.commentInput{
    flex: 1;
    min-width: 0;
    height: 34px;
    padding: 0 10px;
    border: none;
    outline: none;
    border-radius: 8px;
    background: var(--violet-surface);
    border: 1px solid rgba(188, 173, 255, 0.42);
    color: var(--violet-text);
    font-size: 12px;
}

.commentInput::placeholder{
    color: rgba(215, 208, 255, 0.6);
}

.commentAddBtn{
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: #1a123f;
    border: 2px solid rgba(188, 173, 255, 0.68);
    color: var(--violet-text);
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
}

.commentAddBtn:hover{
    background: #2b1f69;
}

.ownerBadge{
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.1);
    color: var(--violet-muted);
    font-size: 11px;
    font-weight: 700;
}

/* ===================================================================
   Marketing landing page (index.html). Static, no app state - body/html's
   existing ambient violet gradient + floating orbs (see the DESIGN SYSTEM
   :root block above) already cover the whole-page background for free,
   so nothing here redeclares a hero background. Every size/space/radius
   below comes from that same token block; the one deliberate exception is
   the hero headline, sized past --text-2xl on purpose (see the DESIGN
   SYSTEM comment's own note that a landing page wants looser sizing than
   the dashboard scale), using the exact clamp() pattern .authBrandTitle
   already established rather than inventing a new sizing approach.
   =================================================================== */

/* body's own base rule (line 7 above) sets display:flex/flex-direction:
   column for the app's centered .container layout, with align-items:
   center (shrink-wraps children to their own content width) and a padded
   min-height:100svh - none of that is right for a normal top-to-bottom
   marketing page with full-width sections, so this overrides it
   explicitly rather than relying on what the app happens to leave
   unset. Class beats the bare body element selector regardless of
   source order, so this reliably wins. */
.landingPage{
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: 100vh;
    padding: 0;
    overflow-x: hidden;
}

.landingHeader{
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-5) clamp(var(--space-5), 6vw, var(--space-9));
}

.landingBrand{
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.landingLogo{
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    border-radius: var(--radius-md);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-lg);
    background: linear-gradient(135deg, var(--violet-accent), var(--violet-accent-2));
    color: #120b30;
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.35);
}

.landingLogoSmall{
    width: 32px;
    height: 32px;
    font-size: var(--text-md);
}

.landingBrandName{
    font-family: 'Playfair Display', serif;
    font-weight: 700;
    font-size: var(--text-lg);
    color: var(--violet-text);
}

/* Not a nav menu - the attention-ratio principle this whole page is built
   around (one page, one job, one CTA) means every other exit from this
   page is deliberately absent; a returning user still needs a way back
   in, so this stays. Given a filled pill + solid border (not the old
   ghost-text treatment) so it actually reads against the hero gradient
   instead of disappearing into it - it just needs to be findable, not
   loud, so it still stays well under .landingCtaBtn's visual weight. */
.landingSignInLink{
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--violet-text);
    text-decoration: none;
    padding: var(--space-2) var(--space-5);
    border-radius: var(--radius-pill);
    border: 1px solid var(--violet-border);
    background: var(--violet-surface-soft);
    transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.landingSignInLink:hover{
    color: var(--violet-text);
    border-color: var(--violet-accent);
    background: var(--violet-surface);
}

.landingEyebrow{
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--violet-accent);
    background: var(--color-info-soft);
    padding: var(--space-1) var(--space-4);
    border-radius: var(--radius-pill);
    margin: 0 0 var(--space-4);
}

.landingHero{
    position: relative;
    z-index: 1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-9);
    padding: clamp(var(--space-6), 6vw, var(--space-9)) clamp(var(--space-5), 6vw, var(--space-9)) var(--space-9);
    max-width: 1180px;
    margin: 0 auto;
}

.landingHeroCopy{
    flex: 1 1 420px;
    max-width: 560px;
}

.landingHeadline{
    font-family: 'Playfair Display', serif;
    font-weight: 700;
    font-size: clamp(32px, 5.2vw, 52px);
    line-height: 1.12;
    color: var(--violet-text);
    margin: 0 0 var(--space-4);
}

.landingSubhead{
    font-size: var(--text-md);
    line-height: 1.55;
    color: var(--violet-muted);
    margin: 0 0 var(--space-6);
}

.landingCtaRow{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-5);
    margin-bottom: var(--space-3);
}

/* The single most saturated, boldest thing on the page (Von Restorff
   Effect) - identical everywhere it appears (hero, final CTA), Fitts's-Law
   sized (large, generous padding) since this is the one button that
   matters. */
.landingCtaBtn{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 56px;
    padding: 0 var(--space-7);
    border-radius: var(--radius-pill);
    background: linear-gradient(135deg, var(--violet-accent), var(--violet-accent-2));
    color: #120b30;
    font-size: var(--text-md);
    font-weight: 800;
    text-decoration: none;
    box-shadow: 0 16px 36px rgba(127, 111, 232, 0.4);
    transition: transform 0.16s ease, box-shadow 0.2s ease, filter 0.2s ease;
}

.landingCtaBtn:hover{
    transform: translateY(-1px);
    filter: brightness(1.06);
    box-shadow: 0 20px 42px rgba(127, 111, 232, 0.5);
}

.landingCtaBtn:active{
    transform: translateY(0);
}

/* Deliberately subordinate - ghost/text styling, never the same visual
   weight as the primary CTA. */
.landingSecondaryLink{
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--violet-muted);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.landingSecondaryLink:hover{
    color: var(--violet-text);
}

.landingCtaNote{
    font-size: var(--text-xs);
    color: var(--violet-muted);
    opacity: 0.8;
    margin: 0;
}

/* Hero content fades/slides in on load (not on scroll - it's already on
   screen at first paint, so an IntersectionObserver would fire instantly
   anyway; a plain keyframe is simpler and looks identical). Guarded inside
   prefers-reduced-motion so the default, unconditional state is simply
   "visible" - motion is progressive enhancement, never a requirement to
   see the content. */
@media (prefers-reduced-motion: no-preference){
    @keyframes landingFadeUp{
        from{ opacity: 0; transform: translateY(20px); }
        to{ opacity: 1; transform: translateY(0); }
    }

    .landingEyebrow{ animation: landingFadeUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) both; }
    .landingHeadline{ animation: landingFadeUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) both 0.06s; }
    .landingSubhead{ animation: landingFadeUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) both 0.14s; }
    .landingCtaRow{ animation: landingFadeUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) both 0.22s; }
    .landingCtaNote{ animation: landingFadeUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) both 0.28s; }
    .landingMockWrap{ animation: landingFadeUp 0.8s cubic-bezier(0.16, 1, 0.3, 1) both 0.2s; }
}

.landingMockWrap{
    position: relative;
    flex: 1 1 380px;
    max-width: 420px;
    padding: var(--space-6);
    border-radius: var(--radius-lg);
    background: var(--violet-surface-soft);
    border: 1px solid var(--violet-border-soft);
    box-shadow: 0 30px 70px rgba(5, 2, 30, 0.45);
}

/* Soft ambient glow behind the mock card, same visual DNA as the
   html::before/::after orbs - makes the one piece of "product proof" on
   the page feel like the focal point it is, instead of a flat card. */
.landingMockWrap::before{
    content: '';
    position: absolute;
    inset: -32px;
    z-index: -1;
    background: radial-gradient(circle at 28% 20%, rgba(181, 139, 255, 0.18), rgba(0, 0, 0, 0) 62%);
    pointer-events: none;
}

.landingMockHeader{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.landingMockLabel{
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--violet-muted);
}

.landingMockLabel i{
    color: var(--violet-accent);
}

.landingMockLive{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--text-2xs);
    font-weight: 800;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--color-success);
    background: var(--color-success-soft);
    padding: 3px var(--space-2);
    border-radius: var(--radius-pill);
}

.landingMockLive::before{
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--color-success);
    box-shadow: 0 0 0 3px var(--color-success-soft);
}

/* The dot earns an actual "live" pulse - a radar-ping ring expanding and
   fading, the standard live/recording-indicator motion, not decoration
   for its own sake: it's the one word on the page claiming to be live,
   so it should look like it. transform+opacity only, and only runs when
   motion is welcome. */
@media (prefers-reduced-motion: no-preference){
    .landingMockLive{
        position: relative;
    }

    .landingMockLive::after{
        content: '';
        position: absolute;
        /* Real bug found in review: no `top` (or transform) was set, so
           this fell back to CSS's static-position fallback instead of
           lining up with the flex-centered dot - it needs an explicit
           vertical position same as the horizontal one below. Centered
           via top:50%+margin instead of transform, since the pulse
           animation's own transform:scale() already needs the full
           property and scales outward from the element's default center
           origin correctly once it starts from the right spot. */
        top: 50%;
        left: var(--space-2);
        width: 6px;
        height: 6px;
        margin-top: -3px;
        border-radius: 50%;
        background: var(--color-success);
        animation: livePing 2.2s cubic-bezier(0, 0, 0.2, 1) infinite;
    }

    @keyframes livePing{
        0%{ transform: scale(1); opacity: 0.7; }
        75%, 100%{ transform: scale(2.8); opacity: 0; }
    }
}

/* Real component reuse, not a mockup image - .tasks/.tasks li/.taskMeta/
   the badge classes are the app's own, unmodified. Perfect message match:
   the very first visual proof a visitor sees is pixel-identical to what
   they get one click later. */
.landingMockTasks{
    transform: none;
}

.landingMockTasks li{
    width: 100%;
    padding-left: 44px;
    cursor: default;
}

/* Rank badges are what actually sells "this is ranked, not just listed" -
   color descends from urgent (red) to neutral (violet) so the ordering
   reads at a glance, reinforcing the same urgency colors already on the
   deadline badges beside it rather than inventing a second color code. */
.landingRankBadge{
    position: absolute;
    left: 10px;
    top: 12px;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-2xs);
    font-weight: 800;
}

.landingRankBadge.rank-1{
    background: linear-gradient(135deg, #ffb3b3, var(--color-danger));
    color: #3a0d0d;
}

/* A slow breathing glow on #1 only - not decoration, it's pointing at the
   actual claim on this page ("know exactly what to do next"): the eye
   should land on the one thing ranked most urgent, without a single
   scroll or click. Opacity/box-shadow only, no layout-affecting property,
   so it can't cause jitter. */
@media (prefers-reduced-motion: no-preference){
    .landingRankBadge.rank-1{
        animation: rankOnePulse 2.6s ease-in-out infinite;
    }

    @keyframes rankOnePulse{
        0%, 100%{ box-shadow: 0 0 0 0 rgba(255, 107, 107, 0.45); }
        50%{ box-shadow: 0 0 0 6px rgba(255, 107, 107, 0); }
    }
}

.landingRankBadge.rank-2{
    background: linear-gradient(135deg, #ffd08a, var(--color-warning));
    color: #3a2400;
}

.landingRankBadge.rank-3{
    background: linear-gradient(135deg, var(--violet-accent), var(--violet-accent-2));
    color: #120b30;
}

.landingBenefits{
    position: relative;
    z-index: 1;
    padding: var(--space-8) clamp(var(--space-5), 6vw, var(--space-9));
}

/* Frames the four cards inside one large dark panel (consulting.com's
   product-tier layout) instead of four cards floating loose on the page -
   a thin accent "tab" centered at the top edge and a faint dot-texture
   give the section a designed edge, same "editorial" DNA as the body's
   own grain layer. */
.landingBenefitsPanel{
    position: relative;
    max-width: 1180px;
    margin: 0 auto;
    padding: var(--space-9) clamp(var(--space-5), 6vw, var(--space-8)) var(--space-8);
    border-radius: var(--radius-lg);
    border: 1px solid var(--card-border);
    background: linear-gradient(165deg, var(--card-1), var(--card-3));
    box-shadow: var(--card-shadow);
    overflow: hidden;
}

.landingBenefitsPanelTab{
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 120px;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--violet-accent), transparent);
}

.landingBenefitsPanel::before{
    content: '';
    position: absolute;
    inset: 0;
    background-image: radial-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1.5px);
    background-size: 22px 22px;
    pointer-events: none;
}

.landingBenefitsGrid{
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--space-5);
}

.landingBenefitCard{
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: var(--space-7) var(--space-5) var(--space-6);
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid var(--violet-border-soft);
    overflow: hidden;
}

/* Short accent line at the corner, not a full-width border - the detail
   that makes a card read as deliberately designed rather than just a
   bordered box. */
.landingBenefitCard::before{
    content: '';
    position: absolute;
    top: 0;
    left: var(--space-5);
    width: 28px;
    height: 2px;
    background: var(--violet-accent);
}

/* Soft corner glow, same technique as .landingMockWrap's. */
.landingBenefitCard::after{
    content: '';
    position: absolute;
    top: -30%;
    right: -30%;
    width: 70%;
    height: 70%;
    background: radial-gradient(circle, rgba(181, 139, 255, 0.14), transparent 70%);
    pointer-events: none;
}

.landingBenefitIcon{
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: 50%;
    border: 1px solid var(--violet-border);
    background: rgba(181, 139, 255, 0.08);
    color: var(--violet-accent);
    font-size: var(--text-lg);
    margin-bottom: var(--space-5);
}

.landingBenefitTitle{
    position: relative;
    z-index: 1;
    font-size: var(--text-md);
    font-weight: 800;
    color: var(--violet-text);
    margin: 0 0 var(--space-2);
}

.landingBenefitText{
    position: relative;
    z-index: 1;
    font-size: var(--text-sm);
    line-height: 1.6;
    color: var(--violet-muted);
    margin: 0;
}

.landingSectionTitle{
    text-align: center;
    font-family: 'Playfair Display', serif;
    font-weight: 700;
    font-size: var(--text-xl);
    color: var(--violet-text);
    margin: 0 0 var(--space-7);
}

.landingHow{
    position: relative;
    z-index: 1;
    max-width: 1080px;
    margin: 0 auto;
    padding: var(--space-9) clamp(var(--space-5), 6vw, var(--space-9));
}

/* A connecting line through the row of number badges, not boxed cards -
   deliberately a different visual device than .landingBenefitCard so the
   page doesn't read as the same card repeated in every section. Ties the
   three steps together as one continuous process instead. */
.landingHowSteps{
    position: relative;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--space-6);
}

.landingHowSteps::before{
    content: '';
    position: absolute;
    top: 18px;
    left: 8%;
    right: 8%;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--violet-border) 15%, var(--violet-border) 85%, transparent);
    z-index: 0;
}

.landingHowStep{
    position: relative;
    z-index: 1;
    text-align: center;
}

.landingHowNumber{
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-circle);
    background: linear-gradient(135deg, var(--violet-accent), var(--violet-accent-2));
    color: #120b30;
    font-weight: 800;
    font-size: var(--text-md);
    /* The connecting line above passes right through this circle's vertical
       center - the circle's own solid fill naturally occludes it, which is
       what makes it read as "dots on a line" instead of a line crossing
       through empty text. */
    box-shadow: 0 0 0 6px var(--violet-bg-2);
    margin-bottom: var(--space-4);
}

.landingHowTitle{
    position: relative;
    z-index: 1;
    font-size: var(--text-md);
    font-weight: 800;
    color: var(--violet-text);
    margin: 0 0 var(--space-2);
}

.landingHowText{
    position: relative;
    z-index: 1;
    font-size: var(--text-sm);
    line-height: 1.6;
    color: var(--violet-muted);
    margin: 0;
}

.landingFounderNote{
    position: relative;
    z-index: 1;
    max-width: 720px;
    margin: 0 auto;
    padding: var(--space-7) clamp(var(--space-5), 6vw, var(--space-9));
    text-align: center;
}

.landingFounderText{
    font-size: var(--text-md);
    line-height: 1.6;
    font-style: italic;
    color: var(--violet-text);
    margin: 0 0 var(--space-3);
}

.landingFounderSign{
    font-size: var(--text-sm);
    color: var(--violet-muted);
    margin: 0;
}

.landingFaq{
    position: relative;
    z-index: 1;
    max-width: 760px;
    margin: 0 auto;
    padding: var(--space-8) clamp(var(--space-5), 6vw, var(--space-9));
}

.landingFaqEyebrow{
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    font-size: var(--text-xs);
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--violet-accent);
}

.landingFaqEyebrowLine{
    width: 40px;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--violet-border));
}

.landingFaqEyebrowLine + span + .landingFaqEyebrowLine{
    background: linear-gradient(90deg, var(--violet-border), transparent);
}

.landingFaq .landingSectionTitle{
    margin-bottom: var(--space-3);
}

.landingFaqAccent{
    color: var(--violet-accent);
}

.landingFaqSubtitle{
    text-align: center;
    font-size: var(--text-sm);
    color: var(--violet-muted);
    max-width: 460px;
    margin: 0 auto var(--space-7);
    line-height: 1.6;
}

/* <details>/<summary> instead of always-expanded text: direct feedback was
   that the FAQ read as "way too much to read" up front. A native accordion
   needs zero JS (keyboard/screen-reader behavior comes for free from the
   browser) and means only the questions themselves are visible until a
   visitor actually wants an answer - Hick's Law applied to reading, not
   just clicking. Each question is now its own boxed pill (not a plain
   divider-separated list) - a third distinct "container" language from
   the benefit cards and the how-it-works timeline, so no two sections on
   the page end up looking like the same component reused. */
.landingFaqItem{
    border: 1px solid var(--violet-border-soft);
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.025);
    padding: 0 var(--space-5);
    margin-bottom: var(--space-3);
    transition: border-color 0.2s ease, background 0.2s ease;
}

.landingFaqItem:last-child{
    margin-bottom: 0;
}

.landingFaqItem:hover{
    border-color: var(--violet-border);
    background: rgba(255, 255, 255, 0.04);
}

.landingFaqItem[open]{
    border-color: var(--violet-accent);
}

.landingFaqQuestion{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    list-style: none;
    cursor: pointer;
    padding: var(--space-4) 0;
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--violet-text);
    transition: color 0.2s ease;
}

.landingFaqQuestion::-webkit-details-marker{
    display: none;
}

.landingFaqQuestion::marker{
    content: '';
}

.landingFaqItem:hover .landingFaqQuestion{
    color: var(--violet-accent);
}

.landingFaqChevron{
    flex: 0 0 auto;
    font-size: var(--text-sm);
    color: var(--violet-muted);
    transition: transform 0.25s ease, color 0.2s ease;
}

.landingFaqItem[open] .landingFaqQuestion{
    color: var(--violet-accent);
}

.landingFaqItem[open] .landingFaqChevron{
    transform: rotate(180deg);
    color: var(--violet-accent);
}

.landingFaqAnswer{
    font-size: var(--text-sm);
    line-height: 1.55;
    color: var(--violet-muted);
    margin: 0;
    padding: 0 0 var(--space-4);
}

.landingFaqAnswer a{
    color: var(--violet-accent);
}

.landingFaqAnswer a:hover{
    color: var(--violet-text);
}

/* Matches the .editorCancelBtn/.editorSaveBtn:focus-visible ring
   established elsewhere - every new interactive element on this page gets
   the same visible keyboard-focus signal as the rest of the app, not just
   whatever the browser default happens to be. */
.landingCtaBtn:focus-visible,
.landingSignInLink:focus-visible,
.landingSecondaryLink:focus-visible,
.landingFooterLinks a:focus-visible,
.landingFaqQuestion:focus-visible,
.landingFaqAnswer a:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(181, 139, 255, 0.4);
    border-radius: var(--radius-sm);
}

/* Serial Position Effect: the same CTA, same wording, repeated here - top
   and bottom are what's remembered best. */
.landingFinalCta{
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-6);
    max-width: 640px;
    margin: 0 auto;
    padding: var(--space-9) clamp(var(--space-5), 6vw, var(--space-9));
    text-align: center;
}

.landingFinalCtaTitle{
    font-family: 'Playfair Display', serif;
    font-weight: 700;
    font-size: clamp(24px, 4vw, 32px);
    color: var(--violet-text);
    margin: 0;
}

.landingFooter{
    position: relative;
    z-index: 1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-5);
    padding: var(--space-6) var(--space-5);
    border-top: 1px solid var(--violet-border-soft);
}

.landingFooterLinks{
    display: flex;
    gap: var(--space-5);
}

.landingFooterLinks a{
    font-size: var(--text-sm);
    color: var(--violet-muted);
    text-decoration: none;
}

.landingFooterLinks a:hover{
    color: var(--violet-text);
}

.landingFooterCopy{
    font-size: var(--text-xs);
    color: var(--violet-muted);
    opacity: 0.7;
    margin: 0;
    width: 100%;
    text-align: center;
}

@media (max-width: 640px){
    .landingHeader{
        padding: var(--space-4);
    }

    .landingHero{
        flex-direction: column;
        text-align: center;
        padding-top: var(--space-6);
    }

    .landingCtaRow{
        justify-content: center;
    }

    .landingMockWrap{
        width: 100%;
    }
}

/* Scroll-reveal for everything below the fold (JS toggles .isVisible via
   IntersectionObserver, index.html). Default state here is plain visible -
   the animated state only exists inside prefers-reduced-motion:no-preference,
   so a visitor with reduced motion on, or a browser where the observer script
   fails to run, still just sees the content normally instead of it getting
   stuck invisible. Motion is a progressive enhancement on top of that, never
   a requirement to see the page. */
@media (prefers-reduced-motion: no-preference){
    .scrollReveal{
        opacity: 0;
        transform: translateY(26px);
        transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
    }

    .scrollReveal.isVisible{
        opacity: 1;
        transform: translateY(0);
    }

    /* Staggered reveal within each grid/list - Serial Position Effect reads
       better when items visibly arrive in the order they're listed, not
       all at once. */
    .landingBenefitCard:nth-child(2){ transition-delay: 0.08s; }
    .landingBenefitCard:nth-child(3){ transition-delay: 0.16s; }
    .landingBenefitCard:nth-child(4){ transition-delay: 0.24s; }

    .landingHowStep:nth-child(2){ transition-delay: 0.1s; }
    .landingHowStep:nth-child(3){ transition-delay: 0.2s; }

    /* nth-of-type, not nth-child: the section heading above these is a
       sibling too, and it's a different tag - nth-of-type counts only
       among same-tag (<details>) siblings, so it still lines up with
       each FAQ item's actual list position. */
    .landingFaqItem:nth-of-type(2){ transition-delay: 0.06s; }
    .landingFaqItem:nth-of-type(3){ transition-delay: 0.12s; }
    .landingFaqItem:nth-of-type(4){ transition-delay: 0.18s; }
}

/* ===================================================================
   Landing page: cinematic motion pass. Layered on top of the block
   above rather than editing it in place, so the original hero/benefit
   rules stay intact and this reads as one clearly-scoped addition (see
   index.html's own closing script tag for the pointer-driven JS half:
   tilt on the hero mock card and benefit cards, parallax on the float
   cards, a cursor-tracked spotlight). Static positioning/sizing rules
   here apply unconditionally; anything that actually moves is gated
   behind prefers-reduced-motion, same convention as the rest of this
   file, so a reduced-motion visitor gets the same layout, fully still.
   =================================================================== */

.landingMockStage{
    position: relative;
    flex: 1 1 380px;
    max-width: 460px;
    perspective: 1400px;
    --spotX: 62%;
    --spotY: 30%;
}

/* Cursor-tracked spotlight - the "light source" that makes the tilt
   below actually read as lit from somewhere instead of just rotated
   flat art. The fixed position set above is what shows when JS never
   touches the vars (no pointer, reduced motion, JS disabled), so this
   is never literally invisible, just static. */
.landingMockStage::before{
    content: '';
    position: absolute;
    inset: -18%;
    z-index: -1;
    background: radial-gradient(circle at var(--spotX) var(--spotY), rgba(181, 139, 255, 0.24), rgba(0, 0, 0, 0) 58%);
    pointer-events: none;
}

.landingMockWrap{
    --tiltX: 0deg;
    --tiltY: 0deg;
    transform: rotateX(var(--tiltX)) rotateY(var(--tiltY));
    transform-style: preserve-3d;
}

/* A second, blurred, offset copy of the card sitting behind it in real
   3D space (translateZ, not just a flat box-shadow) - the actual trick
   that sells depth here. Needs the stage's own perspective above to
   read as "behind," not just "underneath." */
.landingMockWrap::after{
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    background: var(--violet-surface-soft);
    border: 1px solid var(--violet-border-soft);
    transform: translateZ(-46px) translateY(16px) scale(0.94);
    opacity: 0.55;
    pointer-events: none;
}

@media (prefers-reduced-motion: no-preference){
    .landingMockWrap{
        transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
    }
}

.landingFloatCard{
    position: absolute;
    z-index: 2;
    --parX: 0px;
    --parY: 0px;
    transform: translate3d(var(--parX), var(--parY), 70px);
    pointer-events: none;
}

.landingFloatCard--streak{ top: -20px; right: -16px; }
.landingFloatCard--dusty{ bottom: -18px; left: -22px; }

@media (prefers-reduced-motion: no-preference){
    .landingFloatCard{
        transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
    }
}

.landingFloatCardInner{
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background: var(--violet-surface-soft);
    border: 1px solid var(--violet-border-soft);
    box-shadow: 0 18px 40px rgba(5, 2, 30, 0.42);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    white-space: nowrap;
}

.landingFloatIcon{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    flex: 0 0 auto;
    font-size: var(--text-sm);
}

.landingFloatIconFire{
    background: linear-gradient(135deg, #ffd08a, var(--color-warning));
    color: #3a2400;
}

.landingFloatIconDusty{
    background: linear-gradient(135deg, var(--violet-accent), var(--violet-accent-2));
    color: #120b30;
}

.landingFloatText{
    display: flex;
    flex-direction: column;
    font-size: var(--text-xs);
    line-height: 1.4;
    color: var(--violet-muted);
}

.landingFloatText strong{
    font-size: var(--text-sm);
    color: var(--violet-text);
}

@media (prefers-reduced-motion: no-preference){
    .landingFloatCard--streak .landingFloatCardInner{ animation: landingFloatBob 5.5s ease-in-out infinite; }
    .landingFloatCard--dusty .landingFloatCardInner{ animation: landingFloatBob 6.5s ease-in-out infinite 0.7s; }

    @keyframes landingFloatBob{
        0%, 100%{ transform: translateY(0); }
        50%{ transform: translateY(-9px); }
    }
}

/* Too tight below ~880px for two overhanging annotation cards plus a
   full-width mock card without real overlap risk - the hero already
   stacks to one column at 640px (see below), so the float cards step
   aside rather than fight the layout for space in between. */
@media (max-width: 880px){
    .landingFloatCard{ display: none; }
}

@media (max-width: 640px){
    .landingMockStage{
        width: 100%;
        max-width: none;
    }
}

/* Benefit-card hover tilt - same var-driven transform pattern as the
   hero card above, much smaller amplitude since these are secondary
   content, not the hero focal point. Set by index.html's own
   pointermove handler; the 0deg default here means a card with JS
   disabled, or before the first pointermove, is simply flat - never
   stuck mid-tilt. */
.landingBenefitCard{
    --tiltX: 0deg;
    --tiltY: 0deg;
    transform: perspective(900px) rotateX(var(--tiltX)) rotateY(var(--tiltY));
}

@media (prefers-reduced-motion: no-preference){
    .landingBenefitCard{
        transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.2s ease;
    }

    .landingBenefitCard:hover{
        border-color: var(--violet-border);
    }

    .landingBenefitIcon{
        transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
    }

    .landingBenefitCard:hover .landingBenefitIcon{
        transform: scale(1.08) translateY(-2px);
    }
}

/* Scroll-reveal upgrade: the original plain fade+slide (rule earlier in
   this file, untouched) now also rotates in from a slight 3D tilt
   rather than a flat translateY - the same "entering from depth"
   language as the hero above, so the rest of the page doesn't feel
   like a completely different, flatter design once you scroll past it.
   Only overrides the `transform` value itself; the original rule's
   opacity/transition declarations still apply since they're not
   redeclared here. */
@media (prefers-reduced-motion: no-preference){
    .scrollReveal{
        transform: translateY(26px) rotateX(6deg);
        transform-origin: bottom center;
    }

    .scrollReveal.isVisible{
        transform: translateY(0) rotateX(0deg);
    }
}

/* ===========================================================================
   Group Availability scheduling - see availability-plan.md. Deliberately
   built from the same card/token language as .groupHistoryPanel and
   .calendarGrid rather than inventing a new visual style for this feature -
   same border/gradient/radius recipe, same violet accent for "selected"
   state that .calendarDayCell.today already uses.
   =========================================================================== */

.availabilityPanel{
    margin-top: var(--space-4);
    border-radius: var(--radius-lg);
    border: 1px solid var(--card-border);
    border-top: 2px solid var(--card-top-accent);
    background: linear-gradient(165deg, var(--card-1), var(--card-3));
    box-shadow: var(--card-shadow);
    padding: 16px;
}

.availabilityHeader{
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.availabilityPanelTitle{
    margin: 0;
    font-size: var(--text-md);
    font-weight: 800;
    color: #f6f2ff;
}

.availabilityTimezoneRow{
    margin: 0;
    font-size: var(--text-sm);
    color: var(--violet-muted);
}

.availabilityTimezoneRow strong{
    color: var(--violet-text);
}

.availabilityChangeTimezoneBtn{
    background: none;
    border: none;
    color: var(--violet-accent-2);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    padding: 0 0 0 4px;
    text-decoration: underline;
}

/* Sub-tabs inside the Availability tab (My availability / Team overlap /
   Best times). A compact segmented control rather than another row of big
   pills, so it reads as a level BELOW the top-level .viewTab row instead of
   competing with it. Not .viewTab itself - switchGroupView queries every
   .viewTab on the page. */
.availabilitySubTabs{
    display: inline-flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 4px;
    margin: 0 0 var(--space-3);
    border-radius: var(--radius-pill);
    border: 1px solid var(--violet-border);
    background: rgba(255, 255, 255, 0.045);
}

.availabilitySubTab{
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    border: none;
    background: transparent;
    color: var(--violet-muted);
    font-size: var(--text-sm);
    font-weight: 700;
    padding: 6px 14px;
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.availabilitySubTab:hover{
    color: var(--violet-text);
    background: rgba(181, 139, 255, 0.12);
}

/* This stylesheet has no global .hidden rule - every component declares its
   own (.viewPanel.hidden, .groupDashboard.hidden ...) - so each availability
   container that JS toggles `hidden` on needs one here, or the class is a
   no-op and all three sub-views show at once. */
.availabilitySubPanel.hidden,
.availabilityGridWrap.hidden,
.availabilityHeatmapWrap.hidden,
.availabilityRecommendPanel.hidden{
    display: none;
}

.availabilityTouchHint{
    display: none;
    margin: 0 0 var(--space-2);
    font-size: var(--text-xs);
    color: var(--violet-muted);
}

@media (pointer: coarse){
    .availabilityTouchHint{
        display: block;
    }
}

.availabilitySubTab:focus-visible{
    outline: 2px solid var(--violet-accent);
    outline-offset: 1px;
}

.availabilitySubTab.active{
    background: linear-gradient(120deg, rgba(193, 152, 255, 0.95), rgba(132, 140, 255, 0.95));
    color: #fdfcff;
}

@media (max-width: 640px){
    .availabilitySubTabs{
        display: flex;
        width: 100%;
    }

    .availabilitySubTab{
        flex: 1;
        justify-content: center;
        padding: 6px 8px;
        font-size: var(--text-xs);
    }
}

.availabilityBrushRow{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.availabilityBrushBtn{
    border: 1px solid var(--violet-border);
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.045);
    color: var(--violet-muted);
    font-size: var(--text-sm);
    font-weight: 600;
    padding: 6px 14px;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.availabilityBrushBtn:hover{
    border-color: var(--violet-accent);
}

/* Each brush's active state borrows the exact color it paints, so the
   active brush button doubles as a legend for what that color means on the
   grid below - no separate legend needed. */
.availabilityBrushBtn.active[data-brush="free"]{
    background: rgba(63, 174, 106, 0.22);
    border-color: #3fae6a;
    color: #baf0cf;
}

.availabilityBrushBtn.active[data-brush="busy"]{
    background: rgba(217, 83, 79, 0.2);
    border-color: #d9534f;
    color: #f5c6c4;
}

.availabilityBrushBtn.active[data-brush="ifNeeded"]{
    background: rgba(230, 179, 66, 0.2);
    border-color: #e6b342;
    color: #f5deac;
}

.availabilitySaveStatus{
    margin-left: auto;
    font-size: var(--text-xs);
    color: var(--violet-muted);
}

/* "Apply to: Every week | This day only" (setAvailabilityApplyScope in
   group.js). Smaller than the Week | Day pill since it's a secondary
   setting most people never touch. */
.availabilityApplyRow{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.availabilityApplyLabel{
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--violet-muted);
}

.availabilityApplyToggle{
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--violet-border);
    background: rgba(255, 255, 255, 0.045);
}

.availabilityApplyBtn{
    border: none;
    background: transparent;
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 700;
    padding: 4px 11px;
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.availabilityApplyBtn:hover{
    color: #fdfcff;
}

.availabilityApplyBtn i{
    margin-right: 2px;
}

.availabilityApplyBtn.active{
    background: rgba(193, 152, 255, 0.28);
    color: #fdfcff;
}

/* Date mode gets its own sky-blue accent, shared with the grid's dashed
   border below, so the active one-off scope is unmistakable and reads as a
   different kind of control from the violet Week | Day pill. */
.availabilityApplyBtn.active[data-apply-scope="date"]{
    background: rgba(94, 200, 230, 0.22);
    color: #c8f0fb;
    box-shadow: inset 0 0 0 1px #5ec8e6;
}

/* Grid-level cue while painting one-off exceptions. Dashed and sky blue so
   it can't be confused with the solid violet .painting outline, which is
   declared later and wins border-color for the length of a stroke. */
.availabilityGridWrap.dateScope .availabilityGridScroll{
    border: 2px dashed #5ec8e6;
}

.availabilityApplyBtn:focus-visible{
    outline: 2px solid var(--violet-accent);
    outline-offset: 2px;
}

/* "Reset to weekly" chips (renderAvailabilityOverrideResets in group.js).
   Own full-width line after the hint, so the list of active exceptions
   reads as separate from the setting above it. Empty most of the time, so
   the whole row just collapses. */
.availabilityResetRow{
    flex-basis: 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.availabilityResetRow:has(> .availabilityResetList:empty){
    display: none;
}

.availabilityResetLabel{
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--violet-muted);
}

.availabilityResetList{
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.availabilityResetBtn{
    min-height: 32px;
    border: 1px dashed var(--violet-border);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 700;
    padding: 4px 12px;
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease;
}

.availabilityResetBtn:hover{
    border-color: var(--violet-accent);
    color: #fdfcff;
}

.availabilityResetBtn:focus-visible{
    outline: 2px solid var(--violet-accent);
    outline-offset: 2px;
}

.availabilityApplyHint{
    flex-basis: 100%;
    margin: 0;
    font-size: var(--text-xs);
    color: var(--violet-muted);
}

/* Touch targets: same (pointer: coarse) gate as .availabilityTouchHint. */
@media (pointer: coarse){
    .availabilityApplyBtn{
        min-height: 40px;
        padding: 6px 14px;
    }

    .availabilityResetBtn{
        min-height: 44px;
        padding: 6px 14px;
    }
}

/* Group heatmap (Phase 4): same column template as .availabilityGrid below
   so it lines up with your own paint grid column-for-column, and it reuses
   the Activity heatmap's .heatCell level-0..4 violet ramp - here the level
   is "share of members free", not "tasks completed". Header/time-label
   cells reuse the paint grid's own .availabilityGrid* classes. */
.availabilityHeatmapWrap{
    margin-top: var(--space-4);
}

.availabilityHeatmapTitle{
    margin: 0 0 var(--space-2);
    font-size: var(--text-sm);
    font-weight: 800;
    color: #f6f2ff;
}

.availabilityHeatmapLegend{
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 5px;
    margin-bottom: var(--space-2);
    font-size: var(--text-2xs);
    color: var(--violet-muted);
}

.availabilityHeatmapLegend .availabilityHeatmapSwatch{
    width: 14px;
    height: 14px;
    flex: 0 0 14px;
    display: inline-block;
}

.availabilityHeatmapGrid{
    display: grid;
    grid-template-columns: 64px repeat(7, minmax(56px, 1fr));
    min-width: 480px;
}

.availabilityHeatmapCell{
    height: 20px;
    margin: 0;
    padding: 0;
    border-radius: 0;
    border-color: rgba(28, 23, 48, 0.55);
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    touch-action: pan-y;
}

.availabilityHeatmapCell.hourStart{
    border-top-color: rgba(28, 23, 48, 0.9);
}

/* Same level-0..4 classes as the Activity heatmap, but that ramp is tuned
   for small squares where every level is a pale-to-deep lavender - on this
   dark panel levels 0-2 read as the same color, and "nobody free" looked
   like something was there. Here level-0 recedes into the panel and each
   step up is clearly stronger. */
.availabilityHeatmapCell.level-0,
.availabilityHeatmapSwatch.level-0{ background: rgba(255, 255, 255, 0.04); }
.availabilityHeatmapCell.level-1,
.availabilityHeatmapSwatch.level-1{ background: rgba(145, 102, 232, 0.28); }
.availabilityHeatmapCell.level-2,
.availabilityHeatmapSwatch.level-2{ background: rgba(145, 102, 232, 0.5); }
.availabilityHeatmapCell.level-3,
.availabilityHeatmapSwatch.level-3{ background: rgba(145, 102, 232, 0.75); }
.availabilityHeatmapCell.level-4,
.availabilityHeatmapSwatch.level-4{ background: rgba(168, 128, 255, 1); }

/* Outside at least one member's usual hours (the group's view window, in
   their own zone): not free, not busy - muted and hatched so it never reads
   as a good time. Must come after the level rules, whose background
   shorthand would otherwise reset this background-image. */
.availabilityHeatmapCell.outsideHours,
.availabilityHeatmapSwatch.outsideHours{
    background-image: repeating-linear-gradient(135deg, rgba(10, 8, 20, 0.55) 0 2px, transparent 2px 5px);
    opacity: 0.55;
}

.availabilityHeatmapCell:hover,
.availabilityHeatmapCell:focus-visible{
    outline: 2px solid var(--violet-accent);
    outline-offset: -2px;
}

.availabilityHeatmapDetail,
.availabilityHeatmapNote{
    margin: var(--space-2) 0 0;
    font-size: var(--text-xs);
    line-height: 1.5;
    color: var(--violet-muted);
}

.availabilityHeatmapDetail{
    min-height: 1.5em;
    color: var(--violet-text);
}

@media (max-width: 640px){
    .availabilityHeatmapGrid{
        grid-template-columns: 48px repeat(7, minmax(36px, 1fr));
    }
}

/* The grid itself: 1 time-label column + 7 day columns, header row sticky
   so day names stay visible while scrolling a tall grid vertically -
   default 7am-11pm at 30-min rows is 32 rows, comfortably taller than one
   screen, same reasoning .groupHistoryList caps/scrolls internally for a
   long history instead of growing the whole page. */
.availabilityGridScroll{
    max-height: 560px;
    overflow-y: auto;
    overflow-x: auto;
    border-radius: var(--radius-md);
    border: 1px solid var(--violet-border);
}

.availabilityGrid{
    display: grid;
    grid-template-columns: 64px repeat(7, minmax(56px, 1fr));
    min-width: 480px;
}

.availabilityGridCorner,
.availabilityGridDayHeader{
    position: sticky;
    top: 0;
    z-index: 2;
    background: #1c1730;
    border-bottom: 1px solid var(--violet-border);
    padding: 6px 4px;
    text-align: center;
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--violet-muted);
}

.availabilityGridCorner{
    left: 0;
    z-index: 3;
}

.availabilityGridDayHeader{
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
}

/* The real calendar date for "this week" - purely a display aid so the
   grid visibly reads as a live, currently-rolling week rather than a
   one-time form (the grid rebuilds when the day changes, see
   getAvailabilityGridRangeKey in group.js, so this stays current as real
   days pass). Deliberately lighter/smaller than the
   day-name line above it - the day name is the actual recurring-template
   identity (what this feature is really keyed on), the date is context. */
.availabilityGridDateLabel{
    font-size: 10px;
    font-weight: 500;
    color: var(--violet-muted);
    opacity: 0.75;
}

.availabilityGridTimeLabel{
    position: sticky;
    left: 0;
    z-index: 1;
    background: #1c1730;
    border-right: 1px solid var(--violet-border);
    padding: 2px 6px;
    font-size: var(--text-2xs);
    color: var(--violet-muted);
    display: flex;
    align-items: center;
    justify-content: flex-end;
    white-space: nowrap;
}

/* Only every other (on-the-hour) row gets a visible label - a label on
   every 30-min row made the column read as a wall of tiny text; the
   half-hour rows are still identifiable by position between two labeled
   hours, same convention clock UIs generally use. */
.availabilityGridTimeLabel.halfHour{
    color: transparent;
}

.availabilityGridCell{
    height: 20px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
    border-right: 1px solid rgba(255, 255, 255, 0.05);
    background: rgba(217, 83, 79, 0.12);
    cursor: pointer;
    /* Cells keep native scrolling in both directions (the grid scrolls
       sideways on a phone too) - a permanently-none grid would trap page
       scroll on a phone. Touch painting is tap, or press-and-hold then drag;
       see attachAvailabilityGridPointerEvents in group.js for why toggling
       touch-action per stroke can't work for touch. */
    touch-action: pan-x pan-y;
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

/* .penReady: a hovering pen, set before contact so the pen can stroke
   straight away. .painting: a stroke is live (for touch, after the hold
   armed it), which also gets the outline below as the visible cue that
   dragging now paints instead of scrolling. */
.availabilityGrid.penReady .availabilityGridCell,
.availabilityGrid.painting .availabilityGridCell{
    touch-action: none;
}

/* On the scroll box, not the grid: the grid is taller than the box, so an
   outline on it would have its top/bottom edges scrolled out of sight. */
.availabilityGridScroll:has(> .availabilityGrid.painting){
    border-color: var(--violet-accent);
    box-shadow: 0 0 0 2px var(--violet-accent);
}

.availabilityGrid.painting .availabilityGridCell{
    cursor: crosshair;
}

.availabilityGridCell.hourStart{
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.availabilityGridCell.state-free{
    background: rgba(63, 174, 106, 0.55);
}

.availabilityGridCell.state-busy{
    background: rgba(217, 83, 79, 0.12);
}

.availabilityGridCell.state-ifNeeded{
    background: rgba(230, 179, 66, 0.55);
}

.availabilityGridCell:hover{
    outline: 2px solid var(--violet-accent);
    outline-offset: -2px;
}

/* A one-off date exception rather than the weekly pattern (own grid only,
   see applyAvailabilityCellVisual in group.js). A small white corner tick
   layered over the state color, so free/busy/if-needed still reads first. */
.availabilityGridCell.hasOverride{
    background-image: linear-gradient(225deg, rgba(255, 255, 255, 0.85) 0 5px, transparent 5px);
}

@media (max-width: 640px){
    .availabilityGrid{
        grid-template-columns: 48px repeat(7, minmax(36px, 1fr));
    }

    .availabilityGridDayHeader{
        font-size: 10px;
    }
}

/* Week | Day toggle (applyAvailabilityGridLayout in group.js). Same pill
   look as .availabilitySubTabs, own classes so the sub-tab code never
   touches it. */
.availabilityDayToggleRow{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

/* The heatmap's copy of the toggle hides while the heatmap has no grid
   (nobody painted yet / not rendered yet). */
.availabilityDayToggleRow.hidden{
    display: none;
}

/* Your own grid failed to load after its automatic retries
   (fetchMyAvailability in group.js). */
.availabilityLoadError{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
    font-size: var(--text-sm);
    color: var(--violet-muted);
}

.availabilityLoadError.hidden{
    display: none;
}

.availabilityLoadError p{
    margin: 0;
}

.availabilityLoadRetryBtn{
    border: 1px solid var(--violet-border);
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.045);
    color: #fdfcff;
    font-weight: 700;
    padding: 5px 14px;
    cursor: pointer;
}

.availabilityLoadRetryBtn:hover{
    border-color: var(--violet-accent);
}

.availabilityLoadRetryBtn:focus-visible{
    outline: 2px solid var(--violet-accent);
    outline-offset: 2px;
}

.availabilityDayToggle{
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--violet-border);
    background: rgba(255, 255, 255, 0.045);
}

.availabilityDayToggleBtn{
    border: none;
    background: transparent;
    color: var(--violet-muted);
    font-size: var(--text-sm);
    font-weight: 700;
    padding: 5px 14px;
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.availabilityDayToggleBtn:hover{
    color: #fdfcff;
}

.availabilityDayToggleBtn.active{
    background: linear-gradient(120deg, rgba(193, 152, 255, 0.95), rgba(132, 140, 255, 0.95));
    color: #fdfcff;
}

.availabilityDayToggleBtn:focus-visible,
.availabilityDayNavBtn:focus-visible{
    outline: 2px solid var(--violet-accent);
    outline-offset: 2px;
}

.availabilityDayNav{
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.availabilityDayNav.hidden{
    display: none;
}

.availabilityDayNavBtn{
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--violet-border);
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.045);
    color: var(--violet-muted);
    cursor: pointer;
}

.availabilityDayNavBtn:hover:not(:disabled){
    color: #fdfcff;
    border-color: var(--violet-accent);
}

.availabilityDayNavBtn:disabled{
    opacity: 0.35;
    cursor: default;
}

.availabilityDayNavLabel{
    min-width: 9.5em;
    text-align: center;
    font-size: var(--text-sm);
    font-weight: 700;
    color: #fdfcff;
}

/* Day mode: time-label column plus ONE wide day column, done purely by
   hiding the other six columns' header and cells. Relies on the grid's
   child order, which both buildAvailabilityGridDomIfNeeded and the heatmap
   builder share: child 1 is the corner, 2-8 the day headers, then each row
   is 1 time label + 7 cells. So time labels (and the corner) are
   nth-child(8n+1) and day column c (0 = today) is nth-child(8n+c+2).
   display:none also means elementFromPoint can never hit a hidden cell. */
.availabilityGrid.dayMode,
.availabilityHeatmapGrid.dayMode{
    grid-template-columns: 64px minmax(0, 1fr);
    min-width: 0;
}

.availabilityGrid.dayMode[data-day-col="0"] > :not(:nth-child(8n+1)):not(:nth-child(8n+2)),
.availabilityGrid.dayMode[data-day-col="1"] > :not(:nth-child(8n+1)):not(:nth-child(8n+3)),
.availabilityGrid.dayMode[data-day-col="2"] > :not(:nth-child(8n+1)):not(:nth-child(8n+4)),
.availabilityGrid.dayMode[data-day-col="3"] > :not(:nth-child(8n+1)):not(:nth-child(8n+5)),
.availabilityGrid.dayMode[data-day-col="4"] > :not(:nth-child(8n+1)):not(:nth-child(8n+6)),
.availabilityGrid.dayMode[data-day-col="5"] > :not(:nth-child(8n+1)):not(:nth-child(8n+7)),
.availabilityGrid.dayMode[data-day-col="6"] > :not(:nth-child(8n+1)):not(:nth-child(8n+8)),
.availabilityHeatmapGrid.dayMode[data-day-col="0"] > :not(:nth-child(8n+1)):not(:nth-child(8n+2)),
.availabilityHeatmapGrid.dayMode[data-day-col="1"] > :not(:nth-child(8n+1)):not(:nth-child(8n+3)),
.availabilityHeatmapGrid.dayMode[data-day-col="2"] > :not(:nth-child(8n+1)):not(:nth-child(8n+4)),
.availabilityHeatmapGrid.dayMode[data-day-col="3"] > :not(:nth-child(8n+1)):not(:nth-child(8n+5)),
.availabilityHeatmapGrid.dayMode[data-day-col="4"] > :not(:nth-child(8n+1)):not(:nth-child(8n+6)),
.availabilityHeatmapGrid.dayMode[data-day-col="5"] > :not(:nth-child(8n+1)):not(:nth-child(8n+7)),
.availabilityHeatmapGrid.dayMode[data-day-col="6"] > :not(:nth-child(8n+1)):not(:nth-child(8n+8)){
    display: none;
}

.availabilityHeatmapGrid.dayMode .availabilityHeatmapCell{
    height: 28px;
}

/* One column has room for taller, easier-to-hit rows, which is what makes
   Day the friendlier layout on a phone. */
.availabilityGrid.dayMode .availabilityGridCell{
    height: 28px;
}

@media (max-width: 640px){
    .availabilityGrid.dayMode,
    .availabilityHeatmapGrid.dayMode{
        grid-template-columns: 48px minmax(0, 1fr);
    }

    .availabilityDayToggleBtn{
        padding: 5px 12px;
        font-size: var(--text-xs);
    }
}

/* "Best times to meet" (group.js renderAvailabilityRecommendations) - sits
   inside .availabilityPanel below the grid, so it borrows the panel's own
   type scale and the grid's free-green for "everyone can make it". Member
   names reuse the calendar's .calendarChipMemberDot colors. */
.availabilityRecommendPanel{
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--violet-border);
}

.availabilityRecommendHeader{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.availabilityRecommendTitle{
    margin: 0;
    font-size: var(--text-md);
    font-weight: 800;
    color: #f6f2ff;
}

.availabilityRecommendLengthLabel{
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--text-sm);
    color: var(--violet-muted);
}

.availabilityRecommendLengthSelect{
    color-scheme: dark;
    height: 32px;
    padding: 0 10px;
    border: none;
    outline: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.12);
    color: var(--violet-text);
    font-size: 13px;
    cursor: pointer;
}

.availabilityRecommendLengthSelect:focus-visible{
    outline: 2px solid var(--violet-accent);
    outline-offset: 2px;
}

.availabilityRecommendLengthSelect option{
    background: #1a1143;
    color: #f7f3ff;
    font-weight: 600;
}

.availabilityRecommendList{
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.availabilityRecommendItem{
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--violet-border);
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.04);
}

.availabilityRecommendItem.isEveryone{
    border-color: rgba(63, 174, 106, 0.55);
    background: rgba(63, 174, 106, 0.08);
}

.availabilityRecommendRank{
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.08);
    color: var(--violet-text);
    font-size: var(--text-xs);
    font-weight: 800;
}

.availabilityRecommendItem.isEveryone .availabilityRecommendRank{
    background: rgba(63, 174, 106, 0.3);
    color: #baf0cf;
}

.availabilityRecommendBody{
    min-width: 0;
}

.availabilityRecommendWhen{
    margin: 0;
    font-size: var(--text-sm);
    font-weight: 700;
    color: #f6f2ff;
}

.availabilityRecommendWhy{
    margin: 2px 0 0;
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--violet-muted);
}

.availabilityRecommendMember{
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--violet-text);
    font-weight: 600;
}

.availabilityRecommendEmpty{
    padding: 10px 12px;
    border: 1px dashed var(--violet-border);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    color: var(--violet-muted);
}

.availabilityRecommendNote{
    margin: var(--space-3) 0 0;
    font-size: var(--text-xs);
    line-height: 1.5;
    color: var(--violet-muted);
}




/* Group Settings: owner-only "Availability hours" view window (see
   renderAvailabilityHoursSetting in group/group.js). Mirrors the
   .groupSettingsPrivacySelect look so the modal reads as one set. */
.availabilityHoursSetting.hidden,
.groupSettingsRequestsSection.hidden{
    display: none;
}

.availabilityHoursSettingCurrent{
    margin: 0 0 6px;
    font-size: 12px;
    font-weight: 700;
    color: #f4efff;
}

.availabilityHoursSettingRow{
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 10px;
}

.availabilityHoursSettingLabel{
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1 1 110px;
    min-width: 0;
    font-size: 12px;
    font-weight: 700;
    color: #f4efff;
}

.availabilityHoursSettingSelect{
    width: 100%;
    height: 44px;
    padding: 0 10px;
    border: 2px solid rgba(185, 167, 255, 0.48);
    border-radius: 10px;
    outline: none;
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    color: #f7f3ff;
    color-scheme: dark;
    font-weight: 500;
}

.availabilityHoursSettingSelect:focus-visible{
    border-color: rgba(202, 167, 255, 0.95);
}

.availabilityHoursSettingSelect option{
    background: #1a1143;
    color: #f7f3ff;
    font-weight: 600;
}

.availabilityHoursSettingSaveBtn{
    flex: 0 0 auto;
    height: 44px;
    padding: 0 18px;
    border: none;
    border-radius: 10px;
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    color: #120b30;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}

.availabilityHoursSettingSaveBtn:hover:not(:disabled){
    filter: brightness(1.08);
}

.availabilityHoursSettingSaveBtn:disabled{
    opacity: 0.5;
    cursor: not-allowed;
}

.availabilityHoursSettingStatus{
    margin: 0;
    min-height: 1em;
    font-size: 11px;
    color: rgba(217, 206, 255, 0.72);
}

.availabilityHoursSettingStatus.isError{
    color: #ffb3b3;
}

/* ---- Task folders (organization-plan.md section 5.1) ----
   Chip bar + badge + manager dialog. Uses the violet tokens from :root; the
   per-folder color arrives as --folder-color set inline by folders.js. */
.detailsFolderPrimary.hidden{
    display: none;
}

.folderBar{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0 0 12px;
}

.folderChip{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--violet-border);
    background: var(--violet-surface-soft);
    color: var(--violet-muted);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
}

.folderChip:hover{
    border-color: var(--violet-accent);
}

.folderChip.active{
    background: linear-gradient(120deg, rgba(193, 152, 255, 0.98), rgba(132, 140, 255, 0.98));
    border-color: rgba(232, 225, 255, 0.8);
    color: #fdfcff;
}

.folderManageChip{
    border-style: dashed;
}

.folderChipCount{
    min-width: 18px;
    padding: 0 5px;
    border-radius: var(--radius-pill);
    background: rgba(0, 0, 0, 0.28);
    font-size: var(--text-xs);
    text-align: center;
}

.folderDot{
    width: 9px;
    height: 9px;
    border-radius: var(--radius-circle);
    background: var(--folder-color, var(--violet-accent));
    flex: none;
}

.folderBadge{
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--folder-color, var(--violet-border));
    background: rgba(181, 139, 255, 0.1);
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 600;
}

.folderManagerOverlay{
    position: fixed;
    inset: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-5, 20px);
    background: rgba(8, 5, 24, 0.6);
}

.folderManagerCard{
    width: min(420px, 95vw);
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    padding: 18px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--violet-border);
    background: var(--violet-surface);
    color: var(--violet-text);
    box-shadow: var(--card-shadow);
}

.folderManagerHeader{
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
}

.folderManagerHeader h2{
    margin: 0;
    font-size: var(--text-md);
}

.folderManagerCloseBtn,
.folderManagerAddBtn{
    padding: 7px 14px;
    border: 0;
    border-radius: 10px;
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    color: #120b30;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}

.folderManagerList{
    list-style: none;
    margin: 0 0 12px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.folderManagerEmpty{
    font-size: var(--text-sm);
    color: var(--violet-muted);
}

.folderManagerRow,
.folderManagerAddRow{
    display: flex;
    align-items: center;
    gap: 8px;
}

.folderColorBtn{
    width: 26px;
    height: 26px;
    flex: none;
    border-radius: var(--radius-circle);
    border: 2px solid rgba(255, 255, 255, 0.35);
    background: var(--folder-color);
    cursor: pointer;
}

.folderNameInput,
.folderManagerAddInput{
    flex: 1;
    min-width: 0;
    padding: 7px 10px;
    border-radius: 10px;
    border: 1px solid var(--violet-border);
    background: var(--violet-surface-soft);
    color: var(--violet-text);
    font-size: var(--text-base);
}

.folderDeleteBtn{
    flex: none;
    padding: 6px 8px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--color-danger);
    cursor: pointer;
}

.folderDeleteBtn:hover{
    background: var(--color-danger-soft);
}

.folderManagerError{
    margin: 10px 0 0;
    min-height: 1em;
    font-size: var(--text-sm);
    color: var(--color-danger);
}

/* ---- Quick-add chips, "/" menu, bulk folder sorter (organization-plan.md 5.3) ---- */
.inputContainer{
    position: relative;
}

.slashBtn{
    flex: none;
    width: 38px;
    height: 38px;
    border-radius: var(--radius-circle);
    border: 1px solid var(--violet-border);
    background: var(--violet-surface-soft);
    color: var(--violet-muted);
    font-size: 16px;
    font-weight: 700;
    cursor: pointer;
}

.slashBtn:hover{
    border-color: var(--violet-accent);
    color: var(--violet-text);
}

.slashMenu{
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 25;
    width: min(320px, 100%);
    margin: 0;
    padding: 6px;
    list-style: none;
    border-radius: var(--radius-md);
    border: 1px solid var(--violet-border);
    background: var(--violet-surface);
    box-shadow: var(--card-shadow);
}

.slashMenu[hidden]{
    display: none;
}

.slashItem{
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    color: var(--violet-text);
    font-size: var(--text-base);
    cursor: pointer;
}

.slashItem.active,
.slashItem:hover{
    background: rgba(181, 139, 255, 0.22);
}

.slashHint{
    margin-left: auto;
    color: var(--violet-muted);
    font-size: var(--text-xs);
}

.quickChips{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 8px 0 0;
}

.quickChips.empty{
    display: none;
}

.quickChip{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--violet-text);
}

.quickChip.applied{
    border: 1px solid var(--violet-border);
    background: rgba(181, 139, 255, 0.16);
}

.quickChip.suggest{
    border: 1px dashed var(--violet-accent);
    background: transparent;
    color: var(--violet-muted);
    cursor: pointer;
}

.quickChip.suggest:hover{
    background: rgba(181, 139, 255, 0.16);
    color: var(--violet-text);
}

.quickChipRemove{
    border: 0;
    padding: 0 2px;
    background: transparent;
    color: inherit;
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
}

.folderSortChip{
    border-color: var(--violet-accent);
    color: var(--violet-text);
}

.folderSorterCard{
    width: min(560px, 95vw);
}

.folderSorterBulk{
    margin-bottom: 10px;
    font-size: var(--text-sm);
    color: var(--violet-muted);
}

.folderSorterBulk select,
.folderSorterSelect{
    padding: 6px 8px;
    border-radius: 8px;
    border: 1px solid var(--violet-border);
    background: var(--violet-surface-soft);
    color: var(--violet-text);
    font-size: var(--text-sm);
}

.folderSorterBulk select{
    margin-left: 6px;
}

.folderSorterList{
    list-style: none;
    margin: 0 0 12px;
    padding: 0;
    max-height: 50vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.folderSorterRow{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 8px;
    border-radius: 8px;
    background: var(--violet-surface-soft);
}

.folderSorterRow.guessed{
    outline: 1px dashed var(--violet-accent);
}

.folderSorterText{
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--text-sm);
}

.folderSorterCount{
    font-size: var(--text-sm);
    color: var(--violet-muted);
}

.folderManagerAddBtn:disabled{
    opacity: 0.5;
    cursor: not-allowed;
}

/* ---- Folder UI polish ----
   The existing selects get their dark-violet look from several stacked rule
   layers keyed by class name, which the new elements aren't part of - so they
   fell back to the browser's plain grey. This restates the final look for the
   new selects in one place, and makes every new popup fully opaque (the
   translucent --violet-surface let the orange overdue banner bleed through the
   "/" menu). */
.folderSelect,
.editorFolderSelect,
.folderSorterSelect,
.folderSorterBulk select{
    color-scheme: dark;
    appearance: auto;
    -webkit-appearance: menulist;
    -moz-appearance: auto;
    border: 2px solid rgba(181, 139, 255, 0.4);
    border-radius: 12px;
    outline: none;
    background: linear-gradient(145deg, rgba(49, 34, 117, 0.95), rgba(32, 22, 86, 0.97));
    color: var(--violet-text, #f6f4ff);
    font-family: inherit;
    font-weight: 500;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.folderSelect,
.editorFolderSelect{
    width: 100%;
    height: 50px;
    padding: 0 12px;
    font-size: var(--text-md);
}

.folderSorterSelect,
.folderSorterBulk select{
    height: 36px;
    padding: 0 8px;
    font-size: var(--text-base);
}

.folderSelect:hover,
.editorFolderSelect:hover,
.folderSorterSelect:hover,
.folderSorterBulk select:hover{
    border-color: rgba(205, 194, 255, 0.62);
}

.folderSelect:focus-visible,
.editorFolderSelect:focus-visible,
.folderSorterSelect:focus-visible,
.folderSorterBulk select:focus-visible{
    border-color: var(--violet-accent);
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.32);
}

.folderSelect option,
.editorFolderSelect option,
.folderSorterSelect option,
.folderSorterBulk select option{
    background: #1a1143;
    color: #f7f3ff;
    font-weight: 600;
}

.slashMenu{
    background: linear-gradient(145deg, #2a1f66, #1a1143);
    border-color: rgba(181, 139, 255, 0.45);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.7);
}

.folderManagerCard{
    background: linear-gradient(145deg, #2a1f66, #1a1143);
    border-color: rgba(181, 139, 255, 0.4);
}

.folderManagerOverlay{
    background: rgba(8, 5, 24, 0.72);
    backdrop-filter: blur(3px);
}

.folderNameInput,
.folderManagerAddInput{
    border: 2px solid rgba(181, 139, 255, 0.4);
    background: rgba(18, 11, 48, 0.9);
    border-radius: 12px;
}

.folderNameInput:focus-visible,
.folderManagerAddInput:focus-visible{
    outline: none;
    border-color: var(--violet-accent);
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.32);
}

.folderSorterRow{
    background: rgba(18, 11, 48, 0.7);
    border: 1px solid rgba(181, 139, 255, 0.18);
}

.folderSorterList{
    scrollbar-color: rgba(181, 139, 255, 0.5) transparent;
    scrollbar-width: thin;
}

.slashBtn{
    background: linear-gradient(145deg, rgba(63, 46, 140, 0.94), rgba(36, 25, 95, 0.96));
}

/* Folder pickers are a secondary field: compact, not the full-height 50px of
   the primary priority/difficulty selects. */
.folderSelect,
.editorFolderSelect{
    height: 38px;
    padding: 0 10px;
    border-radius: 10px;
    border-width: 1px;
    font-size: var(--text-base);
}

/* No global .hidden in this stylesheet - the group folder bar and its label
   toggle it themselves (nothing to show a plain member until an admin adds
   the first folder). */
.folderBar.hidden,
.taskViewsLabel.hidden{
    display: none;
}

/* ---- Group roles + "Group by" sections (organization-plan.md 5.2) ---- */
.jobRoleTag{
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-left: 6px;
    padding: 1px 8px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--folder-color, var(--violet-border));
    background: rgba(181, 139, 255, 0.1);
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 600;
    vertical-align: middle;
}

.groupByControl{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    color: var(--violet-muted);
    font-size: var(--text-sm);
    font-weight: 600;
}

.groupBySelect{
    color-scheme: dark;
    height: 30px;
    padding: 0 8px;
    border-radius: 10px;
    border: 1px solid rgba(181, 139, 255, 0.4);
    background: linear-gradient(145deg, rgba(49, 34, 117, 0.95), rgba(32, 22, 86, 0.97));
    color: var(--violet-text);
    font-family: inherit;
    font-size: var(--text-sm);
    cursor: pointer;
}

.groupBySelect option{
    background: #1a1143;
    color: #f7f3ff;
}

.groupSectionHeading{
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin: 10px 0 2px;
    padding: 0 4px;
    list-style: none;
    color: var(--violet-text);
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: 0.3px;
    text-transform: uppercase;
}

.groupSectionCount{
    padding: 0 7px;
    border-radius: var(--radius-pill);
    background: rgba(181, 139, 255, 0.18);
    color: var(--violet-muted);
    font-size: var(--text-xs);
}

.rolesManagerCard{
    width: min(480px, 95vw);
}

.rolesHelp{
    margin: 0 0 12px;
    color: var(--violet-muted);
    font-size: var(--text-sm);
    line-height: 1.4;
}

.rolesSubheading{
    margin: 16px 0 8px;
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--violet-text);
}

.rolesMembers{
    max-height: 30vh;
    overflow-y: auto;
}

/* ---- Assign / decline / shared task cards (organization-plan.md 5.4, 5.5) ---- */
.detailsAssignPrimary.hidden{
    display: none;
}

.assignSelect{
    color-scheme: dark;
    appearance: auto;
    -webkit-appearance: menulist;
    -moz-appearance: auto;
    width: 100%;
    height: 38px;
    padding: 0 10px;
    border: 1px solid rgba(181, 139, 255, 0.4);
    border-radius: 10px;
    outline: none;
    background: linear-gradient(145deg, rgba(49, 34, 117, 0.95), rgba(32, 22, 86, 0.97));
    color: var(--violet-text, #f6f4ff);
    font-family: inherit;
    font-size: var(--text-base);
    font-weight: 500;
    cursor: pointer;
}

.assignSelect:hover{
    border-color: rgba(205, 194, 255, 0.62);
}

.assignSelect:focus-visible{
    border-color: var(--violet-accent);
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.32);
}

.assignSelect option{
    background: #1a1143;
    color: #f7f3ff;
    font-weight: 600;
}

.assignmentOutcomesPanel{
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 4px;
}

.assignmentOutcomesPanel.hidden{
    display: none;
}

.assignedBadge{
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--color-info, #7f86ff);
    background: var(--color-info-soft, rgba(127, 134, 255, 0.16));
    color: var(--violet-text);
    font-size: var(--text-xs);
    font-weight: 700;
}

/* Decline: same pill as Handoff/Snooze (label always visible, since "ban"
   alone isn't self-explanatory), amber so it reads as "give back" rather
   than the red destructive Delete next to it. */
.declineBtn{
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: auto;
    height: 30px;
    padding: 0 var(--space-3);
    background: var(--color-warning-soft);
    border: 1px solid var(--color-warning);
    border-radius: var(--radius-pill);
    cursor: pointer;
}

.declineBtn i,
.declineBtn .taskBtnLabel{
    color: var(--color-warning);
}

.declineBtn .taskBtnLabel{
    display: inline;
}

.declineBtn:hover{
    filter: brightness(1.12);
    transform: scale(1.05);
    transition: all 0.2s ease-in-out;
}

@media (max-width: 900px){
    .declineBtn{
        height: 42px;
    }
}

/* One card for a task several people share. */
.sharedTaskCard{
    list-style: none;
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px 16px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(181, 139, 255, 0.4);
    background: linear-gradient(145deg, rgba(49, 34, 117, 0.55), rgba(27, 18, 72, 0.7));
}

.sharedTaskHead{
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.sharedTaskTitle{
    margin: 0;
    min-width: 0;
    color: var(--violet-text);
    font-size: var(--text-md);
    font-weight: 700;
    overflow-wrap: anywhere;
}

.sharedTaskProgress{
    flex: none;
    padding: 2px 10px;
    border-radius: var(--radius-pill);
    background: rgba(181, 139, 255, 0.18);
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 700;
    white-space: nowrap;
}

.sharedTaskBy{
    margin: -6px 0 0;
    color: var(--violet-muted);
    font-size: var(--text-xs);
}

.sharedTaskChips{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.sharedTaskChip{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    padding: 3px 10px 3px 4px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--violet-border);
    background: rgba(18, 11, 48, 0.55);
    color: var(--violet-text);
    font-size: var(--text-xs);
    font-weight: 600;
}

.sharedTaskChip > span:nth-child(2){
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sharedTaskAvatar{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    flex: none;
    border-radius: var(--radius-circle);
    background: rgba(181, 139, 255, 0.28);
    font-size: 11px;
    font-weight: 800;
}

.sharedTaskState{
    flex: none;
    color: var(--violet-muted);
    font-weight: 700;
}

.sharedTaskChip.isDone{
    border-color: rgba(127, 224, 163, 0.5);
    background: rgba(127, 224, 163, 0.12);
}

.sharedTaskChip.isDone .sharedTaskState{
    color: #7fe0a3;
}

.sharedTaskChip.isDeclined{
    border-style: dashed;
    border-color: rgba(255, 159, 159, 0.5);
    opacity: 0.8;
}

.sharedTaskChip.isDeclined .sharedTaskState{
    color: #ff9f9f;
}

.sharedTaskInner{
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* ---- Final polish pass over all folder / role / quick-add / assign UI ---- */

/* Keyboard focus: every new control gets the same visible ring the app's
   other buttons use, instead of the browser default (or nothing). */
.folderChip:focus-visible,
.quickChip:focus-visible,
.quickChipRemove:focus-visible,
.slashBtn:focus-visible,
.folderColorBtn:focus-visible,
.folderDeleteBtn:focus-visible,
.folderManagerCloseBtn:focus-visible,
.folderManagerAddBtn:focus-visible,
.declineBtn:focus-visible,
.groupBySelect:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

.folderManagerAddBtn:hover:not(:disabled),
.folderManagerCloseBtn:hover{
    filter: brightness(1.08);
}

/* Long names must never stretch a chip past the row. */
.folderChip{
    max-width: 100%;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.folderChip > span:not(.folderDot):not(.folderChipCount){
    min-width: 0;
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.folderBadge > span:last-child{
    max-width: 16ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.folderBar{
    align-items: center;
}

.quickChip{
    max-width: 100%;
    transition: background 0.15s ease;
}

.slashItem{
    transition: background 0.1s ease;
}

.folderColorBtn{
    transition: transform 0.12s ease;
}

.folderColorBtn:hover{
    transform: scale(1.12);
}

.folderManagerList{
    max-height: 40vh;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: rgba(181, 139, 255, 0.5) transparent;
}

.folderManagerAddRow{
    margin-top: 4px;
}

.folderManagerAddBtn{
    flex: none;
}

.folderSorterCount{
    margin-left: auto;
}

/* Small screens: dialogs and rows give up side-by-side layouts. */
@media (max-width: 520px){
    .folderManagerOverlay{
        align-items: flex-end;
        padding: 0;
    }

    .folderManagerCard{
        width: 100%;
        max-height: 88vh;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    }

    .folderSorterRow{
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
    }

    .folderSorterText{
        white-space: normal;
    }

    .folderSorterSelect{
        width: 100%;
    }

    .slashMenu{
        width: 100%;
    }

    .groupByControl{
        margin-left: 0;
        width: 100%;
    }

    .sharedTaskHead{
        flex-direction: column;
        gap: 6px;
    }
}

@media (prefers-reduced-motion: reduce){
    .folderChip,
    .quickChip,
    .slashItem,
    .folderColorBtn,
    .declineBtn{
        transition: none;
    }
}

/* Dusty's review card: the Folder dropdown matches its sibling selects. */
.brainDumpTaskCardFolder{
    flex: 1 1 100px;
    height: 30px;
    padding: 0 6px;
    border: 1px solid rgba(185, 167, 255, 0.4);
    border-radius: 8px;
    background: linear-gradient(145deg, rgba(53, 39, 120, 0.95), rgba(35, 24, 92, 0.96));
    color: #f7f3ff;
    font-size: 11px;
    color-scheme: dark;
}

.brainDumpTaskCardFolder option{
    background: #1a1143;
    color: #f7f3ff;
}

/* ---- Roles & access dialog: per-person access rows ---- */
.rolesAccessRow{
    flex-wrap: wrap;
}

.rolesAccessRow .folderSorterText{
    flex: 1 1 120px;
}

.rolesFullAccess{
    flex: none;
    padding: 2px 10px;
    border-radius: var(--radius-pill);
    background: rgba(181, 139, 255, 0.16);
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 700;
}

.rolesFoldersToggle{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: none;
    color: var(--violet-text);
    font-size: var(--text-sm);
    cursor: pointer;
}

.rolesFoldersToggle input{
    width: 16px;
    height: 16px;
    accent-color: var(--violet-accent);
    cursor: pointer;
}

.rolesAccess{
    max-height: 30vh;
    overflow-y: auto;
}

/* "Remember this?" - a memory Dusty proposed that the user didn't actually say
   (see brain-dump.js's memoryIsSupportedByUser), so it waits for a tap. */
.brainDumpMemorySaved.offer{
    flex-wrap: wrap;
    border-style: dashed;
    border-color: var(--violet-accent, #b58bff);
}

.brainDumpMemorySaved.offer .brainDumpMemorySavedText{
    flex-basis: 60%;
}

.brainDumpMemorySaved.offer .suggestionAcceptBtn,
.brainDumpMemorySaved.offer .suggestionDismissBtn{
    height: 26px;
    padding: 0 10px;
    border-radius: 8px;
    font-size: var(--text-xs, 11px);
    font-weight: 700;
    cursor: pointer;
}

/* ---- "What's new" popup + header button (whatsnew.js) ---- */
.whatsNewBtn{
    position: relative;
    height: 32px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-sm);
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface);
    color: #dce8fb;
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.whatsNewBtn:hover{
    background: var(--violet-surface-soft);
    border-color: var(--violet-accent);
}

.whatsNewBtn:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

.whatsNewDot{
    display: none;
    position: absolute;
    top: -3px;
    right: -3px;
    width: 10px;
    height: 10px;
    border-radius: var(--radius-circle);
    background: var(--color-danger, #ff6b6b);
    border: 2px solid #0a0712;
}

.whatsNewBtn.hasNew .whatsNewDot{
    display: block;
}

.whatsNewOverlay{
    position: fixed;
    inset: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-5, 20px);
    background: rgba(8, 5, 24, 0.72);
    backdrop-filter: blur(3px);
}

.whatsNewCard{
    display: flex;
    flex-direction: column;
    width: min(940px, 96vw);
    height: min(680px, calc(100vh - 40px));
    overflow: hidden;
    padding: 18px 22px 16px;
    border-radius: var(--radius-lg);
    border: 1px solid rgba(181, 139, 255, 0.4);
    background: linear-gradient(145deg, #2a1f66, #1a1143);
    color: var(--violet-text);
    box-shadow: var(--card-shadow);
}

.whatsNewHeader{
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 4px;
}

.whatsNewKicker{
    margin: 0;
    color: var(--violet-accent);
    font-size: var(--text-sm);
    font-weight: 800;
    letter-spacing: 0.6px;
    text-transform: uppercase;
}

.whatsNewCloseBtn{
    width: 30px;
    height: 30px;
    border: 0;
    border-radius: var(--radius-circle);
    background: transparent;
    color: var(--violet-muted);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
}

.whatsNewCloseBtn:hover{
    background: rgba(181, 139, 255, 0.18);
    color: var(--violet-text);
}

.whatsNewActions{
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 18px;
}

.whatsNewDoneBtn,
.whatsNewSecondaryBtn{
    height: 36px;
    padding: 0 18px;
    border-radius: 10px;
    font-size: var(--text-base);
    font-weight: 700;
    cursor: pointer;
}

.whatsNewDoneBtn{
    border: 0;
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    color: #120b30;
}

.whatsNewSecondaryBtn{
    border: 1px solid var(--violet-border);
    background: transparent;
    color: var(--violet-muted);
}

.whatsNewDoneBtn:hover{
    filter: brightness(1.08);
}

.whatsNewSecondaryBtn:hover{
    border-color: var(--violet-accent);
    color: var(--violet-text);
}

.whatsNewDoneBtn:focus-visible,
.whatsNewSecondaryBtn:focus-visible,
.whatsNewCloseBtn:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

@media (max-width: 520px){
    .whatsNewOverlay{
        align-items: flex-end;
        padding: 0;
    }

    .whatsNewCard{
        width: 100%;
        max-height: 88vh;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    }


    .whatsNewDoneBtn{
        flex: 1;
    }
}

/* The header is tight on a phone: keep just the gift icon (the button keeps its aria-label). */
@media (max-width: 700px){
    .whatsNewBtn > span:not(.whatsNewDot){
        display: none;
    }

    .whatsNewBtn{
        padding: 0 var(--space-2);
    }
}

/* Dusty's action cards (dusty-actions.js): plain-words description of what would happen,
   and a clear "can't do this" state (unticked, disabled, with the reason) when the user
   isn't permitted. */
.brainDumpActionText{
    margin: 0;
    color: var(--violet-text, #f6f4ff);
    font-size: var(--text-sm, 12px);
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.brainDumpActionCard.blocked{
    border-style: dashed;
    border-color: rgba(255, 159, 159, 0.5);
    background: rgba(255, 107, 107, 0.06);
}

.brainDumpActionCard.blocked .brainDumpActionText{
    color: #ffb3b3;
}

.brainDumpActionCard.blocked .brainDumpTaskCardTarget{
    opacity: 0.7;
}

.brainDumpActionNote{
    margin: 4px 0 0;
    color: var(--color-warning, #ffb84d);
    font-size: var(--text-xs, 11px);
    font-weight: 600;
}

/* ---- Capped folder bar: "More folders" panel + the narrow-screen picker ---- */

/* The compact "Folder: X" button only exists for narrow screens. */
.folderPickerChip{
    display: none;
}

.folderMoreChip{
    border-style: dashed;
}

.folderMoreChip i,
.folderPickerChip i{
    font-size: 10px;
}

.folderPickerPanel{
    position: fixed;
    z-index: 60;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(181, 139, 255, 0.45);
    background: linear-gradient(145deg, #2a1f66, #1a1143);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.7);
}

.folderPickerSearch{
    flex: 0 0 auto;
    width: 100%;
    padding: 8px 10px;
    border: 2px solid rgba(181, 139, 255, 0.4);
    border-radius: 12px;
    background: rgba(18, 11, 48, 0.9);
    color: var(--violet-text);
    font-size: var(--text-base);
    box-sizing: border-box;
}

.folderPickerSearch:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

/* The list scrolls inside the panel, so the panel never gets taller than the screen. */
.folderPickerList{
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-height: 0;
    overflow-y: auto;
}

.folderPickerItem{
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--violet-text);
    font-size: var(--text-base);
    text-align: left;
    cursor: pointer;
}

.folderPickerItem:hover,
.folderPickerItem:focus-visible{
    outline: none;
    background: rgba(181, 139, 255, 0.22);
}

.folderPickerItem.active{
    background: rgba(181, 139, 255, 0.34);
    font-weight: 700;
}

.folderPickerName{
    min-width: 0;
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.folderPickerEmpty{
    margin: 0;
    padding: 8px 10px;
    color: var(--violet-muted);
    font-size: var(--text-sm);
}

@media (max-width: 640px){
    .folderFilterChip{
        display: none;
    }

    .folderPickerChip{
        display: inline-flex;
    }
}

/* Group by sections can be folded shut: the heading is one full-width button. */
.groupSectionToggle{
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 6px 8px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    text-align: left;
    cursor: pointer;
}

.groupSectionToggle:hover{
    background: rgba(181, 139, 255, 0.14);
}

.groupSectionToggle:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

.groupSectionTitle{
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.groupSectionChevron{
    flex: 0 0 auto;
    font-size: 10px;
    color: var(--violet-muted);
    transition: transform 0.15s ease;
}

.groupSectionHeading.collapsed .groupSectionChevron{
    transform: rotate(-90deg);
}

@media (prefers-reduced-motion: reduce){
    .groupSectionChevron{
        transition: none;
    }
}
.groupSectionHeading{ padding: 0; }

/* ---- What's new, as a reader: updates on the left, the post on the right ---- */
.whatsNewHeader{
    flex: 0 0 auto;
    margin-bottom: 10px;
}

.whatsNewLayout{
    flex: 1 1 auto;
    display: grid;
    grid-template-columns: 240px minmax(0, 1fr);
    gap: 16px;
    min-height: 0;
}

.whatsNewNav{
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-height: 0;
    overflow-y: auto;
    padding-right: 4px;
    scrollbar-width: thin;
    scrollbar-color: rgba(181, 139, 255, 0.5) transparent;
}

.whatsNewNavItem{
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 10px 12px;
    border: 1px solid var(--violet-border-soft);
    border-radius: var(--radius-md);
    background: rgba(18, 11, 48, 0.55);
    color: var(--violet-text);
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.whatsNewNavItem:hover{
    border-color: var(--violet-accent);
}

.whatsNewNavItem.active{
    border-color: rgba(202, 167, 255, 0.9);
    background: rgba(181, 139, 255, 0.24);
}

.whatsNewNavItem:focus-visible,
.whatsNewMain:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

.whatsNewNavTop{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.whatsNewNavDate{
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 700;
}

.whatsNewNewTag{
    padding: 1px 8px;
    border-radius: var(--radius-pill);
    background: #3ddc97;
    color: #0b2a1d;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.4px;
    text-transform: uppercase;
}

.whatsNewNavTitle{
    font-size: var(--text-sm);
    font-weight: 700;
    line-height: 1.3;
}

.whatsNewMain{
    min-height: 0;
    overflow-y: auto;
    padding: 4px 8px 12px 2px;
    border-radius: var(--radius-md);
    scrollbar-width: thin;
    scrollbar-color: rgba(181, 139, 255, 0.5) transparent;
}

.whatsNewPostTitle{
    margin: 0;
    font-size: 26px;
    line-height: 1.2;
}

.whatsNewPostDate{
    margin: 6px 0 0;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--violet-border-soft);
    color: var(--violet-muted);
    font-size: var(--text-sm);
    font-weight: 600;
}

.whatsNewIntro{
    margin: 16px 0 0;
    font-size: var(--text-md);
    line-height: 1.6;
}

.whatsNewSection{
    margin-top: 22px;
}

.whatsNewSectionHead{
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 8px;
    font-size: var(--text-lg, 20px);
    line-height: 1.25;
}

.whatsNewIcon{
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    background: rgba(181, 139, 255, 0.18);
    color: var(--violet-accent);
    font-size: 15px;
}

.whatsNewText{
    margin: 0 0 10px;
    color: var(--violet-text);
    font-size: var(--text-base);
    line-height: 1.65;
}

.whatsNewPoints{
    margin: 0 0 4px;
    padding-left: 22px;
    color: var(--violet-muted);
    font-size: var(--text-base);
    line-height: 1.6;
}

.whatsNewPoints li + li{
    margin-top: 4px;
}

.whatsNewTip{
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 22px 0 0;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: 1px dashed rgba(202, 167, 255, 0.6);
    background: rgba(181, 139, 255, 0.12);
    font-size: var(--text-base);
    line-height: 1.5;
}

.whatsNewTip i{
    margin-top: 3px;
    color: #ffd166;
}

.whatsNewSignoff{
    margin: 18px 0 0;
    color: var(--violet-muted);
    font-size: var(--text-base);
    font-style: italic;
}

.whatsNewActions{
    flex: 0 0 auto;
}

@media (max-width: 760px){
    .whatsNewLayout{
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto minmax(0, 1fr);
        gap: 10px;
    }

    /* The list of updates becomes a sideways strip above the post. */
    .whatsNewNav{
        flex-direction: row;
        overflow-x: auto;
        overflow-y: hidden;
        padding: 0 0 6px;
    }

    .whatsNewNavItem{
        flex: 0 0 200px;
    }

    .whatsNewPostTitle{
        font-size: 22px;
    }
}

@media (max-width: 520px){
    .whatsNewCard{
        height: 92vh;
        padding: 16px 16px 14px;
    }
}

@media (prefers-reduced-motion: reduce){
    .whatsNewNavItem{
        transition: none;
    }
}

/* Group by: the section heading is a solid banner in the section's color, and the tasks
   under it are indented with a stripe in the same color, so it's clear where one group
   ends and the next begins. (Needs to beat the generic ".tasks li" card look.) */
.tasks li.groupSectionHeading{
    width: 90%;
    margin: 18px 0 2px;
    padding: 0;
    gap: 0;
    cursor: default;
    border: 0;
    border-radius: 12px;
    background: linear-gradient(90deg, color-mix(in srgb, var(--section-color, #94a3b8) 62%, #120b30) 0%, color-mix(in srgb, var(--section-color, #94a3b8) 16%, #120b30) 100%);
    box-shadow: inset 6px 0 0 var(--section-color, #94a3b8), 0 6px 18px rgba(0, 0, 0, 0.35);
    color: #ffffff;
    font-size: var(--text-md);
    letter-spacing: 0.6px;
}

.tasks li.groupSectionHeading:first-child{
    margin-top: 4px;
}

.tasks li.groupSectionHeading .groupSectionToggle{
    padding: 12px 16px 12px 22px;
    border-radius: 12px;
}

.tasks li.groupSectionHeading .groupSectionToggle:hover{
    background: rgba(255, 255, 255, 0.08);
}

.tasks li.groupSectionHeading .groupSectionChevron{
    color: #ffffff;
    font-size: 12px;
}

.tasks li.groupSectionHeading .groupSectionCount{
    margin-left: auto;
    padding: 2px 11px;
    background: rgba(0, 0, 0, 0.32);
    color: #ffffff;
    font-size: var(--text-sm);
    font-weight: 800;
}

/* Tasks inside a section: indented, with a stripe in the section's color. */
.tasks li.inSection{
    align-self: flex-end;
    width: calc(90% - 22px);
    margin-right: 5%;
    border-left: 5px solid var(--section-color, #94a3b8);
}

@media (max-width: 520px){
    .tasks li.inSection{
        width: calc(90% - 12px);
    }
}

/* Team tab: the owner/admin "Roles & access" strip above the roster. */
.teamToolbar{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    margin: 0 0 14px;
    padding: 12px 16px;
    border-radius: var(--radius-md);
    border: 1px dashed rgba(202, 167, 255, 0.5);
    background: rgba(181, 139, 255, 0.1);
}

.teamToolbar.hidden{
    display: none;
}

.teamToolbarText{
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    color: var(--violet-muted);
    font-size: var(--text-sm);
}

.teamToolbarText strong{
    color: var(--violet-text);
    font-size: var(--text-base);
}

.teamRolesBtn{
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 36px;
    padding: 0 16px;
    border: 0;
    border-radius: 10px;
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    color: #120b30;
    font-size: var(--text-base);
    font-weight: 700;
    cursor: pointer;
}

.teamRolesBtn:hover{
    filter: brightness(1.08);
}

.teamRolesBtn:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

@media (max-width: 520px){
    .teamToolbar{
        flex-direction: column;
        align-items: stretch;
    }
}

/* ---- Notification center: the bell + panel (notifications.js) ---- */
.notifBtn{
    position: relative;
    flex: none;
    width: 34px;
    height: 32px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--violet-border-soft);
    background: var(--violet-surface);
    color: #dce8fb;
    font-size: 15px;
    cursor: pointer;
}

.notifBtn:hover,
.notifBtn[aria-expanded="true"]{
    background: var(--violet-surface-soft);
    border-color: var(--violet-accent);
}

.notifBtn:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

.notifBadge{
    display: none;
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: #ef5b4c;
    border: 2px solid #0a0712;
    color: #fff;
    font-size: 10px;
    font-weight: 800;
    line-height: 14px;
    text-align: center;
    box-sizing: border-box;
}

.notifBtn.hasUnread .notifBadge{
    display: block;
}

.notifPanel{
    position: fixed;
    z-index: 70;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-radius: var(--radius-lg);
    border: 1px solid rgba(181, 139, 255, 0.45);
    background: linear-gradient(145deg, #2a1f66, #1a1143);
    color: var(--violet-text);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.7);
}

.notifHead{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px 8px;
}

.notifHeading{
    margin: 0;
    font-size: var(--text-lg, 20px);
}

.notifMarkAll{
    border: 0;
    background: transparent;
    color: var(--violet-accent);
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
}

.notifMarkAll:disabled{
    opacity: 0.4;
    cursor: default;
}

.notifTabs{
    display: flex;
    gap: 6px;
    padding: 0 16px 10px;
    border-bottom: 1px solid var(--violet-border-soft);
    overflow-x: auto;
}

.notifTab{
    flex: none;
    padding: 4px 12px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--violet-border);
    background: transparent;
    color: var(--violet-muted);
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
}

.notifTab.active{
    background: linear-gradient(120deg, rgba(193, 152, 255, 0.98), rgba(132, 140, 255, 0.98));
    border-color: transparent;
    color: #120b30;
}

.notifAsk{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin: 10px 16px 0;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    border: 1px dashed rgba(202, 167, 255, 0.6);
    background: rgba(181, 139, 255, 0.12);
    font-size: var(--text-sm);
}

.notifAskBtn,
.alertsAskYes{
    flex: none;
    padding: 5px 14px;
    border: 0;
    border-radius: 8px;
    background: linear-gradient(120deg, rgba(202, 167, 255, 0.97), rgba(143, 150, 255, 0.98));
    color: #120b30;
    font-weight: 700;
    cursor: pointer;
}

.notifList{
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 6px 8px 10px;
    scrollbar-width: thin;
    scrollbar-color: rgba(181, 139, 255, 0.5) transparent;
}

.notifSection{
    margin: 10px 8px 4px;
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 800;
    letter-spacing: 0.5px;
    text-transform: uppercase;
}

.notifItem{
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    width: 100%;
    padding: 10px 12px;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    box-sizing: border-box;
}

button.notifItem{
    cursor: pointer;
}

button.notifItem:hover,
button.notifItem:focus-visible{
    outline: none;
    background: rgba(181, 139, 255, 0.18);
}

.notifItem.unread{
    background: rgba(181, 139, 255, 0.1);
}

.notifIcon{
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: rgba(181, 139, 255, 0.2);
    color: var(--violet-accent);
    font-size: 15px;
}

.notifReminder.level-overdue .notifIcon{
    background: rgba(248, 118, 111, 0.22);
    color: #ff8f86;
}

.notifReminder.level-critical .notifIcon{
    background: rgba(255, 147, 83, 0.22);
    color: #ffae78;
}

.notifReminder.level-soon .notifIcon{
    background: rgba(255, 191, 84, 0.2);
    color: #ffd27a;
}

.notifBody{
    flex: 1 1 auto;
    min-width: 0;
}

.notifBody p{
    margin: 0;
    overflow-wrap: anywhere;
}

.notifTitle{
    font-size: var(--text-base);
    font-weight: 700;
    line-height: 1.35;
}

.notifText{
    margin-top: 2px;
    color: var(--violet-muted);
    font-size: var(--text-sm);
    line-height: 1.4;
}

.notifMeta{
    margin-top: 4px;
    color: var(--violet-muted);
    font-size: var(--text-xs);
}

.notifDot{
    flex: none;
    align-self: center;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #8fa0ff;
}

.notifEmpty{
    margin: 26px 16px;
    color: var(--violet-muted);
    font-size: var(--text-base);
    text-align: center;
}

.alertsAskToast{
    position: fixed;
    left: 16px;
    bottom: 16px;
    z-index: 60;
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: min(340px, calc(100vw - 32px));
    padding: 14px 16px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(181, 139, 255, 0.45);
    background: linear-gradient(145deg, #2a1f66, #1a1143);
    color: var(--violet-text);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.6);
}

.alertsAskText{
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: var(--text-sm);
    line-height: 1.45;
}

.alertsAskText strong{
    font-size: var(--text-base);
}

.alertsAskActions{
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

.alertsAskYes{
    padding: 7px 16px;
}

.alertsAskNo{
    padding: 7px 14px;
    border: 1px solid var(--violet-border);
    border-radius: 8px;
    background: transparent;
    color: var(--violet-muted);
    font-weight: 700;
    cursor: pointer;
}

.notifBtn:focus-visible,
.notifMarkAll:focus-visible,
.notifTab:focus-visible,
.notifAskBtn:focus-visible,
.alertsAskYes:focus-visible,
.alertsAskNo:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

@media (max-width: 520px){
    .notifPanel{
        border-radius: var(--radius-md);
    }
}

/* ---- Today panel (today.js) ---- */
.todayPanel{
    width: 100%;
    margin: 0 0 16px;
    padding: 4px 16px 14px;
    border-radius: var(--radius-lg);
    border: 1px solid rgba(181, 139, 255, 0.4);
    background: linear-gradient(145deg, rgba(42, 31, 102, 0.9), rgba(26, 17, 67, 0.92));
    color: var(--violet-text);
    box-sizing: border-box;
}

.todayPanel.hidden{
    display: none;
}

.todayToggle{
    display: flex;
    align-items: baseline;
    gap: 10px;
    width: 100%;
    padding: 10px 0 6px;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.todayToggle:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
    border-radius: 8px;
}

.todayChevron{
    font-size: 11px;
    color: var(--violet-muted);
    transition: transform 0.15s ease;
}

.todayPanel.collapsed .todayChevron{
    transform: rotate(-90deg);
}

.todayTitle{
    font-size: var(--text-lg, 20px);
    font-weight: 800;
}

.todayDate{
    color: var(--violet-muted);
    font-size: var(--text-sm);
    font-weight: 600;
}

.todaySummary{
    margin: 2px 0 10px;
    font-size: var(--text-md);
    line-height: 1.5;
}

.todayChips{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 10px;
}

.todayChip{
    padding: 3px 12px;
    border-radius: var(--radius-pill);
    background: rgba(181, 139, 255, 0.2);
    font-size: var(--text-sm);
    font-weight: 700;
}

.todayChip.isOverdue{ background: rgba(248, 118, 111, 0.28); color: #ffb3ad; }
.todayChip.isToday{ background: rgba(255, 191, 84, 0.25); color: #ffd98f; }
.todayChip.isBlocked{ background: rgba(255, 107, 107, 0.22); color: #ff9c9c; }
.todayChip.isReview{ background: rgba(77, 196, 255, 0.22); color: #9adcff; }

.todayLabel{
    margin: 10px 0 4px;
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 800;
    letter-spacing: 0.5px;
    text-transform: uppercase;
}

.todayList{
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.todayItem{
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0;
    border-radius: 10px;
    background: rgba(18, 11, 48, 0.5);
    font-size: var(--text-base);
}

.todayItem.isBlocked,
.todayItem.isReview{
    padding: 8px 12px;
}

.todayItemBtn{
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 12px;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.todayItemBtn:hover,
.todayItemBtn:focus-visible{
    outline: none;
    background: rgba(181, 139, 255, 0.2);
}

.todayNumber{
    flex: none;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: rgba(181, 139, 255, 0.28);
    font-size: var(--text-xs);
    font-weight: 800;
    line-height: 22px;
    text-align: center;
}

.todayItem.level-overdue .todayNumber{ background: rgba(248, 118, 111, 0.4); }
.todayItem.level-today .todayNumber{ background: rgba(255, 191, 84, 0.4); }

.todayItemText{
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.todayItemLabel{
    flex: none;
    color: var(--violet-muted);
    font-size: var(--text-sm);
}

.todayFlash{
    animation: todayFlash 1.5s ease;
}

@keyframes todayFlash{
    0%, 60% { box-shadow: 0 0 0 4px rgba(202, 167, 255, 0.85); }
    100% { box-shadow: 0 0 0 0 rgba(202, 167, 255, 0); }
}

/* ---- Task status, review and mentions (group/workflow.js) ---- */
.taskStatusRow{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 2px 4px 0;
}

.statusChip{
    padding: 3px 11px;
    border-radius: var(--radius-pill);
    background: rgba(181, 139, 255, 0.22);
    font-size: var(--text-sm);
    font-weight: 700;
}

.statusChip.status-inprogress{ background: rgba(77, 196, 255, 0.22); color: #9adcff; }
.statusChip.status-blocked{ background: rgba(255, 107, 107, 0.25); color: #ffa3a3; }
.statusChip.status-review{ background: rgba(255, 191, 84, 0.25); color: #ffd98f; }
.statusChip.status-approved{ background: rgba(61, 220, 151, 0.25); color: #8ff0c4; }

.statusReason{
    min-width: 0;
    color: var(--violet-muted);
    font-size: var(--text-sm);
    overflow-wrap: anywhere;
}

.statusControls{
    display: inline-flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-left: auto;
}

.statusBtn{
    padding: 3px 11px;
    border-radius: var(--radius-pill);
    border: 1px dashed var(--violet-border);
    background: transparent;
    color: var(--violet-muted);
    font-size: var(--text-sm);
    font-weight: 700;
    cursor: pointer;
}

.statusBtn:hover,
.statusBtn:focus-visible{
    outline: none;
    border-color: var(--violet-accent);
    color: var(--violet-text);
}

.statusBtn.isBlockedBtn:hover{ border-color: #ff8f8f; color: #ffb3b3; }
.statusBtn.isReviewBtn{ border-style: solid; }
.statusBtn.isApproveBtn{ border-style: solid; border-color: rgba(61, 220, 151, 0.7); color: #8ff0c4; }
.statusBtn.isBackBtn{ border-style: solid; }

.sharedReviewRow{
    margin-top: 8px;
}

.sharedTaskChip.isBlocked{
    border-color: rgba(255, 107, 107, 0.7);
}

.askTextCard{
    width: min(460px, 95vw);
}

.askTextInput{
    width: 100%;
    padding: 10px 12px;
    border: 2px solid rgba(181, 139, 255, 0.4);
    border-radius: 12px;
    background: rgba(18, 11, 48, 0.9);
    color: var(--violet-text);
    font: inherit;
    resize: vertical;
    box-sizing: border-box;
}

.askTextInput:focus-visible{
    outline: none;
    box-shadow: 0 0 0 3px rgba(174, 148, 255, 0.4);
}

.askTextActions{
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 12px;
}

.commentAddRow{
    position: relative;
}

.mention{
    padding: 0 4px;
    border-radius: 6px;
    background: rgba(143, 150, 255, 0.28);
    color: #c9ceff;
    font-weight: 700;
}

.mentionMenu{
    position: absolute;
    left: 0;
    bottom: calc(100% + 4px);
    z-index: 30;
    display: flex;
    flex-direction: column;
    min-width: 200px;
    max-width: 100%;
    padding: 4px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(181, 139, 255, 0.45);
    background: linear-gradient(145deg, #2a1f66, #1a1143);
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
}

.mentionOption{
    padding: 7px 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--violet-text);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.mentionOption.active,
.mentionOption:hover{
    background: rgba(181, 139, 255, 0.25);
}

/* ---- Weekly report (group/report.js) ---- */
.teamReport{
    margin: 0 0 16px;
    padding: 16px 18px;
    border-radius: var(--radius-lg);
    border: 1px solid rgba(181, 139, 255, 0.4);
    background: linear-gradient(145deg, rgba(42, 31, 102, 0.9), rgba(26, 17, 67, 0.92));
    color: var(--violet-text);
}

.teamReport.hidden{
    display: none;
}

.reportHead{
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.reportTitle{
    margin: 0;
    font-size: var(--text-lg, 20px);
}

.reportPeriod{
    margin: 2px 0 0;
    color: var(--violet-muted);
    font-size: var(--text-sm);
}

.reportCopyBtn{
    flex: none;
    padding: 6px 14px;
    border-radius: 10px;
    border: 1px solid var(--violet-border);
    background: transparent;
    color: var(--violet-muted);
    font-weight: 700;
    cursor: pointer;
}

.reportCopyBtn:hover,
.reportCopyBtn:focus-visible{
    outline: none;
    border-color: var(--violet-accent);
    color: var(--violet-text);
}

.reportHeadline{
    margin: 12px 0;
    font-size: var(--text-md);
    line-height: 1.5;
}

.reportTiles{
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px;
    margin-bottom: 14px;
}

.reportTile{
    display: flex;
    flex-direction: column;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    background: rgba(18, 11, 48, 0.55);
}

.reportTileValue{
    font-size: 26px;
    font-weight: 800;
    line-height: 1.1;
}

.reportTileLabel{
    color: var(--violet-muted);
    font-size: var(--text-sm);
}

.reportTile.isDone .reportTileValue{ color: #8ff0c4; }
.reportTile.isOverdue .reportTileValue{ color: #ff9c94; }
.reportTile.isBlocked .reportTileValue{ color: #ffa3a3; }
.reportTile.isReview .reportTileValue{ color: #ffd98f; }

.reportTable{
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.reportRow{
    display: grid;
    grid-template-columns: minmax(0, 2fr) repeat(5, minmax(0, 1fr));
    gap: 8px;
    align-items: center;
    padding: 7px 10px;
    border-radius: 8px;
    font-size: var(--text-base);
}

.reportRow:nth-child(even){
    background: rgba(18, 11, 48, 0.4);
}

.reportRowHead{
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 800;
    letter-spacing: 0.4px;
    text-transform: uppercase;
}

.reportName{
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 700;
}

.reportRow .isOverdue{ color: #ff9c94; font-weight: 800; }
.reportRow .isBlocked{ color: #ffa3a3; font-weight: 800; }

.reportNote{
    margin: 8px 0 0;
    color: var(--violet-muted);
    font-size: var(--text-xs);
}

.reportSection{
    margin: 14px 0 4px;
    color: var(--violet-muted);
    font-size: var(--text-xs);
    font-weight: 800;
    letter-spacing: 0.5px;
    text-transform: uppercase;
}

.reportStuck{
    margin: 0;
    padding-left: 20px;
    font-size: var(--text-base);
    line-height: 1.5;
}

@media (max-width: 560px){
    .reportTiles{
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .reportRow{
        grid-template-columns: minmax(0, 2fr) repeat(5, minmax(0, 1fr));
        padding: 7px 4px;
        font-size: var(--text-sm);
    }

    .statusControls{
        margin-left: 0;
    }
}

@media (prefers-reduced-motion: reduce){
    .todayChevron{
        transition: none;
    }

    .todayFlash{
        animation: none;
    }
}

/* ---- "Needs my approval" (assigning) ---- */
.assignApprovalRow{
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    color: var(--violet-muted);
    font-size: var(--text-sm);
    cursor: pointer;
}

.assignApprovalRow.hidden{
    display: none;
}

.statusChip.status-needs{
    background: rgba(255, 191, 84, 0.18);
    color: #ffd98f;
}

/* ---- Task dependencies ---- */
.statusChip.status-waiting{
    background: rgba(154, 163, 255, 0.2);
    color: #c9ceff;
}

.tasks li.isWaitingOnTask{
    opacity: 0.78;
}

.dependencyList{
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: min(320px, 45vh);
    margin: 8px 0;
    overflow-y: auto;
}

.dependencyRow{
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.dependencyRow:hover{
    background: rgba(181, 139, 255, 0.2);
}

.dependencyText{
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dependencyWho{
    flex: none;
    color: var(--violet-muted);
    font-size: var(--text-sm);
}
