/* ==========================================================================
   Modern visual layer ("Polish, same layout")
   --------------------------------------------------------------------------
   Linked right after styles.css. It adds design tokens on top of the
   generated modules/css/tokens.css and restyles existing components through
   their existing classes: no markup or layout changes. Rules here touch paint
   (colour, background, border, radius, shadow, type, transitions), not box
   geometry, so the responsive layout rules in styles.css keep working.

   Sections
     1. Tokens: type, space, radii, surfaces, elevation, accent palette,
        focus ring, motion (light on :root, dark on html[data-mode="dark"])
     2. Base: type rendering, tabular numbers, selection, focus ring
     3. Buttons: primary / secondary / ghost / destructive
     4. Chips, inputs, selects, sliders, switches
     5. Cards and list rows
     6. Bars: home header, builder header, stats/feature headers, segmented tabs
     7. Modals and sheets (rounded top sheets on phones), scrims
     8. Toasts, empty states, skeleton loaders, icons
     9. Motion: press, hover lift (desktop only), enter/exit, list insert
    10. Reduce Motion (OS setting or html[data-reduce-motion]) and perf guards

   Backdrop blur is only used on modal scrims on wide, hover-capable screens.
   Phones and long scrolling lists get opaque surfaces.
   ========================================================================== */

/* 1. Tokens ---------------------------------------------------------------- */
:root {
    /* Type: system UI stack (SF Pro on Apple platforms). The Font Style
       setting still swaps --font-design via [data-font]. */
    --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
        "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
    --fs-2xs: 11px;
    --fs-xs: 12px;
    --fs-sm: 13px;
    --fs-md: 15px;
    --fs-base: 16px;
    --fs-lg: 17px;
    --fs-xl: 20px;
    --fs-2xl: 24px;
    --fs-3xl: 28px;
    --fs-4xl: 34px;
    --lh-tight: 1.2;
    --lh-snug: 1.35;
    --lh-body: 1.5;
    --fw-regular: 400;
    --fw-medium: 500;
    --fw-semibold: 600;
    --fw-bold: 700;
    --tracking-tight: -0.011em;
    --tracking-title: -0.02em;
    --tracking-caps: 0.06em;

    /* Space: 4/8 pt grid. --space-1..7 (4..48) come from tokens.css. */
    --space-0: 2px;
    --space-8: 64px;

    /* Radii */
    --radius-xs: 6px;
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --radius-xl: 20px;
    --radius-2xl: 28px;

    /* Surface hierarchy: page < base (cards) < raised (menus, popovers)
       < overlay (sheets, modals). --surface-glass is the translucent version
       of the overlay, used only where backdrop-filter is allowed (see §10). */
    --surface-page: var(--bg-app);
    --surface-base: var(--surface);
    --surface-raised: #ffffff;
    --surface-sunken: var(--surface-2);
    --surface-overlay: #ffffff;
    --surface-glass: rgba(255, 255, 255, 0.72);
    --surface-bar: rgba(255, 255, 255, 0.92);
    --glass-filter: saturate(180%) blur(20px);
    --hairline: rgba(0, 0, 0, 0.08);
    --hairline-strong: rgba(0, 0, 0, 0.14);
    --scrim: rgba(17, 17, 26, 0.38);

    /* Elevation: two-layer shadows (contact + ambient). */
    --elev-0: none;
    --elev-1: 0 1px 2px rgba(17, 17, 26, 0.05), 0 1px 3px rgba(17, 17, 26, 0.06);
    --elev-2: 0 1px 2px rgba(17, 17, 26, 0.04), 0 4px 14px rgba(17, 17, 26, 0.08);
    --elev-3: 0 2px 6px rgba(17, 17, 26, 0.06), 0 12px 32px rgba(17, 17, 26, 0.12);
    --elev-4: 0 4px 12px rgba(17, 17, 26, 0.08), 0 24px 64px rgba(17, 17, 26, 0.18);
    /* Hairline ring drawn with box-shadow so it adds no layout. */
    --ring-hairline: 0 0 0 1px var(--hairline);

    /* Accent palette, derived from whatever accent is active (default, a Theme
       preset, or a custom colour), so every theme keeps working.
       --accent-fill is the background of solid accent controls with white
       labels; --accent-tint-* are translucent fills for selected states. */
    --accent-fill: var(--accent);
    --accent-fill-hover: var(--accent-hover);
    --accent-on: var(--text-on-accent, #ffffff);
    --accent-tint-1: rgba(var(--accent-rgb), 0.08);
    --accent-tint-2: rgba(var(--accent-rgb), 0.14);
    --accent-tint-3: rgba(var(--accent-rgb), 0.22);
    --accent-glow: 0 1px 2px rgba(var(--accent-rgb), 0.24), 0 4px 12px rgba(var(--accent-rgb), 0.22);

    /* Secondary text that must still meet AA (4.5:1) on page, cards and
       chips: the old #888 / #999 were 3.5:1 / 2.8:1 on white. */
    --text-tertiary: #6e6e73;
    --text-muted: #6e6e73;

    /* Status */
    --danger-fill: #d92d20;
    --danger-fill-hover: #b42318;
    --danger-ink: #b42318;
    --success-fill: #1f8f4e;

    /* Switch "on" track: the accent fill (>= 3:1 against the page in every
       preset theme, unlike the old #34c759 at 2.2:1). */
    --switch-on: var(--accent-fill);
    --switch-off: #d1d1d6;
    --switch-thumb: #ffffff;

    /* Focus ring: >= 3:1 against every light surface for all preset themes
       (darkened accent; 4.0:1 worst case, sunset). Fallback without
       color-mix(): --accent-hover, which is the accent darkened 15%. */
    --focus-ring: var(--accent-hover);
    --focus-ring-width: 2px;
    --focus-ring-offset: 2px;

    /* Motion (UI micro-interactions; durations drop to 0 under Reduce Motion,
       see §10). --dur-press / --press-scale come from tokens.css (W1). */
    --dur-fast: 120ms;
    --dur-base: 180ms;
    --dur-slow: 250ms;
    --ease-emph: cubic-bezier(0.2, 0.8, 0.2, 1);
    --lift: -2px;
}

@supports (color: color-mix(in srgb, red 50%, white)) {
    :root {
        --focus-ring: color-mix(in srgb, var(--accent) 80%, #000000);
        --accent-fill-hover: color-mix(in srgb, var(--accent-fill) 88%, #000000);
    }
    /* Preset themes and custom accents: white labels on the raw accent are
       3.1-3.9:1 for sunset/forest/lavender/rose. Darken the fill 20% (>= 4.57:1
       for every preset) and accent-coloured text 28% (>= 4.75:1 on light
       surfaces). The default purple already passes (7.0:1) and is unchanged. */
    html[data-theme],
    html[style*="--accent:"] {
        --accent-fill: color-mix(in srgb, var(--accent) 80%, #000000);
    }
    html[data-theme]:not([data-mode="dark"]),
    html[style*="--accent:"]:not([data-mode="dark"]) {
        --accent-text: color-mix(in srgb, var(--accent) 72%, #000000);
    }
}

html[data-mode="dark"] {
    --surface-raised: #242426;
    --surface-overlay: #1c1c1e;
    --surface-glass: rgba(30, 30, 32, 0.72);
    --surface-bar: rgba(10, 10, 12, 0.88);
    --hairline: rgba(255, 255, 255, 0.08);
    --hairline-strong: rgba(255, 255, 255, 0.14);
    --scrim: rgba(0, 0, 0, 0.62);

    /* Dark elevation: shadows barely read on near-black, so each level adds a
       faint top highlight (inset) and a deeper ambient shadow. */
    --elev-1: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 1px 2px rgba(0, 0, 0, 0.5);
    --elev-2: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 4px 14px rgba(0, 0, 0, 0.55);
    --elev-3: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 12px 32px rgba(0, 0, 0, 0.6);
    --elev-4: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 24px 64px rgba(0, 0, 0, 0.7);

    --text-tertiary: #98989d;
    --text-muted: #8e8e93;

    /* White labels need >= 4.5:1: #d8363b is 4.66:1 (hover #cd2b31 5.27:1),
       and both stay >= 3:1 against the dark surfaces. */
    --danger-fill: #d8363b;
    --danger-fill-hover: #cd2b31;
    --danger-ink: #ff8a8f;
    --switch-off: #48484a;
    --switch-thumb: #ffffff;
    /* The darkened accent fill is 1.7-2.4:1 on dark surfaces (default,
       midnight); the dark accent text colour is >= 4.5:1 for every preset. */
    --switch-on: var(--accent-text);

    /* Dark focus ring: the dark accent text (accent 48% + white): 4.7:1 or
       better on every dark surface for all presets. This replaces the old
       2.4:1 ring (#6E29D9 on black). Fallback: the token value #B998ED. */
    --focus-ring: var(--accent-text);
}

/* 2. Base ------------------------------------------------------------------- */
html:not([data-font]) { --font-design: var(--font-sans); }

body {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

::selection { background: var(--accent-tint-3); }

/* Timers, counters and durations: tabular figures so digits don't jitter. */
#countdown,
#flowTime,
.build-flow-timer,
.flow-card-duration,
#flowTable td:nth-child(4),
#flowTable input[type="number"],
.freq-hz,
.stats-summary-cards,
.stat-value,
.breath-timer,
.breath-count,
.med-timer,
.timestamp,
.flow-count,
.home-continue-meta,
.selection-count {
    font-variant-numeric: tabular-nums;
}

/* One focus ring everywhere: the token colour wins over the older
   per-component rings that used the raw accent (2.4:1 in dark mode). The
   white rings drawn on dark/accent banners keep their colour. */
:focus-visible:not(.builder-history-toast-action):not(.app-store-banner *) {
    outline-color: var(--focus-ring) !important;
}
button:focus-visible,
a:focus-visible,
summary:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: var(--focus-ring-width) solid var(--focus-ring);
    outline-offset: var(--focus-ring-offset);
}
.switch input:focus-visible + .slider,
.pos-row input:focus-visible + .slider {
    outline: var(--focus-ring-width) solid var(--focus-ring);
    outline-offset: 2px;
}
input[type="range"]:focus-visible {
    outline: var(--focus-ring-width) solid var(--focus-ring);
    outline-offset: 4px;
}

/* 3. Buttons ---------------------------------------------------------------- */
/* Primary: solid accent, white label. */
.flow-btn,
.create-fab,
.settings-action-btn:not(.secondary),
.empty-message .primary-btn,
.flow-empty-actions .primary-btn,
.create-row-hero,
.freq-play-btn,
.feature-begin-btn,
.picker-add-btn {
    background: var(--accent-fill);
    color: var(--accent-on);
    border-color: transparent;
    box-shadow: var(--accent-glow);
}
.flow-btn {
    letter-spacing: 0.04em;
    font-weight: var(--fw-bold);
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
/* Play glyph from the icon set (playFill), drawn as a mask so it takes the
   label colour. */
.flow-item .flow-btn::before {
    content: "";
    width: 10px;
    height: 10px;
    flex: 0 0 auto;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 4.5v15a1 1 0 0 0 1.5.86l12.5-7.5a1 1 0 0 0 0-1.72L7.5 3.64A1 1 0 0 0 6 4.5z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 4.5v15a1 1 0 0 0 1.5.86l12.5-7.5a1 1 0 0 0 0-1.72L7.5 3.64A1 1 0 0 0 6 4.5z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.flow-btn:hover,
.settings-action-btn:not(.secondary):hover,
.empty-message .primary-btn:hover,
.flow-empty-actions .primary-btn:hover,
.create-row-hero:hover,
.freq-play-btn:hover,
.feature-begin-btn:hover,
.picker-add-btn:hover {
    background: var(--accent-fill-hover);
    opacity: 1;
}

/* Secondary: raised neutral with a hairline. */
.settings-action-btn.secondary,
.flow-empty-actions .secondary-btn,
.cancel-btn,
.delete-btn,
.create-row:not(.create-row-hero),
.create-tile {
    background: var(--surface-raised);
    color: var(--text-primary);
    border-color: var(--hairline-strong);
}
.settings-action-btn.secondary:hover,
.flow-empty-actions .secondary-btn:hover,
.cancel-btn:hover,
.create-row:not(.create-row-hero):hover,
.create-tile:hover {
    background: var(--surface-2);
    border-color: var(--hairline-strong);
}
.cancel-btn {
    border-width: 1px;
    border-radius: var(--radius-pill);
    text-transform: none;
    letter-spacing: 0;
    font-weight: var(--fw-semibold);
}

/* Ghost: icon buttons in bars. */
.settings-gear-btn,
.sync-now-btn,
.build-view-toggle,
.build-back-btn,
.create-sheet-close,
.home-continue-collapse,
.flow-more-btn,
.stats-back-btn,
.feature-back-btn,
.player-options-btn {
    border-color: transparent;
}
.settings-gear-btn,
.sync-now-btn {
    background: transparent;
    color: var(--text-secondary);
    box-shadow: none;
}
.settings-gear-btn:hover,
.sync-now-btn:hover,
.build-view-toggle:hover,
.build-back-btn:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}
.build-view-toggle.active {
    background: var(--accent-tint-2);
    color: var(--accent-text);
}

/* Destructive */
.delete-confirm-btn,
.delete-group-btn,
.stats-clear-btn {
    background: var(--danger-fill);
    color: #ffffff;
    border-color: var(--danger-fill);
    border-radius: var(--radius-pill);
    text-transform: none;
    letter-spacing: 0;
}
.delete-confirm-btn:hover,
.delete-group-btn:hover,
.stats-clear-btn:hover {
    background: var(--danger-fill-hover);
    border-color: var(--danger-fill-hover);
}
.delete-btn:hover {
    background: var(--danger-surface);
    color: var(--danger-text);
    border-color: transparent;
}
/* The End Flow confirm uses .delete-btn as its destructive action. */

/* Dialog actions in the small section modals. index.html styles several of
   them by id with a hard-coded #6d28d9 that ignored the Theme setting;
   :is(#id, ...) + the container class out-ranks those rules so the themed
   tokens win. Primary = .create-section-btn, secondary = .cancel-btn,
   destructive = .delete-btn. */
.section-modal:is(#renameFlowModal, #endFlowModal, #groupNamingModal, #groupSkipAlertModal, #customPoseNamingModal) .section-name-input-container .create-section-btn,
.section-modal .section-name-input-container .create-section-btn {
    background: var(--accent-fill);
    color: var(--accent-on);
    border: 0;
    border-radius: var(--radius-pill);
    box-shadow: var(--accent-glow);
}
.section-modal:is(#renameFlowModal, #endFlowModal, #groupNamingModal, #groupSkipAlertModal, #customPoseNamingModal) .section-name-input-container .create-section-btn:hover,
.section-modal .section-name-input-container .create-section-btn:hover {
    background: var(--accent-fill-hover);
    transform: none;
}
.section-modal:is(#endFlowModal) .section-name-input-container .cancel-btn,
.section-modal .section-name-input-container .cancel-btn {
    background: var(--surface-raised);
    color: var(--text-primary);
    border: 1px solid var(--hairline-strong);
    border-radius: var(--radius-pill);
    box-shadow: var(--elev-1);
}
.section-modal:is(#endFlowModal) .section-name-input-container .cancel-btn:hover,
.section-modal .section-name-input-container .cancel-btn:hover {
    background: var(--surface-2);
    transform: none;
    box-shadow: var(--elev-1);
}
.section-modal:is(#endFlowModal) .section-name-input-container .delete-btn,
.section-modal .section-name-input-container .delete-btn {
    background: var(--danger-fill);
    color: #ffffff;
    border: 0;
    border-radius: var(--radius-pill);
    box-shadow: 0 1px 2px rgba(217, 45, 32, 0.24), 0 4px 12px rgba(217, 45, 32, 0.2);
}
.section-modal:is(#endFlowModal) .section-name-input-container .delete-btn:hover,
.section-modal .section-name-input-container .delete-btn:hover {
    background: var(--danger-fill-hover);
    transform: none;
}
.section-modal:is(#renameFlowModal, #endFlowModal, #groupNamingModal, #groupSkipAlertModal, #customPoseNamingModal) .section-name-input-container button:active {
    transform: scale(var(--press-scale, 0.97));
}

/* 4. Chips, inputs, selects, sliders, switches ------------------------------ */
.category-btn,
.build-flow-language,
.gen-seg-btn,
.analysis-toggle-btn,
.day-btn {
    border-color: var(--hairline-strong);
    background: var(--surface-raised);
    color: var(--text-secondary);
}
.category-btn:hover,
.build-flow-language:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}
.category-btn.active,
.gen-seg-btn.active,
.analysis-toggle-btn.active,
.day-btn.active {
    background: var(--accent-fill);
    border-color: var(--accent-fill);
    color: var(--accent-on);
}
.category-btn.active:hover {
    background: var(--accent-fill-hover);
    border-color: var(--accent-fill-hover);
}

input[type="text"],
input[type="search"],
input[type="email"],
input[type="url"],
input[type="number"],
input[type="password"],
textarea,
select {
    caret-color: var(--accent-text);
}
input[type="text"]:focus,
input[type="search"]:focus,
input[type="number"]:focus,
textarea:focus,
select:focus {
    border-color: var(--focus-ring);
    box-shadow: 0 0 0 3px var(--accent-tint-2);
}
::placeholder { color: var(--text-tertiary); opacity: 1; }

.flow-search-field,
.settings-search,
#asanaSearch,
.asana-search-input,
.section-name-input {
    border-radius: var(--radius-md);
}

/* Range: filled track + clean thumb; the thumb keeps a 20 px visual size,
   the input's own height gives the hit area. */
input[type="range"] {
    background: linear-gradient(90deg, var(--accent-tint-3), var(--accent-fill));
    border-radius: var(--radius-pill);
}
input[type="range"]::-webkit-slider-thumb {
    background: var(--switch-thumb);
    border: 0;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06), 0 2px 6px rgba(0, 0, 0, 0.22), inset 0 0 0 6px var(--accent-fill);
    transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
input[type="range"]::-webkit-slider-thumb:hover {
    transform: scale(1.1);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06), 0 3px 10px rgba(0, 0, 0, 0.26), inset 0 0 0 6px var(--accent-fill);
}
input[type="range"]::-moz-range-thumb {
    background: var(--switch-thumb);
    border: 0;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06), 0 2px 6px rgba(0, 0, 0, 0.22), inset 0 0 0 6px var(--accent-fill);
}

/* Switch: iOS-style track in the accent fill, white thumb with a soft shadow. */
.slider {
    background-color: var(--switch-off);
    transition: background-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.slider:before {
    background-color: var(--switch-thumb);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18), 0 2px 6px rgba(0, 0, 0, 0.08);
    transition: transform var(--dur-slow) var(--ease-emph), box-shadow var(--dur-base) var(--ease-out);
}
input:checked + .slider,
.pos-row input:checked + .slider,
.flow-controls-global input:checked + .slider,
.settings-toggle-row input[type="checkbox"]:checked {
    background-color: var(--switch-on);
}
input:checked + .slider:before {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18), 0 2px 6px rgba(0, 0, 0, 0.08);
}
input[type="checkbox"] { accent-color: var(--accent-fill); }

/* 5. Cards and list rows ------------------------------------------------------ */
.flow-item,
.home-continue-body,
.flow-card,
.stats-section-block:not(:empty),
.stats-summary-card,
.dashboard-card {
    background: var(--surface-base);
    border-color: var(--hairline);
    box-shadow: var(--elev-1);
}
.flow-item {
    border-radius: var(--radius-lg);
}
.flow-item.recent {
    border-left-color: var(--accent);
    background-color: var(--surface-base);
}
.flow-info h4,
.home-continue-title {
    letter-spacing: var(--tracking-tight);
}
.flow-description,
.timestamp {
    color: var(--text-secondary);
}

/* Builder list (table) and its rows. */
.flow-table-container {
    border-color: var(--hairline);
    box-shadow: var(--elev-1);
}
#flowTable td {
    border-bottom-color: var(--hairline);
}

/* Pose tiles in the picker: soft hover tint, rounded art tile. */
.asana-item:hover {
    background: var(--accent-tint-1);
}
.asana-item img,
.recommended-inline-item img {
    border-radius: var(--radius-md);
}
.recommended-inline-item {
    border-radius: var(--radius-md);
}

/* Settings rows (W5 index). */
.settings-index-item {
    border-radius: var(--radius-md);
}
.settings-index-item:hover {
    background: var(--surface-2);
}

/* 6. Bars and segmented controls ------------------------------------------- */
.accent-bar {
    background: linear-gradient(90deg, var(--accent), var(--accent-light));
}
#homeScreen > header,
.build-header,
.stats-header,
.feature-header {
    background: var(--surface-bar);
    border-bottom: 1px solid var(--hairline);
}
#homeScreen > header { border-bottom-color: transparent; }
h1 { letter-spacing: 0.12rem; }
.build-header-title,
.stats-header h2,
.feature-header h2,
.create-sheet-title,
.settings-header h2,
.modal h2 {
    letter-spacing: var(--tracking-title);
}

/* Segmented controls (stats type + period tabs). */
.stats-period-tabs {
    background: var(--surface-2);
    border-radius: var(--radius-md);
    box-shadow: inset 0 0 0 1px var(--hairline);
}
.stats-tab.active {
    background: var(--surface-raised);
    color: var(--text-primary);
    box-shadow: var(--elev-1);
}
.stats-type-tab.active {
    background: var(--accent-fill);
    color: var(--accent-on);
}

/* 7. Modals, sheets, scrims ------------------------------------------------- */
.modal,
.settings-modal-overlay,
.breath-picker-overlay {
    background-color: var(--scrim);
}
.create-sheet-backdrop { background: var(--scrim); }

.modal-content,
.settings-panel,
.breath-picker-content,
.create-sheet {
    background-color: var(--surface-overlay);
    box-shadow: var(--elev-4), var(--ring-hairline);
}
.modal-content,
.section-modal .modal-content,
.settings-panel {
    border-radius: var(--radius-xl);
}
.settings-header {
    background: var(--surface-overlay);
    border-top-left-radius: var(--radius-xl);
    border-top-right-radius: var(--radius-xl);
    border-bottom-color: var(--hairline);
}
.section-modal h2 {
    color: var(--text-primary);
}

/* Close glyphs (the "×" text spans): drawn as the icon set's xmark in a
   44 px round hit target, same position. */
.close-modal {
    width: 44px;
    height: 44px;
    top: 8px;
    right: 8px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0;
    line-height: 0;
    color: var(--text-secondary);
    background: transparent;
    border: 0;
    transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.close-modal::before {
    content: "";
    width: 18px;
    height: 18px;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round'%3E%3Cpath d='M18 6 6 18M6 6l12 12'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round'%3E%3Cpath d='M18 6 6 18M6 6l12 12'/%3E%3C/svg%3E") center / contain no-repeat;
}
.close-modal > span { display: none; }
.close-modal:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}
.section-modal .close-modal {
    top: 8px;
    right: 8px;
    font-size: 0;
}

/* Phones get no scrim blur (see §10), so the dim is a little stronger to
   keep the page behind from competing with the dialog. */
@media (max-width: 899px), (hover: none) {
    :root { --scrim: rgba(17, 17, 26, 0.48); }
    html[data-mode="dark"] { --scrim: rgba(0, 0, 0, 0.7); }
}

/* Phones: confirmation and small form dialogs become bottom sheets with a
   rounded top and a grabber (same content, same buttons). */
@media (max-width: 599px) {
    /* margin-top:auto (not align-items:flex-end) pins a short sheet to the
       bottom and still lets a tall one scroll from its top. */
    .modal.section-modal .modal-content,
    #poseDetailModal .modal-content {
        width: 100%;
        max-width: none;
        margin: auto 0 0;
        border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
        padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px));
    }
    .modal.section-modal .modal-content { padding-top: 28px; }
    #poseDetailModal { padding-top: 16px; }
    .modal.section-modal .modal-content::before,
    #poseDetailModal .modal-content::before {
        content: "";
        position: absolute;
        top: 8px;
        left: 50%;
        width: 36px;
        height: 5px;
        margin-left: -18px;
        border-radius: var(--radius-pill);
        background: var(--hairline-strong);
    }
    .create-sheet {
        border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
    }
    /* Settings: a bottom sheet with a grabber on its sticky header. */
    .settings-modal-overlay.active {
        align-items: flex-end !important;
        padding-left: 0;
        padding-right: 0;
        padding-bottom: 0;
    }
    .settings-panel {
        width: 100%;
        max-width: none;
        max-height: min(92vh, 100%);
        max-height: min(92dvh, 100%);
        border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }
    .settings-header {
        border-top-left-radius: var(--radius-2xl);
        border-top-right-radius: var(--radius-2xl);
    }
    .settings-header::before {
        content: "";
        position: absolute;
        top: 6px;
        left: 50%;
        width: 36px;
        height: 5px;
        margin-left: -18px;
        border-radius: var(--radius-pill);
        background: var(--hairline-strong);
    }
}

/* 8. Toasts, empty states, skeletons, icons --------------------------------- */
.toast-notification,
.achievement-banner,
.builder-history-toast {
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-3);
}
.achievement-banner {
    background: var(--surface-overlay);
    border: 1px solid var(--hairline);
}
.achievement-banner-icon {
    border-radius: var(--radius-md);
    color: #1d1d1f;
    font-variant-numeric: tabular-nums;
}
.toast-notification span::before {
    background-color: var(--accent-light);
}

.stats-empty,
.empty-message {
    color: var(--text-secondary);
}
.stats-empty h3,
.empty-message h3 {
    color: var(--text-primary);
    letter-spacing: var(--tracking-tight);
}
.stats-empty-icon {
    width: 64px;
    height: 64px;
    margin-left: auto;
    margin-right: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--accent-tint-1);
    color: var(--accent-text);
}

/* Skeleton loader: a reusable class + the pose-art tile behind lazy
   thumbnails (#35 keeps loading them lazily; this only paints the tile). */
.fb-skeleton {
    background: linear-gradient(90deg, var(--surface-2) 0%, var(--surface-3) 50%, var(--surface-2) 100%);
    background-size: 200% 100%;
    border-radius: var(--radius-sm);
    animation: fbSkeleton 1.4s ease-in-out infinite;
}
@keyframes fbSkeleton {
    from { background-position: 100% 0; }
    to { background-position: -100% 0; }
}

/* Insights "Pose of the Day" skeleton (dashboard.css, loaded later, hence
   the html prefix): the same shimmer + surface tokens, readable in dark mode
   (its rgba(0,0,0,.07) fill was invisible on black). */
html .fbdb-skeleton .fbdb-daily-img,
html .fbdb-skeleton .fbdb-daily-name,
html .fbdb-skeleton .fbdb-daily-sub {
    background: linear-gradient(90deg, var(--surface-2) 0%, var(--surface-3) 50%, var(--surface-2) 100%);
    background-size: 200% 100%;
    animation: fbSkeleton 1.4s ease-in-out infinite;
}

/* Icons: sprite icons are 24-grid strokes (2 px). No vertical-align change:
   in inline contexts it resized the buttons around them (the builder view
   toggles that the tour highlights shrank by 3 px). */
.fb-icon {
    overflow: visible;
}

/* 9. Motion ------------------------------------------------------------------- */
/* Press: every button-like control scales on the W1 press tokens. */
.flow-btn:active,
.settings-action-btn:active,
.cancel-btn:active,
.delete-confirm-btn:active,
.category-btn:active,
.stats-tab:active,
.stats-type-tab:active,
.close-modal:active,
.flow-item:active {
    transform: scale(var(--press-scale, 0.97));
    transition-duration: var(--dur-press, 120ms);
}

/* Hover lift on cards: desktop (hover + fine pointer) only. */
.flow-item {
    transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out),
        border-color var(--dur-base) var(--ease-out), background-color var(--dur-base) var(--ease-out);
}
.flow-item:hover {
    transform: none;
    box-shadow: var(--elev-1);
    border-color: var(--hairline);
}
@media (hover: hover) and (pointer: fine) {
    .flow-item:hover,
    .home-continue-body:hover,
    .create-tile:hover {
        transform: translateY(var(--lift));
        box-shadow: var(--elev-3);
        border-color: var(--hairline-strong);
    }
    .home-continue-body {
        transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
    }
    .flow-item:active { transform: translateY(var(--lift)) scale(var(--press-scale, 0.97)); }
}

/* List insert: home flow cards rise in once (stagger via --i if set). */
.flow-item {
    /* backwards, not both: a finished animation that still fills would keep
       overriding transform, killing the hover lift and the press scale. */
    animation: fbListIn var(--dur-slow) var(--ease-out) backwards;
}
@keyframes fbListIn {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
}

/* List remove: FB.motion.animateOut() adds this, then re-renders. */
.fb-anim-out {
    animation: fbListOut var(--dur-base) var(--ease-std) forwards !important;
    pointer-events: none;
}
@keyframes fbListOut {
    from { opacity: 1; transform: none; }
    to { opacity: 0; transform: scale(0.96); }
}

/* Modal enter/exit. Enter: @starting-style; exit: JS sets inline
   display:none, which keeps the box painted for the fade with
   allow-discrete. Browsers without these features simply show/hide. */
.modal {
    transition: opacity var(--dur-base) var(--ease-out),
        display var(--dur-base) allow-discrete, overlay var(--dur-base) allow-discrete;
}
.modal[style*="display: none"] {
    opacity: 0;
    pointer-events: none;
}
.modal .modal-content {
    animation: none;
    transition: transform var(--dur-slow) var(--ease-emph), opacity var(--dur-base) var(--ease-out);
}
.modal[style*="display: none"] .modal-content {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
}
@starting-style {
    .modal { opacity: 0; }
    .modal .modal-content { opacity: 0; transform: translateY(8px) scale(0.98); }
}
@media (max-width: 599px) {
    .modal.section-modal[style*="display: none"] .modal-content,
    #poseDetailModal[style*="display: none"] .modal-content { transform: translateY(100%); opacity: 1; }
    @starting-style {
        .modal.section-modal .modal-content,
        #poseDetailModal .modal-content { transform: translateY(100%); opacity: 1; }
    }
}

.settings-modal-overlay,
.breath-picker-overlay {
    animation: overlayFadeIn var(--dur-base) var(--ease-out);
}
.settings-panel,
.breath-picker-content,
.pose-detail-content {
    animation: fbModalIn var(--dur-slow) var(--ease-emph);
}
@keyframes fbModalIn {
    from { opacity: 0; transform: translateY(10px) scale(0.98); }
    to { opacity: 1; transform: none; }
}

/* 10. Perf guards + Reduce Motion -------------------------------------------- */
/* Full-screen scrims: blur only on wide, hover-capable screens. On phones the
   page behind is a long list (and low-end GPUs re-blur it every frame), so
   the scrim is a plain dim. */
.modal,
.settings-modal-overlay {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}
@media (min-width: 900px) and (hover: hover) and (pointer: fine) {
    .modal,
    .settings-modal-overlay,
    .create-sheet-backdrop {
        -webkit-backdrop-filter: blur(8px);
        backdrop-filter: blur(8px);
    }
}
/* No backdrop blur on the sticky builder header: index.html's inline
   .build-header background (opaque --surface) wins over --surface-bar, so a
   blur there cost a re-blur of the scrolling pose table on every frame
   (iPad included) and showed nothing. */

@media (prefers-reduced-motion: reduce) {
    .flow-item,
    .home-continue-body,
    .create-tile {
        animation: none;
    }
    .flow-item:hover,
    .home-continue-body:hover,
    .create-tile:hover,
    .flow-item:active,
    .flow-btn:active,
    .settings-action-btn:active,
    .cancel-btn:active,
    .delete-confirm-btn:active,
    .category-btn:active,
    .stats-tab:active,
    .stats-type-tab:active,
    .close-modal:active {
        transform: none !important;
    }
    .modal,
    .modal .modal-content,
    .slider,
    .slider:before {
        transition: none;
    }
    .modal[style*="display: none"] .modal-content { transform: none; }
    .settings-modal-overlay,
    .breath-picker-overlay,
    .settings-panel,
    .breath-picker-content,
    .pose-detail-content,
    .fb-skeleton,
    html .fbdb-skeleton .fbdb-daily-img,
    html .fbdb-skeleton .fbdb-daily-name,
    html .fbdb-skeleton .fbdb-daily-sub {
        animation: none;
    }
    .section-modal .section-name-input-container button:active {
        transform: none !important;
    }
}
html[data-reduce-motion] .flow-item,
html[data-reduce-motion] .home-continue-body,
html[data-reduce-motion] .create-tile,
html[data-reduce-motion] .settings-modal-overlay,
html[data-reduce-motion] .breath-picker-overlay,
html[data-reduce-motion] .settings-panel,
html[data-reduce-motion] .breath-picker-content,
html[data-reduce-motion] .pose-detail-content,
html[data-reduce-motion] .fb-skeleton,
html[data-reduce-motion] .fbdb-skeleton .fbdb-daily-img,
html[data-reduce-motion] .fbdb-skeleton .fbdb-daily-name,
html[data-reduce-motion] .fbdb-skeleton .fbdb-daily-sub {
    animation: none;
}
html[data-reduce-motion] .section-modal .section-name-input-container button:active {
    transform: none !important;
}
html[data-reduce-motion] .flow-item:hover,
html[data-reduce-motion] .home-continue-body:hover,
html[data-reduce-motion] .create-tile:hover,
html[data-reduce-motion] .flow-item:active,
html[data-reduce-motion] .flow-btn:active,
html[data-reduce-motion] .settings-action-btn:active,
html[data-reduce-motion] .cancel-btn:active,
html[data-reduce-motion] .delete-confirm-btn:active,
html[data-reduce-motion] .category-btn:active,
html[data-reduce-motion] .stats-tab:active,
html[data-reduce-motion] .stats-type-tab:active,
html[data-reduce-motion] .close-modal:active {
    transform: none !important;
}
html[data-reduce-motion] .modal,
html[data-reduce-motion] .modal .modal-content,
html[data-reduce-motion] .slider,
html[data-reduce-motion] .slider:before,
html[data-reduce-motion] .flow-item {
    transition: none;
}
html[data-reduce-motion] .modal[style*="display: none"] .modal-content { transform: none; }

/* 11. Generator + Text-to-Flow (streamlined) ---------------------------------
   Generator: three main choices, a "More options" disclosure and a sticky
   Generate bar (visible without scrolling on a phone). Builder: the result bar
   (▶ Play + Regenerate) under the title of a just-made flow. Text-to-Flow:
   live status line + one Create button. */
.gen-main {
    padding-bottom: 0;
}
.gen-more {
    margin: var(--space-1) 0 var(--space-4);
    border: 1px solid var(--hairline-strong);
    border-radius: var(--radius-card);
    background: var(--surface-raised);
}
.gen-more-toggle {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    min-height: 48px;
    padding: var(--space-3) var(--space-4);
    border: 0;
    border-radius: var(--radius-card);
    background: transparent;
    color: var(--text-primary);
    font: inherit;
    font-size: var(--fs-md);
    font-weight: var(--fw-semibold);
    text-align: left;
    cursor: pointer;
}
.gen-more-label { flex: 0 0 auto; }
.gen-more-summary {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--text-secondary);
    font-weight: var(--fw-regular);
    font-size: var(--fs-sm);
    text-align: right;
}
.gen-more-chevron {
    flex: 0 0 auto;
    color: var(--text-secondary);
    transition: transform var(--dur-settle, 240ms) var(--ease-std, ease);
}
.gen-more-toggle[aria-expanded="true"] .gen-more-chevron { transform: rotate(180deg); }
.gen-more-panel {
    padding: var(--space-1) var(--space-4) var(--space-2);
    border-top: 1px solid var(--hairline);
}
.gen-more-panel[hidden] { display: none; }
.gen-more-panel .gen-section:first-child { margin-top: var(--space-3); }
.gen-generate-bar {
    position: sticky;
    bottom: 0;
    z-index: 5;
    margin: 0 -20px;
    padding: var(--space-3) 20px calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
    background: linear-gradient(to bottom, transparent, var(--surface-page, var(--bg-app)) 30%);
}
.gen-generate-bar .feature-begin-btn { margin-top: 0; }
@media (max-width: 600px) {
    .gen-generate-bar { margin: 0 -12px; padding-left: 12px; padding-right: 12px; }
}

.flow-result-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin: var(--space-2) 0 var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--accent-tint-2, var(--hairline-strong));
    border-radius: var(--radius-card);
    background: var(--accent-tint-1, var(--surface-raised));
}
.flow-result-bar[hidden] { display: none; }
.flow-result-text {
    flex: 1 1 140px;
    margin: 0;
    color: var(--text-primary);
    font-size: var(--fs-md);
    font-weight: var(--fw-semibold);
}
.flow-result-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.flow-result-bar .flow-result-play {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: auto;
    min-height: 44px;
    margin: 0;
    padding: 10px 22px;
    font-size: var(--fs-base);
}
.flow-result-regen,
.flow-result-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 44px;
    border: 1px solid var(--hairline-strong);
    border-radius: var(--radius-pill);
    background: var(--surface-raised);
    color: var(--accent-text);
    font: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-semibold);
    cursor: pointer;
}
.flow-result-regen { padding: 8px 14px; }
.flow-result-regen[hidden] { display: none; }
.flow-result-close {
    width: 44px;
    padding: 0;
    color: var(--text-secondary);
}

.ttf-status {
    margin: var(--space-2) 0 0;
    color: var(--text-secondary);
    font-size: var(--fs-sm);
}
.ttf-status.ttf-status-empty { color: var(--danger-ink, var(--text-primary)); font-weight: var(--fw-semibold); }
.ttf-results { margin-top: var(--space-3); }
.feature-begin-btn.ttf-create-btn { margin-top: var(--space-3); }
.feature-begin-btn:disabled {
    opacity: 0.45;
    box-shadow: none;
    cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
    .gen-more-chevron { transition: none; }
}
html[data-reduce-motion] .gen-more-chevron { transition: none; }

/* Streamline WS2: Home rows. ▶ Play (an icon on phones, "▶ Play" on wider
   screens) and a visible ⋯ that opens the row menu; the Edit and Delete
   icons moved into that menu. */
.flow-item .flow-actions { gap: var(--space-2, 8px); }
.flow-item .flow-more-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--text-secondary);
    flex: 0 0 auto;
}
.flow-item .flow-more-btn:hover,
.flow-item .flow-more-btn[aria-expanded="true"] {
    background: var(--surface-2);
    color: var(--text-primary);
}
.flow-item .flow-btn {
    min-height: 44px;
    padding: 0 18px;
    justify-content: center;
    text-transform: none;
    letter-spacing: 0;
}
.flow-item .flow-btn::before { width: 12px; height: 12px; }
@media screen and (max-width: 768px) {
    .flow-item .flow-btn {
        width: 44px;
        padding: 0;
        border-radius: 50%;
    }
    .flow-item .flow-btn::before { width: 16px; height: 16px; margin-left: 2px; }
    .flow-item .flow-btn .flow-btn-label {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }
}

/* Row and builder ⋯ menus: real buttons (keyboard + screen readers). */
.flow-row-menu .context-menu-item {
    display: block;
    width: 100%;
    min-height: 40px;
    border: 0;
    background: transparent;
    font: inherit;
    font-size: var(--fs-sm, 14px);
    text-align: start;
}
.flow-row-menu .context-menu-item[hidden] { display: none; }
.flow-row-menu .context-menu-item:focus-visible {
    outline: var(--focus-ring-width, 2px) solid var(--focus-ring, var(--accent));
    outline-offset: -2px;
}
@media (pointer: coarse) {
    .flow-row-menu .context-menu-item { min-height: 44px; }
}

/* Toasts with an action on Home, and achievement banners, sit at the bottom
   (above the + button on phones) so they never cover the header buttons. */
.builder-history-toast.home-action-toast {
    top: auto;
    bottom: calc(24px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%) translateY(60px);
}
.builder-history-toast.home-action-toast.show { transform: translateX(-50%) translateY(0); }
.achievement-banner {
    top: auto;
    bottom: -160px;
    transition: bottom 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.achievement-banner.show { top: auto; bottom: calc(24px + env(safe-area-inset-bottom, 0px)); }
@media screen and (max-width: 768px) {
    .builder-history-toast.home-action-toast,
    .achievement-banner.show { bottom: calc(84px + env(safe-area-inset-bottom, 0px)); }
    .achievement-banner { max-width: calc(100vw - 32px); box-sizing: border-box; }
}
@media (prefers-reduced-motion: reduce) {
    .achievement-banner { transition: none; }
}
html[data-reduce-motion] .achievement-banner { transition: none; }
