/* Ijek (Train With Myself) — styles extracted from train.html.
   Edit here, not inline. Shipped by build-deploy.js, precached by sw.js. */
  :root {
    --bg: #0b1220;
    --surface: #131c2e;
    --surface-2: #1a2540;
    --border: #243149;
    --border-strong: #364463;
    --text: #f1f5f9;
    --text-muted: #94a3b8;
    --text-dim: #7a8fa6; /* was #64748b — bumped for WCAG AA (~4.6:1 on --bg, was ~3.9:1); fixes 30+ dim-text selectors at once */
    --accent: #a3e635;
    --accent-hover: #bef264;
    --accent-rgb: 163,230,53;     /* accent as raw RGB for rgba() soft tints; themed by applyTheme */
    --accent-text: #0b1220;
    /* "You / the gap" race color — distinct from --accent so You-vs-committed-self stays
       readable. Themed in pairs by applyTheme (amber for cool themes, sky for warm ones). */
    --you: #fbbf24;
    --you-rgb: 251,191,36;
    --danger: #f87171;
    --radius: 14px;
    --nav-h: 76px;
    --header-h: 56px;
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --app-max: 480px;
  }

  * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
  /* This is an installed app, not a webpage — a long-press on any image should never pop the
     native "save / copy image" callout or a drag ghost (that solid highlight the user saw). */
  img { -webkit-touch-callout: none; -webkit-user-drag: none; user-select: none; -webkit-user-select: none; }
  html, body { margin: 0; padding: 0; height: 100%; overscroll-behavior: none; }
  body {
    background: #05080f;
    color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    -webkit-font-smoothing: antialiased;
    font-size: 15px;
    line-height: 1.4;
    overflow: hidden;
  }

  #root {
    position: fixed;
    inset: 0;
    display: flex;
    justify-content: center;
    background: #05080f;
  }

  .app {
    width: 100%;
    max-width: var(--app-max);
    height: 100%;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    position: relative;
    overflow: hidden;
  }

  @media (min-width: 520px) {
    .app {
      box-shadow: 0 30px 80px rgba(0,0,0,0.55), 0 0 0 1px var(--border);
      border-radius: 28px;
      /* Was overflow:hidden. A *rounded* clip over the scrolling .app-main forces Edge/Chrome
         off the composited fast-scroll path → the content re-rasterizes every frame, which is
         the jitter on hard scroll. Let .app overflow (its box-shadow ring stays rounded) and
         round the header/nav corners instead, so no rounded clip ever sits over the scroller. */
      overflow: visible;
      margin: 24px 0;
      max-height: calc(100% - 48px);
    }
    .app-header { border-radius: 28px 28px 0 0; }
    .bottom-nav { border-radius: 0 0 28px 28px; }
  }

  .app-header {
    flex: 0 0 auto;
    padding: calc(var(--safe-top) + 14px) 20px 12px;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    z-index: 4;
    position: relative;
  }
  /* Undo / redo control, pinned to the header's top-right. */
  .hist-ctrl { position: absolute; top: calc(var(--safe-top) + 12px); right: 16px; display: flex; gap: 8px; }
  .hist-btn { width: 34px; height: 34px; border-radius: 10px; border: 1px solid var(--border); background: var(--card); color: var(--text); font-size: 17px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; }
  .hist-btn:active { transform: scale(0.93); }
  .hist-btn:disabled { opacity: 0.32; cursor: default; }
  .brand { display: flex; align-items: center; gap: 10px; min-width: 0; padding-right: 90px; }
  .brand-mark { height: 20px; width: auto; display: block; flex-shrink: 0; }
  .brand-text { font-size: 17px; font-weight: 700; letter-spacing: -0.01em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .brand-sub {
    padding-right: 90px;
    margin-top: 4px;
    font-size: 11px;
    color: var(--text-muted);
    letter-spacing: 0.06em;
    text-transform: lowercase;
  }

  .app-main {
    flex: 1;
    min-height: 0;
    /* `scroll` (not `auto`) keeps the scrollbar track in a CONSTANT state so it can't blink
       in/out across a tab/content swap (a Chromium quirk with auto + scrollbar-gutter). The
       gutter is already reserved below, so this adds no width — only a constant (transparent)
       track. The thumb still appears only when there's something to scroll. */
    overflow-y: scroll;
    overflow-x: hidden;
    /* Always reserve the scrollbar's gutter so the page width doesn't jump when content
       shrinks past the viewport (e.g. deleting a sticker removes the scrollbar). */
    scrollbar-gutter: stable;
    padding: 16px 14px 24px; /* nav is an in-flow sibling below, so no nav-h reserve needed */
  }
  /* Schedule fills the screen so only the calendar scrolls (one scrollbar). */
  .app-main.is-schedule {
    display: flex; flex-direction: column;
    /* Symmetric 14px sides — SAME as the normal .app-main. scrollbar-gutter:stable (inherited from
       the base rule) still reserves the 10px gutter even though this screen is overflow:hidden
       (overflow:hidden is still a scroll container), so usable width — and the Day|Week toggle —
       already matches the Progress page. (An earlier +10px right padding over-compensated and made
       the toggle 5px narrower than Progress — confirmed via on-screen measurement.) */
    overflow: hidden; padding: 14px 14px 12px;
  }
  .app-main.is-schedule .sched-screen { flex: 1; min-height: 0; }

  /* Slim, themed scrollbar */
  .app-main, .tl-scroll, .wg-scroll, .billing-body, .sheet-body { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
  .app-main::-webkit-scrollbar, .tl-scroll::-webkit-scrollbar, .wg-scroll::-webkit-scrollbar, .billing-body::-webkit-scrollbar, .sheet-body::-webkit-scrollbar { width: 10px; }
  .app-main::-webkit-scrollbar-track, .tl-scroll::-webkit-scrollbar-track, .wg-scroll::-webkit-scrollbar-track, .billing-body::-webkit-scrollbar-track, .sheet-body::-webkit-scrollbar-track { background: transparent; }
  .app-main::-webkit-scrollbar-thumb, .tl-scroll::-webkit-scrollbar-thumb, .wg-scroll::-webkit-scrollbar-thumb, .billing-body::-webkit-scrollbar-thumb, .sheet-body::-webkit-scrollbar-thumb {
    background: var(--border-strong); border-radius: 999px;
    border: 3px solid var(--bg); background-clip: padding-box;
  }
  .tl-scroll::-webkit-scrollbar-thumb, .wg-scroll::-webkit-scrollbar-thumb, .sheet-body::-webkit-scrollbar-thumb { border-color: var(--surface); }
  .app-main::-webkit-scrollbar-thumb:hover, .tl-scroll::-webkit-scrollbar-thumb:hover, .billing-body::-webkit-scrollbar-thumb:hover, .sheet-body::-webkit-scrollbar-thumb:hover { background: var(--text-dim); background-clip: padding-box; }
  /* To-Do sheet body was missing from the group above → showed the fat native scrollbar. Same
     slim themed bar; its container bg is --surface, so the thumb border matches that (not --bg). */
  .todo-sheet-body { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
  .todo-sheet-body::-webkit-scrollbar { width: 10px; }
  .todo-sheet-body::-webkit-scrollbar-track { background: transparent; }
  .todo-sheet-body::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; border: 3px solid var(--surface); background-clip: padding-box; }
  .todo-sheet-body::-webkit-scrollbar-thumb:hover { background: var(--text-dim); background-clip: padding-box; }

  .empty {
    margin-top: 12vh;
    text-align: center;
    padding: 0 20px;
  }
  .empty-mark { font-size: 40px; color: var(--accent); margin-bottom: 14px; line-height: 1; }
  .empty-title { font-size: 22px; margin: 0 0 6px; font-weight: 700; }
  .empty-sub { color: var(--text-muted); margin: 0 0 22px; font-size: 14px; }

  .btn-primary {
    background: var(--accent);
    color: var(--accent-text);
    border: 0;
    border-radius: 10px;
    padding: 11px 18px;
    font: inherit;
    font-weight: 700;
    cursor: pointer;
    min-height: 44px;
    touch-action: manipulation;
  }
  .btn-primary:active:not(:disabled) { background: var(--accent-hover); }
  .btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }

  .btn-ghost {
    background: transparent;
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: 10px;
    padding: 11px 16px;
    cursor: pointer;
    font: inherit;
    min-height: 44px;
    touch-action: manipulation;
  }
  .btn-ghost:active { background: var(--surface-2); }
  .btn-block { width: 100%; margin-top: 14px; padding: 14px; }

  .bottom-nav {
    flex: 0 0 auto;
    position: relative;
    display: flex;
    background: var(--surface);
    border-top: 1px solid var(--border);
    padding-bottom: var(--safe-bottom);
    z-index: 6;
  }
  .bottom-nav-btn {
    flex: 1; min-width: 0;
    height: var(--nav-h);
    background: transparent;
    border: 0;
    color: var(--text-dim);
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    touch-action: manipulation;
    /* iPadOS/iOS treats a big emoji as an image: a long-press fires the native
       "Save to Photos / Share / Copy" callout. Suppress it so the nav behaves like
       desktop — no save-emoji menu, no text selection on the label. */
    -webkit-touch-callout: none;
    -webkit-user-select: none; user-select: none;
  }
  .bottom-nav-icon { -webkit-user-drag: none; }
  .bottom-nav-btn span:last-child { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .bottom-nav-btn.is-active { color: var(--accent); }
  .bottom-nav-icon {
    font-size: 25px;
    line-height: 1;
    position: relative; /* anchor for the ★ home-tab badge */
  }
  /* SVG nav icons (cross-platform identical) — explicit size, inherits the btn's color via currentColor. */
  .bottom-nav-icon svg { display: block; width: 24px; height: 24px; }
  /* ★ badge on the chosen landing tab (Settings › Start on). Sits at the icon's top-right, always
     in the accent color (even on inactive tabs) so "this is your home page" reads at a glance. */
  .bottom-nav-star {
    position: absolute; top: -5px; right: -7px;
    font-size: 11px; line-height: 1; color: var(--accent);
    text-shadow: 0 0 2px var(--bg, rgba(0,0,0,0.6));
    pointer-events: none;
  }

  /* Settings › Start on — a mini toolbar: each tab as an icon+label tile, selected one in the
     accent with the ★ badge (reuses .bottom-nav-star). Reads as "point at the nav you want". */
  .set-starton-row { display: flex; gap: 6px; }
  .set-starton-btn {
    flex: 1; min-width: 0;
    display: flex; flex-direction: column; align-items: center; gap: 5px;
    padding: 12px 4px; border-radius: 12px;
    background: var(--surface); border: 1px solid var(--border);
    color: var(--text-muted); cursor: pointer;
    transition: color .15s, border-color .15s, background .15s;
  }
  .set-starton-btn.on {
    color: var(--accent); border-color: var(--accent);
    background: rgba(var(--accent-rgb), 0.08);
  }
  .set-starton-btn:active { transform: scale(0.97); }
  .set-starton-icon { position: relative; font-size: 25px; line-height: 1; }
  .set-starton-icon svg { display: block; width: 24px; height: 24px; }
  .set-starton-label {
    font-size: 11px; font-weight: 600; line-height: 1;
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  .sheet-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    animation: fadeIn 0.18s ease-out;
    z-index: 50;
  }
  .sheet-backdrop.l2 { z-index: 70; background: rgba(0, 0, 0, 0.42); }
  .sheet {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--surface);
    border-top: 1px solid var(--border-strong);
    border-radius: 22px 22px 0 0;
    max-height: 94%;
    display: flex;
    flex-direction: column;
    z-index: 60;
    animation: slideUp 0.22s ease-out;
    padding-bottom: var(--safe-bottom);
  }
  .sheet.l2 { z-index: 80; max-height: 90%; }
  /* GCal-style "this day vs every week" chooser — sits above the BlockSheet (z-index 60/80). */
  .scope-ask-backdrop { position: fixed; inset: 0; z-index: 9990; background: rgba(0,0,0,0.5);
    display: flex; align-items: center; justify-content: center; padding: 24px; animation: fadeIn 0.12s ease; }
  .scope-ask { width: 100%; max-width: 320px; background: var(--surface-2); border: 1px solid var(--border);
    border-radius: 18px; padding: 18px; box-shadow: 0 18px 48px rgba(0,0,0,0.55);
    display: flex; flex-direction: column; gap: 10px; }
  .scope-ask-title { font-weight: 700; font-size: 15px; text-align: center; margin-bottom: 4px; }
  .scope-ask-cancel { background: none; border: none; color: var(--text-dim); font-size: 14px; padding: 6px; cursor: pointer; }
  .scope-ask-danger { background: rgba(248,113,113,0.12); border: 1px solid var(--danger); color: var(--danger); }
  /* Inline "delete scope" in the block editor (replaces the old one-button → popup): a small label
     over a compact pair of danger buttons — "just this one" (light) vs the whole weekly plan (strong). */
  .blk-del-split { margin-top: 20px; display: flex; flex-direction: column; gap: 8px; }
  .blk-del-label { font-size: 11px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); }
  /* Exactly the app's .btn-ghost.btn-block delete button (centered red label, neutral border) —
     just two of them stacked for the two scopes. Override btn-block's top margin; gap spaces them. */
  .blk-del-opt { margin-top: 0; color: var(--danger); }
  @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
  @keyframes slideUp { from { transform: translateY(100%); } to { transform: translateY(0); } }

  .sheet-grabber {
    width: 40px; height: 4px;
    background: var(--border-strong);
    border-radius: 2px;
    margin: 8px auto 0;
  }

  .sheet-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 12px 12px;
    border-bottom: 1px solid var(--border);
    gap: 10px;
  }
  .sheet-title { font-weight: 600; font-size: 15px; }
  .sheet-body { padding: 16px; overflow-y: auto; flex: 1; }
  .input-underline {
    display: block;
    width: 100%;
    background: transparent;
    color: var(--text);
    border: 0;
    border-bottom: 1px solid var(--border);
    padding: 12px 0;
    font: inherit;
    outline: none;
    margin-bottom: 12px;
    border-radius: 0;
  }
  .input-underline::placeholder { color: var(--text-dim); }
  .input-underline:focus { border-bottom-color: var(--accent); }
  /* iOS Safari auto-zooms the whole page when a focused field's text is < 16px.
     user-scalable=no does NOT suppress this, so guarantee 16px on touch devices.
     (Desktop keeps the smaller, denser sizes.) */
  @media (pointer: coarse) {
    .input-underline, .emoji-search-input, .day-mini-input, .amt-unit,
    .custom-text-input, .set-name-input, .tl2-amt-input,
    textarea, input[type="text"], input[type="email"],
    input[type="number"], input[type="search"], input[type="password"] { font-size: 16px; }
  }
  .input-large { font-size: 22px; font-weight: 600; }
  textarea.input-underline { resize: vertical; line-height: 1.5; }
  /* Keyboard focus ring — visible only for keyboard / assistive-tech users (focus-visible),
     never on mouse/touch. Previously there was NO focus indicator at all. */
  /* NOTE: do NOT set border-radius here — it overrides each element's own radius (a 10px-rounded
     task card would square down to the focus value, "popping" a sharp rectangle). Modern browsers
     already round the outline to follow the element's own border-radius. */
  :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  /* Underline inputs already signal focus via an accent border-bottom — the rectangle
     outline boxes them in and looks unstyled. Suppress it so only the underline shows. */
  .input-underline:focus-visible { outline: none; }
  /* Kill the browser autofill white box — keep the dark theme on paste/autofill. */
  .input-underline:-webkit-autofill,
  .input-underline:-webkit-autofill:hover,
  .input-underline:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--text);
    -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
    box-shadow: 0 0 0 1000px var(--surface) inset;
    caret-color: var(--text);
    transition: background-color 9999s ease 0s;
  }
  /* Button loading spinner */
  .btn-spin { display: inline-block; width: 17px; height: 17px; vertical-align: middle;
    border: 2px solid rgba(11,18,32,0.25); border-top-color: #0b1220; border-radius: 50%;
    animation: btn-spin 0.6s linear infinite; }
  @keyframes btn-spin { to { transform: rotate(360deg); } }

  .section-label {
    text-transform: uppercase;
    letter-spacing: 0.1em;
    font-size: 11px;
    color: var(--text-dim);
    margin: 22px 0 10px;
    font-weight: 600;
  }

  /* --- Activity / Schedule screens --- */
  .activity-screen {
    display: flex; flex-direction: column; gap: 12px;
  }
  .race-setup-label {
    font-size: 12px; font-weight: 600; color: var(--text-muted);
    text-transform: uppercase; letter-spacing: 0.04em;
    margin: 20px 0 8px;
  }
  .race-setup-explain {
    font-size: 12px; color: var(--text-muted);
    margin-top: 12px; line-height: 1.55;
    font-variant-numeric: tabular-nums;
  }

  .act-list { display: flex; flex-direction: column; gap: 10px; }
  .act-card {
    display: flex; align-items: center; gap: 11px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 9px 12px;
  }
  .act-card.is-running { border-color: rgba(var(--accent-rgb), 0.5); background: rgba(var(--accent-rgb), 0.06); }
  /* Hold-then-drag reorder: held card lifts, others slide to open the drop gap. */
  .act-card.shift { transition: transform 0.16s ease; }
  .act-card.armed { position: relative; z-index: 4; transform: scale(1.015); touch-action: none;
    user-select: none; -webkit-user-select: none;
    box-shadow: 0 6px 18px rgba(0,0,0,0.4); transition: transform 0.12s ease, box-shadow 0.12s ease; }
  .act-card.dragging { position: relative; z-index: 6; touch-action: none; user-select: none; -webkit-user-select: none; cursor: grabbing;
    border-color: var(--accent); box-shadow: 0 12px 28px rgba(0,0,0,0.55); opacity: 0.97; }
  .act-card-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
  .act-card-emoji {
    flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%;
    background: var(--surface-2); border: 2px solid var(--border);
    display: flex; align-items: center; justify-content: center;
    font-size: 17px; line-height: 1;
  }
  .act-card-info { flex: 1; min-width: 0; }
  .act-card-name { font-weight: 600; font-size: 15px; display: flex; align-items: center; gap: 7px; min-width: 0; }
  .act-card-name-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
  .act-hobby-pill { flex-shrink: 0; font-size: 10px; font-weight: 800; letter-spacing: 0.03em; color: #7dd3fc;
    background: rgba(56,189,248,0.12); border: 1px solid rgba(56,189,248,0.35); border-radius: 999px; padding: 2px 7px; }
  .act-card-tag {
    margin-left: 7px; font-size: 10px; font-weight: 800; vertical-align: 1px;
    color: #7dd3fc; background: rgba(56,189,248,0.14); border: 1px solid rgba(56,189,248,0.4);
    border-radius: 999px; padding: 1px 7px; white-space: nowrap;
  }
  .act-card-sub {
    display: flex; gap: 12px; margin-top: 4px; flex-wrap: wrap;
    font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums;
  }
  .act-card-sub .v { color: var(--text); font-weight: 700; }
  .act-color-row { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 4px; }
  .act-color-swatch {
    width: 34px; height: 34px; border-radius: 50%;
    border: 2px solid transparent; cursor: pointer; padding: 0;
    touch-action: manipulation;
  }
  .act-color-swatch.on { border-color: var(--text); box-shadow: 0 0 0 2px var(--bg) inset; }
  .emoji-pick-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
  .emoji-opt {
    width: 42px; height: 42px; border-radius: 12px;
    background: var(--surface-2); border: 1px solid var(--border);
    font-size: 22px; line-height: 1; cursor: pointer; padding: 0;
    display: flex; align-items: center; justify-content: center;
    touch-action: manipulation;
  }
  .emoji-opt.on { border-color: var(--accent); background: rgba(var(--accent-rgb),0.16); }
  /* "Use your own image/GIF" — a LABELLED row under the Suggested emojis (a bare 🔒 cell just looked like
     a mystery "block" button). Dashed accent = clearly an action; locked variant shows a PRO tag. */
  .emoji-useown { display: flex; align-items: center; gap: 8px; width: 100%; margin: 8px 0 2px; padding: 9px 12px;
    border-radius: 12px; border: 1px dashed var(--accent); background: rgba(var(--accent-rgb),0.06); color: var(--text);
    font-size: 13px; font-weight: 700; cursor: pointer; transition: background .14s ease; }
  .emoji-useown:hover { background: rgba(var(--accent-rgb),0.12); }
  .emoji-useown.locked { border-color: var(--border-strong); background: var(--surface-2); }
  .emoji-useown-ic { font-size: 16px; line-height: 1; }
  .emoji-useown-txt { flex: 1; text-align: left; }
  .emoji-useown-pro { font-size: 10px; font-weight: 800; color: var(--accent); letter-spacing: 0.04em; }
  .emoji-more { color: var(--text-muted); font-weight: 700; border-style: dashed; }
  /* Saved PHOTO cell in the picker — fill & round-crop the data-URL image to the cell. */
  .emoji-photo-cell { overflow: hidden; }
  .emoji-photo-cell .emoji-png { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
  /* Saved emoji cells (in the ＋ picker) carry a × remove badge — mirrors the avatar's saved photos. */
  .emoji-opt-wrap { position: relative; display: inline-flex; }
  .emoji-rm {
    position: absolute; top: -5px; right: -5px; z-index: 2;
    width: 18px; height: 18px; border-radius: 50%; padding: 0; line-height: 1;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface-2); color: var(--text-muted);
    border: 1px solid var(--border-strong); font-size: 13px; cursor: pointer;
    opacity: 0; transition: opacity 0.14s ease, color 0.14s ease, transform 0.1s ease;
  }
  .emoji-opt-wrap:hover .emoji-rm, .emoji-rm:focus-visible { opacity: 1; }
  .emoji-rm:hover { color: #ef4444; border-color: #ef4444; }
  .emoji-rm:active { transform: scale(0.85); }
  @media (hover: none) { .emoji-rm { opacity: 1; } } /* touch: no hover, always show */
  .emoji-group-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); margin: 16px 0 8px; }
  .emoji-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: 8px; }
  /* Only render the emoji groups actually on screen — the picker has 600+ cells and
     mounting/painting them all at once janks the sheet open. The browser skips
     off-screen groups and reserves ~their height so scrolling stays stable. */
  .emoji-group { content-visibility: auto; contain-intrinsic-size: auto 320px; }
  .emoji-glyph { font-size: 24px; line-height: 1; }
  .emoji-png { display: block; width: 26px; height: 26px; }
  .emoji-search-wrap { flex: 0 0 auto; background: var(--surface); padding: 12px 16px; border-bottom: 1px solid var(--border); }
  .emoji-search-input {
    width: 100%; box-sizing: border-box; background: var(--surface-2);
    border: 1px solid var(--border); border-radius: 12px; color: var(--text);
    font: inherit; font-size: 15px; padding: 10px 12px; outline: none;
  }
  .emoji-search-input:focus { border-color: var(--accent); }
  .emoji-search-input::placeholder { color: var(--text-dim); }
  .emoji-noresult { color: var(--text-dim); text-align: center; padding: 28px 12px; font-size: 14px; }

  .weekday-row { display: flex; gap: 6px; margin-top: 4px; }
  .weekday-chip {
    flex: 1; min-width: 0; aspect-ratio: 1 / 1;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text-dim);
    border-radius: 10px; font: inherit; font-weight: 700; font-size: 13px;
    cursor: pointer; touch-action: manipulation;
  }
  .weekday-chip.on { background: rgba(var(--accent-rgb), 0.16); border-color: var(--accent); color: var(--accent); }
  /* TODAY marker: a small accent dot at the top-right so you instantly see which weekday is today. */
  .weekday-chip.today { position: relative; }
  .weekday-chip.today::after { content: ''; position: absolute; top: 4px; right: 4px; width: 6px; height: 6px;
    border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 2px var(--surface-2); }
  /* HAS-TASK marker (amber dot, top-left) — warns that picking this day as a copy/apply target will
     REPLACE the tasks already on it. Distinct corner + colour from the accent "today" dot. */
  .weekday-chip.hastask { position: relative; }
  .weekday-chip.hastask::before { content: ''; position: absolute; top: 4px; left: 4px; width: 6px; height: 6px;
    border-radius: 50%; background: #fbbf24; box-shadow: 0 0 0 2px var(--surface-2); }
  .rt-overwrite-hint { font-size: 11px; color: var(--text-dim); margin: 7px 2px 0; text-align: center; }
  /* Undo toast after a copy/apply overwrite — floats above the sheet body, auto-dismisses. */
  .rt-undo-toast { animation: fadeIn .18s ease-out; position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 50;
    display: flex; align-items: center; gap: 12px; padding: 9px 10px 9px 16px; border-radius: 999px;
    max-width: calc(100% - 28px); background: var(--surface-2); border: 1px solid var(--border-strong);
    box-shadow: 0 8px 26px rgba(0,0,0,0.55); font-size: 13px; font-weight: 600; color: var(--text); }
  .rt-undo-msg { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .rt-undo-btn { flex-shrink: 0; padding: 6px 13px; border-radius: 999px; border: 0; cursor: pointer;
    background: var(--accent); color: var(--accent-text); font-weight: 800; font-size: 13px; }
  .rt-undo-btn:active { transform: scale(0.95); }
  /* "Save the day you're viewing" — a full-width option above the recurring-weekday picker. */
  .rt-viewday-btn { width: 100%; margin-top: 8px; padding: 11px 14px; border-radius: 12px; cursor: pointer;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text); font-size: 13px; font-weight: 700; text-align: center; }
  .rt-viewday-btn.on { border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
  .rt-viewday-btn:active { transform: scale(0.99); }
  .rt-viewday-or { text-align: center; font-size: 11px; color: var(--text-dim); margin: 9px 0 7px; letter-spacing: 0.03em; }
  /* Outline the 7 weekday chips as "this week"; each chip stacks its letter over its real date, and
     today's chip gets an accent ring so the current day of the week reads at a glance. */
  .rt-week-frame { border: 1px solid var(--border); border-radius: 14px; padding: 7px 8px 9px; position: relative; }
  .rt-week-cap { font-size: 10px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim);
    position: absolute; top: -8px; left: 12px; padding: 0 6px; background: var(--surface); }
  .rt-daychip { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; line-height: 1.05; }
  .rt-daychip-wd { font-size: 13px; font-weight: 700; }
  .rt-daychip-dt { font-size: 10px; font-weight: 600; opacity: 0.55; }
  .rt-daychip.on .rt-daychip-dt { opacity: 0.85; }
  .weekday-chip.today.rt-daychip { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
  .weekday-chip.today.rt-daychip .rt-daychip-dt { color: var(--accent); opacity: 1; }
  /* The day whose per-day sub-task name is currently showing below the pills. */
  .weekday-chip.active { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
  /* Per-weekday sub-task name editor — a small box under each day pill, in the same 7-col grid. */
  .weekday-grid { display: flex; gap: 6px; margin-top: 4px; }
  .weekday-col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
  .weekday-col .weekday-chip { flex: 0 0 auto; aspect-ratio: auto; width: 100%; height: 40px; }
  .day-mini-input {
    width: 100%; min-width: 0; box-sizing: border-box;
    background: transparent; border: 1px dashed var(--border); color: var(--text);
    border-radius: 8px; font: inherit; font-size: 11px; padding: 5px 5px; text-align: center;
  }
  .day-mini-input::placeholder { color: var(--text-dim); opacity: 0.45; }
  .day-mini-input.filled { background: var(--surface-2); border-style: solid; border-color: var(--accent); color: var(--accent); }
  .day-mini-input:disabled { opacity: 0.18; cursor: not-allowed; }
  .day-mini-input:focus { border-style: solid; border-color: var(--accent); outline: none; }

  /* --- Compact "New / Edit activity" form: fit everything on one screen, no scroll --- */
  .act-form { padding: 8px 14px 16px; }
  .act-form .input-large { font-size: 20px; padding: 8px 2px; margin: 2px 0 0; }
  .act-form .race-setup-label { margin: 0 0 6px; }
  .act-form .lbl-opt { text-transform: none; letter-spacing: 0; font-weight: 500; font-size: 11px; color: var(--text-dim); margin-left: 7px; }

  /* Color dot lives in front of the task name; tap to reveal the swatch popover. */
  .act-name-row { display: flex; align-items: center; gap: 12px; }
  .act-name-row .input-underline { flex: 1; margin-bottom: 0; }
  .act-color-dot {
    flex-shrink: 0; width: 26px; height: 26px; border-radius: 50%;
    border: 2px solid var(--border-strong); padding: 0; cursor: pointer;
    box-shadow: 0 0 0 3px var(--bg) inset; touch-action: manipulation;
  }
  .act-color-pop { display: flex; flex-wrap: wrap; gap: 12px; padding: 12px 2px 2px; }

  /* Grouped section cards — compact. */
  .act-section { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px 11px; margin-top: 8px; }
  .act-section > .race-setup-label:first-child { margin-top: 0; }
  .act-section > .race-setup-label:not(:first-child) { margin-top: 13px; }
  /* "More options" disclosure header — folds the set-once advanced fields (race-vs-just-me,
     scoring mode) so a new task opens to just name → emoji → when. */
  .act-adv-toggle { display: flex; align-items: center; justify-content: space-between; width: 100%; margin-top: 10px; padding: 11px 13px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); color: var(--text-dim); font-size: 13px; font-weight: 600; cursor: pointer; }
  .act-adv-toggle:hover { color: var(--text); }
  .act-adv-caret { transition: transform .18s ease; font-size: 11px; line-height: 1; }
  .act-adv-caret.open { transform: rotate(180deg); }
  /* Group divider inside the activity form — splits "What is this task" (identity/rules) from
     "When" (schedule). Bolder than a field's race-setup-label; a hairline rule above it. */
  .act-group-label { margin: 14px 2px 2px; padding-top: 11px; border-top: 1px solid var(--border); font-size: 12px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--text); }
  .act-group-label:first-of-type { margin-top: 14px; }
  .act-group-label .lbl-opt { display: block; margin: 3px 0 0; font-size: 11px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--text-dim); }
  /* Quick-add "More options" fold trigger — a tappable pill that reveals the "what" details. */
  .act-more-toggle { display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%; margin: 14px 0 2px; padding: 9px 12px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); color: var(--text-muted); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; touch-action: manipulation; }
  .act-more-toggle:hover { border-color: var(--accent); color: var(--text); }
  .act-more-toggle:active { transform: scale(0.99); }
  .act-more-caret { font-size: 11px; line-height: 1; transition: transform .18s ease; }
  .act-more-caret.open { transform: rotate(180deg); }
  /* Time-slot card in the "When" group — one per time the task runs (morning, afternoon…). */
  .act-slot { margin-top: 12px; padding: 11px 12px 12px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; }
  .act-slot:first-of-type { margin-top: 8px; }
  .act-slot-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
  .act-slot-num { font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-dim); }
  .act-slot-remove { background: none; border: 0; color: var(--text-muted); font-size: 13px; cursor: pointer; padding: 3px 7px; border-radius: 8px; line-height: 1; }
  .act-slot-remove:hover { color: var(--you); background: rgba(var(--you-rgb),0.12); }
  .act-add-slot { margin-top: 10px; width: 100%; padding: 11px; background: rgba(var(--accent-rgb),0.07); border: 1px dashed rgba(var(--accent-rgb),0.45); border-radius: 12px; color: var(--accent); font-size: 13px; font-weight: 700; cursor: pointer; transition: background .12s ease; }
  .act-add-slot:hover { background: rgba(var(--accent-rgb),0.13); }
  .day-sub-input { flex: 1; min-width: 0; background: transparent; border: 0; border-bottom: 1px solid var(--border); color: var(--text); font-size: 13px; padding: 5px 2px; }
  .day-sub-input:focus { outline: none; border-bottom-color: var(--accent); }
  /* "→ full editor" bridge link inside BlockSheet (scoring/goal/emoji/multi-slot live there). */
  .bs-details-link { display: block; width: 100%; margin: 12px 0 2px; padding: 10px; text-align: center; background: rgba(var(--accent-rgb),0.07); border: 1px dashed rgba(var(--accent-rgb),0.4); border-radius: 12px; color: var(--accent); font-size: 13px; font-weight: 600; cursor: pointer; }
  .bs-details-link:hover { background: rgba(var(--accent-rgb),0.13); }
  .bs-details-link:disabled { cursor: default; }
  /* Quick Add sheet — the simple Main-page create front door (QuickAddSheet). */
  .qa-name-row { display: flex; align-items: center; gap: 12px; margin: 4px 0 6px; }
  .qa-emoji { flex: 0 0 auto; width: 52px; height: 52px; border-radius: 14px; border: 2px solid var(--accent); background: var(--card2); display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; }
  .qa-name { flex: 1; margin-bottom: 0; font-size: 17px; }
  .qa-everyday { margin: 8px 0 2px; padding: 6px 14px; border-radius: 999px; border: 1px solid var(--border); background: transparent; color: var(--text-dim); font-size: 13px; font-weight: 600; cursor: pointer; }
  .qa-everyday.on { background: rgba(var(--accent-rgb),0.16); border-color: var(--accent); color: var(--accent); }
  .qa-preset-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 4px 0 12px; }
  .qa-preset { padding: 12px 4px; border-radius: 12px; border: 1px solid var(--border); background: var(--card2); color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer; text-align: center; }
  .qa-preset.on { background: rgba(var(--accent-rgb),0.16); border-color: var(--accent); color: var(--accent); }
  .preset-goto-sched { color: var(--accent); font-weight: 700; white-space: nowrap; }
  .qa-suggest-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 12px; }
  .qa-suggest { display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px; border-radius: 999px; border: 1px solid var(--border); background: var(--card2); color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer; }
  .qa-suggest:active { background: rgba(var(--accent-rgb),0.16); border-color: var(--accent); }
  .qa-time-row { display: flex; align-items: center; gap: 10px; }
  .qa-time-dash { color: var(--text-dim); font-weight: 700; }
  /* Compact emoji row: picked-emoji preview + a "Choose" button that opens the full picker sheet
     (replaces the old 3-row inline grid). */
  .act-emoji-pick { display: flex; align-items: center; gap: 9px; margin-top: 4px; }
  .act-emoji-preview { flex-shrink: 0; width: 46px; height: 46px; display: flex; align-items: center; justify-content: center; border-radius: 12px; background: var(--surface); border: 1px solid var(--border); cursor: pointer; }
  .act-emoji-preview:hover { border-color: var(--accent); }
  .act-emoji-choose { flex: 1; display: flex; align-items: center; justify-content: space-between; height: 46px; padding: 0 14px; border-radius: 12px; background: var(--surface); border: 1px solid var(--border); color: var(--text); font-size: 14px; font-weight: 600; cursor: pointer; }
  .act-emoji-choose:hover { border-color: var(--accent); }
  .act-emoji-pick .emoji-photo { width: 46px; height: 46px; }
  .act-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; align-items: start; }
  /* Scoring-mode selector (Time / Amount / Percent) in the activity editor */
  .goalmode-row { display: flex; gap: 6px; margin-top: 6px; }
  .goalmode-opt { flex: 1 1 0; font-size: 12px; font-weight: 700; padding: 8px 4px; border-radius: 10px;
    background: var(--surface); color: var(--text-muted); border: 1px solid var(--border);
    cursor: pointer; touch-action: manipulation; white-space: nowrap;
    display: inline-flex; align-items: center; justify-content: center; gap: 5px; }
  .goalmode-opt.on { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
  .goal-amount-row { display: flex; gap: 10px; margin-top: 12px; align-items: stretch; }
  /* Pill stepper: custom −/＋ around a spinner-less number field (no ugly native arrows). */
  .amt-stepper { display: inline-flex; align-items: center; gap: 2px; flex: 0 0 auto;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 4px; }
  .amt-stepper:focus-within { border-color: var(--accent); }
  .amt-step { width: 40px; height: 40px; border: 0; border-radius: 9px; background: var(--surface);
    color: var(--text); font-size: 18px; font-weight: 700; line-height: 1; cursor: pointer;
    touch-action: manipulation; display: inline-flex; align-items: center; justify-content: center;
    transition: background 0.12s ease, transform 0.06s ease; }
  .amt-step:hover { background: var(--accent); color: #0b1220; }
  .amt-step:active { transform: scale(0.92); }
  .amt-num { width: 58px; background: transparent; border: 0; outline: none; color: var(--text);
    font: inherit; font-size: 18px; font-weight: 800; text-align: center; -moz-appearance: textfield;
    font-variant-numeric: tabular-nums; }
  .amt-num::-webkit-outer-spin-button, .amt-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .amt-num::placeholder { color: var(--text-dim); font-weight: 600; }
  .amt-unit { flex: 1; min-width: 0; background: var(--surface-2); border: 1px solid var(--border);
    border-radius: 12px; padding: 0 14px; color: var(--text); font: inherit; outline: none; }
  .amt-unit::placeholder { color: var(--text-dim); }
  .amt-unit:focus { border-color: var(--accent); }
  .act-form-grid .input-underline, .act-form-grid .amount-input { margin-bottom: 0; }
  .act-form .amount-row { gap: 8px; }
  .act-form .amount-input { padding: 8px 0; }
  .act-form .amount-unit { min-width: 0; font-size: 13px; }
  .act-color-pop .act-color-swatch { width: 32px; height: 32px; }

  /* Working emoji: wrap all options onto 2–3 rows so the whole curated set is
     visible at once (no horizontal scroll hiding most of it). */
  .act-form .emoji-pick-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
  .act-form .emoji-opt { flex-shrink: 0; width: 35px; height: 35px; border-radius: 10px; font-size: 18px; }
  /* Dense "task" card: each decision is one row — fixed label on the left, control fills the rest. */
  .act-compact .cmp-row { display: flex; align-items: center; gap: 10px; margin-top: 9px; }
  .act-compact > .cmp-row:first-child { margin-top: 0; }
  .cmp-lbl { flex: 0 0 58px; font-size: 11px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--text-muted); line-height: 1.2; }
  .cmp-seg { flex: 1; margin-top: 0; }
  .cmp-emoji { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; }
  .cmp-cur { background: rgba(var(--accent-rgb),0.14) !important; border-color: var(--accent) !important; }
  .cmp-switch { display: inline-flex; align-items: center; cursor: pointer; position: relative; }
  .cmp-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
  /* The two emoji tiles that lead the name (right of the colour dot). 2nd = dashed "add" slot. */
  .act-name-row { gap: 8px; }
  .act-lead-emoji { flex: 0 0 auto; }
  .act-lead-2nd:not(.on) { border-style: dashed; background: transparent; color: var(--text-dim); font-size: 16px; }
  .act-lead-clear { flex: 0 0 auto; width: 18px; padding: 0; background: none; border: 0; color: var(--text-muted); font-size: 12px; line-height: 1; cursor: pointer; }
  .act-lead-clear:hover { color: var(--you); }

  .act-form .weekday-row { gap: 6px; margin-top: 4px; }
  .act-form .weekday-chip { aspect-ratio: auto; height: 40px; border-radius: 10px; font-size: 13px; }

  /* Time of day: stacked, with the duration chips on their own clean row. */
  .act-time-line { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
  .act-time-line .time-row { gap: 8px; }
  .act-time-line .act-chip-row { gap: 7px; }
  /* From / To range pickers so the exact start and end times can both be set. */
  .act-time-range { display: flex; flex-direction: column; gap: 10px; margin-top: 6px; }
  .act-time-field { display: flex; align-items: center; gap: 12px; }
  .act-time-lbl { flex: 0 0 38px; font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-muted); }
  .act-time-field .time-row { flex: 1; gap: 8px; }
  .act-dur-quick { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin-top: 12px; }
  .act-dur-lbl { font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-dim); margin-right: 2px; }
  .act-time-summary { font-size: 12px; margin-top: 8px; font-variant-numeric: tabular-nums; }
  /* Edit-block sheet: tighten the per-label vertical rhythm (global label has a 20px top
     margin — across ~6 labels that's most of the scroll). Scoped to this sheet only. */
  .blk-form .act-group-label:first-of-type { border-top: 0; padding-top: 0; margin-top: 6px; }
  .blk-form .act-section { padding: 9px 11px 10px; margin-top: 7px; }
  .blk-form .race-setup-label { margin: 10px 0 6px; }
  .blk-form .act-section > .race-setup-label:first-child { margin-top: 0; }
  .blk-form .race-setup-explain { margin-top: 5px; font-size: 11px; line-height: 1.4; }
  .blk-form .act-chip-row { gap: 6px; }
  .blk-form .act-dur-quick { margin-top: 8px; }
  .blk-form .bs-details-link { margin: 8px 0 0; padding: 8px; font-size: 12px; }
  .blk-trow { margin-top: 7px; }
  /* Sub-headers inside the WHAT card ("Activity" / "For me") — lighter than the card title. */
  .bs-pick-sub { font-size: 11px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--text-dim); margin: 8px 0 5px; }
  /* Collapsible card (FoldCard): header is the whole tap target; collapsed shows the current
     value on the right, expanded reveals the controls. Keeps long forms short + scannable. */
  .foldcard { padding: 0; }
  .foldcard-head { display: flex; align-items: center; gap: 8px; width: 100%; background: none; border: 0; cursor: pointer; padding: 12px; text-align: left; color: var(--text); font: inherit; touch-action: manipulation; }
  .foldcard-title { font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted); }
  .foldcard.open .foldcard-title, .foldcard-head:hover .foldcard-title { color: var(--text); }
  .foldcard-sum { margin-left: auto; font-size: 13px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .foldcard-caret { margin-left: 8px; flex-shrink: 0; color: var(--text-dim); font-size: 12px; }
  .foldcard.open .foldcard-caret { margin-left: auto; }
  .foldcard-body { padding: 0 12px 12px; }
  /* "Different time per day" toggle + the per-day From–To rows it reveals. */
  .perday-toggle { display: flex; align-items: center; gap: 10px; margin: 8px 0 2px; cursor: pointer; user-select: none; }
  .perday-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
  .perday-switch { flex: 0 0 auto; width: 38px; height: 22px; border-radius: 999px; background: var(--surface); border: 1px solid var(--border-strong); position: relative; transition: background 0.15s, border-color 0.15s; }
  .perday-knob { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: var(--text-dim); transition: left 0.15s, background 0.15s; }
  .perday-toggle input:checked + .perday-switch { background: rgba(var(--accent-rgb),0.22); border-color: var(--accent); }
  .perday-toggle input:checked + .perday-switch .perday-knob { left: 18px; background: var(--accent); }
  .perday-toggle-lbl { font-size: 13px; font-weight: 600; color: var(--text); }
  .perday-list { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
  .perday-row { display: flex; align-items: center; gap: 10px; }
  .perday-day { flex: 0 0 38px; font-size: 12px; font-weight: 800; color: var(--text-muted); }
  .perday-times { flex: 1; display: flex; align-items: center; gap: 8px; }
  .perday-dash { color: var(--text-dim); }
  .perday-row.bad .perday-day { color: var(--you); }
  /* Per-day AMOUNT rows reuse the amount stepper; let it grow to fill the row. */
  .perday-row .amt-stepper-day { flex: 1; }
  .perday-row .amt-stepper-day .amt-num { flex: 1; width: auto; min-width: 0; text-align: center; }
  .perday-unit { flex: 0 0 auto; font-size: 12px; font-weight: 600; color: var(--text-muted); min-width: 28px; }
  .act-delete { margin-top: 14px; }

  /* --- Your committed self (avatar) --- */
  .self-avatar {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 18px; padding: 14px 16px;
    display: flex; flex-direction: column; gap: 12px;
  }
  .self-avatar-top { display: flex; align-items: center; gap: 14px; }
  .self-avatar-bubble {
    position: relative; flex-shrink: 0;
    width: 58px; height: 58px; border-radius: 50%;
    background: var(--surface-2); border: 1px solid var(--border);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer; padding: 0; touch-action: manipulation;
  }
  .self-avatar-face { font-size: 32px; line-height: 1; display: block; }
  .self-avatar-badge {
    position: absolute; bottom: -3px; right: -3px;
    font-size: 16px; line-height: 1;
    background: var(--bg); border-radius: 50%; padding: 1px;
  }
  .self-avatar-msg { flex: 1; min-width: 0; }
  .self-avatar-head { font-weight: 800; font-size: 16px; line-height: 1.2; }
  .self-avatar-sub {
    font-size: 12px; color: var(--text-muted);
    margin-top: 4px; line-height: 1.45; font-variant-numeric: tabular-nums;
  }
  .self-avatar-pickrow {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
    gap: 8px; align-items: center;
    border-top: 1px solid var(--border); padding-top: 12px;
  }
  .self-avatar-opt {
    width: 100%; aspect-ratio: 1; height: auto; border-radius: 12px;
    background: var(--surface-2); border: 1px solid var(--border);
    font-size: 22px; line-height: 1; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    padding: 0; touch-action: manipulation;
    transition: transform 0.14s ease, background 0.14s ease, border-color 0.14s ease;
  }
  .self-avatar-opt:hover { transform: translateY(-2px) scale(1.07); border-color: var(--border-strong); z-index: 1; }
  .self-avatar-opt:active { transform: scale(0.92); }
  .self-avatar-opt.on { border-color: var(--accent); background: rgba(var(--accent-rgb), 0.16); }
  /* No fake bob/sway on the chosen face — if it has a real animated gif it plays on
     its own; selection is shown by the accent border + tint only. */
  .self-avatar-opt.add { color: var(--text-muted); font-size: 24px; font-weight: 700; }
  .self-avatar-opt.add:hover { color: var(--text); border-color: var(--accent); }
  .self-avatar-opt.photo { overflow: hidden; display: flex; align-items: center; justify-content: center; }
  /* Saved-photo cell: the selectable face button + a tiny corner remove badge (siblings,
     so we never nest a <button> inside a <button>). The wrapper is the grid item. */
  .self-avatar-photo-wrap { position: relative; width: 100%; aspect-ratio: 1; }
  .self-avatar-rm {
    position: absolute; top: -5px; right: -5px; z-index: 2;
    width: 18px; height: 18px; border-radius: 50%; padding: 0; line-height: 1;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface-2); color: var(--text-muted);
    border: 1px solid var(--border-strong); font-size: 13px; cursor: pointer;
    opacity: 0; transition: opacity 0.14s ease, color 0.14s ease, transform 0.1s ease;
  }
  .self-avatar-photo-wrap:hover .self-avatar-rm, .self-avatar-rm:focus-visible { opacity: 1; }
  .self-avatar-rm:hover { color: #ef4444; border-color: #ef4444; }
  .self-avatar-rm:active { transform: scale(0.85); }
  @media (hover: none) { .self-avatar-rm { opacity: 1; } } /* touch: no hover, always show */
  /* Uploaded photo avatar — always a round, cropped face. The round crop trims the box's
     4 corners, so at the SAME box size a circular photo reads visibly SMALLER than a square
     emoji that fills its frame edge-to-edge. Scale the photo up ~10% (layout box unchanged)
     so a photo avatar feels the same size as an emoji avatar sitting next to it. */
  /* Photo/GIF face now renders as a SPAN with background-size:cover (iOS square fix), which already
     fills the circle — the old transform:scale(1.1) (an <img> edge-gap hack) just overflowed the box
     ~10% into neighbours, so it's removed. */
  .face-img { border-radius: 50%; object-fit: cover; display: block; }
  /* Animated (GIF) avatar with a stored zoom/pan crop: a round clip window with the raw
     animated <img> positioned + scaled inside it (renderFace computes width/height/left/top).
     Can't bake the crop into a canvas — that would freeze the animation — so we frame it live. */
  .face-crop { position: relative; display: inline-block; vertical-align: top; overflow: hidden; border-radius: 50%; }
  .face-crop img { position: absolute; max-width: none; user-select: none; -webkit-user-drag: none; }
  /* Emoji-face nudge: an inner layer the resize/drag transform rides on. No clip, so the main
     face can drift/grow outside its circle as freely as a sticker badge. */
  .face-adj { display: inline-flex; align-items: center; justify-content: center; vertical-align: top; }
  .face-adj-in { display: inline-flex; align-items: center; justify-content: center; transform-origin: center center; }
  /* Double-habit second-emoji badge: stacked at the main emoji's bottom-right corner. */
  .te-wrap { position: relative; display: inline-flex; line-height: 0; vertical-align: top; }
  .te-badge { position: absolute; right: -4px; bottom: -4px; line-height: 0; border-radius: 50%;
    background: var(--surface); box-shadow: 0 0 0 1.5px var(--surface); display: inline-flex;
    align-items: center; justify-content: center; pointer-events: none; }

  /* Photo cropper (pan + zoom before saving the avatar photo) */
  .cropper {
    position: relative; border-radius: 50%; overflow: hidden; background: #000;
    margin: 6px auto 16px; touch-action: none; cursor: grab; box-shadow: 0 0 0 3px var(--border-strong);
  }
  .cropper:active { cursor: grabbing; }
  .cropper-img { position: absolute; max-width: none; user-select: none; -webkit-user-drag: none; }
  .cropper-ring { position: absolute; inset: 0; border-radius: 50%; box-shadow: inset 0 0 0 2px rgba(255,255,255,0.4); pointer-events: none; }
  .cropper-zoom { display: flex; align-items: center; gap: 12px; width: 100%; max-width: 260px; margin: 0 auto 4px; color: var(--text-muted); font-size: 18px; }
  .cropper-zoom input[type=range] { flex: 1; accent-color: var(--accent); }
  /* When the background is cut out, show a checkerboard so the transparency reads. */
  .cropper.is-cut {
    background:
      conic-gradient(#cfcfcf 25%, #efefef 0 50%, #cfcfcf 0 75%, #efefef 0) 0 0 / 20px 20px;
  }
  .crop-cut-btn {
    display: inline-flex; align-items: center; gap: 7px; margin: 2px auto 10px;
    padding: 9px 16px; border-radius: 999px; cursor: pointer;
    border: 1px solid var(--border-strong); background: var(--card2-bg, transparent);
    color: var(--text); font-size: 14px; font-weight: 600; transition: opacity .15s;
  }
  .crop-cut-btn.on { border-color: var(--accent); color: var(--accent); background: rgba(var(--accent-rgb), 0.12); }
  .crop-cut-btn:disabled { opacity: 0.55; cursor: default; }
  .crop-cut-btn .spin { width: 14px; height: 14px; border-radius: 50%; border: 2px solid currentColor; border-top-color: transparent; animation: cropspin 0.7s linear infinite; }
  @keyframes cropspin { to { transform: rotate(360deg); } }
  .crop-cut-err { color: #ef4444; font-size: 12px; text-align: center; margin: -4px auto 8px; }

  .self-avatar-bubble.anim-run { animation: avatarRun 0.7s ease-in-out infinite; }
  .self-avatar-bubble.anim-dash { animation: avatarDash 1.1s ease-in-out infinite; }
  .self-avatar-bubble.anim-rest { animation: avatarRest 2.6s ease-in-out infinite; }
  .self-avatar-bubble.anim-proud { animation: avatarProud 2s ease-in-out infinite; }
  @keyframes avatarRun {
    0%, 100% { transform: translateY(0) rotate(-2deg); }
    50% { transform: translateY(-5px) rotate(2deg); }
  }
  @keyframes avatarDash {
    0%, 100% { transform: translateX(0); }
    50% { transform: translateX(4px); }
  }
  @keyframes avatarRest {
    0%, 100% { transform: scale(1); opacity: 0.92; }
    50% { transform: scale(1.03); opacity: 1; }
  }
  @keyframes avatarProud {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-3px); }
  }
  @media (prefers-reduced-motion: reduce) {
    .self-avatar-bubble { animation: none !important; }
  }
  .self-avatar.tone-go { border-color: rgba(var(--accent-rgb),0.4); background: rgba(var(--accent-rgb),0.06); }
  .self-avatar.tone-done { border-color: rgba(var(--you-rgb),0.4); background: rgba(var(--you-rgb),0.05); }

  /* --- Schedule screen + day timeline --- */
  .sched-screen { display: flex; flex-direction: column; gap: 14px; }
  /* Day | Week segmented toggle */
  .view-toggle { display: flex; gap: 4px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 3px; flex: 0 0 auto; }
  .view-toggle-btn {
    flex: 1; padding: 8px 0; border: 0; border-radius: 9px; background: transparent;
    color: var(--text-muted); font: inherit; font-weight: 700; font-size: 13px;
    cursor: pointer; touch-action: manipulation; transition: background .15s ease, color .15s ease;
  }
  .view-toggle-btn.on { background: var(--accent); color: var(--accent-text); box-shadow: 0 1px 5px rgba(var(--accent-rgb),0.4); }
  /* Explicit hover states so the active pill never flashes a weird default on hover: inactive brightens,
     active stays solid green. */
  .view-toggle-btn:not(.on):hover { color: var(--text); background: rgba(255,255,255,0.04); }
  .view-toggle-btn.on:hover { background: var(--accent); color: var(--accent-text); }
  /* 7-day Google-Calendar-style week grid (Mon–Sun columns, continuous hour axis) */
  .wg-wrap { position: relative; display: flex; flex-direction: column; flex: 1; min-height: 0; }
  /* Horizontal scroller so the 7 day-columns can be WIDER than the screen (tappable me/plan
     lanes) and you slide sideways to reach later days. The day-header strip lives inside the
     same scroller as the grid, so the two pan together. Vertical scroll stays inside .wg-scroll. */
  .wg-xscroll { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow-x: auto; overflow-y: hidden; }
  .wg-xinner { flex: 1; min-height: 0; width: 100%; min-width: 530px; display: flex; flex-direction: column; }
  .wg-nav { flex: 0 0 auto; margin-top: 6px; }
  /* Smaller nav circles in the Week toolbar so they don't crowd/overlap the Drag strip above. */
  .wg-nav .cal-nav { width: 28px; height: 28px; font-size: 13px; }
  /* The week label ("This week" / a short date range) is always narrow, so don't let the
     ellipsis machinery collapse it to "This we…": overflow:hidden on a flex item forces a
     min-content basis even when there's free space. Clip-not-ellipsis here keeps it whole. */
  .wg-nav .cal-date-main { overflow: visible; text-overflow: clip; }
  /* Week-summary "kept" pill, right of the week nav. (Dropping the race bars + the redundant
     see-progress icon from this nav freed enough room that "This week" no longer truncates.) */
  .wg-kept { margin-left: auto; font-size: 11px; font-weight: 800; padding: 5px 11px; border-radius: 999px; white-space: nowrap; letter-spacing: .01em; }
  .wg-kept.good { color: var(--accent); background: rgba(var(--accent-rgb),0.14); }
  .wg-kept.mid { color: var(--you); background: rgba(var(--you-rgb),0.14); }
  .wg-kept.bad { color: var(--danger); background: rgba(248,113,113,0.14); }
  .wg-kept.dim { color: var(--text-dim); background: var(--surface-2); }
  /* ⤢ Expand toggle, tucked at the right end of the week-nav row — small icon button mirroring the
     Day timeline's .tl2-cap-expand (not a labelled toolbar button). */
  .wg-expand-ic { flex: 0 0 auto; margin-left: 6px; width: 28px; height: 28px; border-radius: 8px;
    display: flex; align-items: center; justify-content: center; padding: 0;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text-dim);
    cursor: pointer; touch-action: manipulation; }
  .wg-expand-ic:active { background: var(--surface); color: var(--text); }
  /* Compact TODAY race tucked into the week-nav row (this week only) — reuses the
     dashboard's .hrm mini bars so it reads identically, just narrower. */
  .wg-race { flex: 1 1 auto; min-width: 0; max-width: 210px; display: flex; flex-direction: column; gap: 3px; margin: 0 10px; }
  .wg-race .hrm-tag { width: 30px; }
  /* Tools row: drag hint + "move every day at once" toggle. */
  .wg-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; flex: 0 0 auto; padding: 5px 2px 7px 0; }
  /* The two hobby switches + "Move all days" stay grouped together at the right; the hint
     truncates first when the row is tight. */
  .wg-toolgroup { margin-left: auto; flex: 0 0 auto; display: flex; align-items: center; gap: 8px; }
  /* "Hobbies" caption that introduces the Me / JEK switch pair. */
  .wg-hobs-lbl { font-size: 10px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-dim); }
  /* "Me" hobbies are always on — a plain label (your colour), no switch — mirroring the Day view. */
  .wg-hobme { font-size: 11px; font-weight: 700; color: var(--you); display: inline-flex; align-items: center; }
  /* Day-view toolbar chrome (surface-2 fill + border, muted, lifts on press) with the icon on
     the LEFT and a short label on the RIGHT (side by side) so each button explains itself
     without growing a second row — icon-only was too cryptic, stacked was too tall. */
  .wg-allbtn { flex-shrink: 0; height: 32px; padding: 0 10px; border-radius: 12px; display: inline-flex; flex-direction: row; align-items: center; justify-content: center; gap: 5px; color: var(--text-muted); background: var(--surface-2); border: 1px solid var(--border); cursor: pointer; touch-action: manipulation; }
  .wg-allbtn:active { background: var(--surface); color: var(--text); }
  .wg-allbtn svg { flex-shrink: 0; }
  .wg-btn-lbl { font-size: 11px; font-weight: 700; line-height: 1; letter-spacing: 0.01em; white-space: nowrap; }
  .wg-add-plus { font-size: 17px; font-weight: 700; line-height: 1; }
  /* ＋ Add task — the primary toolbar action, accent-filled like the Day view's .cal-add. */
  .wg-allbtn.wg-add { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
  .wg-allbtn.wg-add:active { background: var(--accent-hover); color: var(--accent-text); }
  .wg-allbtn.on { color: var(--accent-text); background: var(--accent); border-color: var(--accent); }
  .wg-allbtn.danger { color: var(--danger,#ef4444); background: rgba(var(--danger-rgb,239,68,68),0.12); border-color: rgba(var(--danger-rgb,239,68,68),0.5); }
  .wg-allbtn.danger:active { background: rgba(var(--danger-rgb,239,68,68),0.2); }
  /* Each hobby toggle = an iOS-style switch (label + slider) instead of a pill, since it's a
     pure on/off display preference. Mirrors the Avatar tab's Lively switch, sized for this row. */
  .wg-hobtog { display: inline-flex; align-items: center; gap: 5px; font-size: 11px;
    font-weight: 600; color: var(--text-dim); background: none; border: none; cursor: pointer;
    touch-action: manipulation; white-space: nowrap; padding: 2px; max-width: 90px; }
  .wg-hobtog > span:first-child { overflow: hidden; text-overflow: ellipsis; }
  .wg-hobtog.on { color: var(--text-muted); }
  /* Subtle switch — small and quiet so it doesn't shout over the grid. Off = flat surface;
     on = a soft, low-saturation slate-blue (not a neon cyan). */
  .wg-switch { flex: 0 0 auto; width: 28px; height: 16px; border-radius: 999px; background: var(--surface-2);
    border: 1px solid var(--border-strong); position: relative; transition: background .18s, border-color .18s; }
  .wg-hobtog.on .wg-switch { background: rgba(56,189,248,0.30); border-color: rgba(56,189,248,0.45); }
  .wg-knob { position: absolute; top: 2px; left: 2px; width: 10px; height: 10px; border-radius: 50%;
    background: #94a3b8; transition: transform .18s, background .18s; }
  .wg-hobtog.on .wg-knob { transform: translateX(12px); background: #e2e8f0; }
  /* Day-header strip: weekday · date · at-a-glance grade dot. */
  /* Right padding is set inline to the MEASURED scrollbar width (see WeekGrid `sbw`), so
     the day headers line up with the columns below instead of drifting — the columns
     stop at the scrollbar's inner edge, and the header reserves exactly that gap. */
  .wg-head { display: flex; flex: 0 0 auto; padding: 0; border-bottom: 1px solid var(--border); }
  .wg-corner { flex: 0 0 46px; }
  /* Compact day header: dow + date + grade glyph on ONE row (was a tall 3-row stack that wasted
     vertical space). flex-wrap lets the glyph drop to a 2nd line only on very narrow columns. */
  .wg-dh { flex: 1 1 0; min-width: 0; display: flex; flex-flow: row wrap; align-items: center; justify-content: center; gap: 1px 3px; padding: 4px 1px; background: none; border: none; border-left: 1px solid var(--border); cursor: pointer; touch-action: manipulation; }
  .wg-dh-dow { font-size: 9px; font-weight: 700; letter-spacing: .02em; text-transform: uppercase; color: var(--text-dim); }
  .wg-dh.today .wg-dh-dow { color: var(--accent); }
  .wg-dh-num { font-size: 12px; font-weight: 700; color: var(--text); min-width: 17px; height: 17px; line-height: 17px; text-align: center; border-radius: 9px; padding: 0 2px; box-sizing: border-box; }
  .wg-dh.today .wg-dh-num { background: var(--accent); color: var(--accent-text); }
  /* Grade dot: filled = kept · amber = partial · red ring = missed · faint ring = upcoming. */
  .wg-dot { width: 7px; height: 7px; border-radius: 50%; box-sizing: border-box; }
  .wg-dot.good { background: var(--accent); }
  .wg-dot.mid { background: var(--you); }
  .wg-dot.bad { background: transparent; border: 2px solid var(--danger); }
  .wg-dot.dim { background: transparent; border: 1.5px solid var(--text-dim); }
  .wg-dh-none { font-size: 12px; line-height: 7px; height: 7px; color: var(--text-dim); }
  .wg-dh-rest { font-size: 11px; line-height: 7px; }
  /* Achievement-ladder glyph (⭐/◕/◑/◔/○) — same symbols as the Progress "This week" strip. */
  .wg-dh-glyph { font-size: 11px; line-height: 1; height: 13px; display: flex; align-items: center; justify-content: center; }
  .wg-dh-glyph.almost { color: var(--accent); }
  .wg-dh-glyph.half, .wg-dh-glyph.start { color: var(--you); }
  .wg-dh-glyph.today { color: var(--accent); }
  .wg-dh-glyph.miss, .wg-dh-glyph.future, .wg-dh-glyph.none { color: var(--text-dim); }
  .wg-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; position: relative; }
  .wg-canvas { position: relative; }
  .wg-hline { position: absolute; left: 46px; right: 0; border-top: 1px solid var(--border); }
  /* Same RESTYLE as the Day gutter: a clean colour rail on the far-left + a fill that fades out before
     the hour numbers (no muddy flat tint). */
  .wg-band { position: absolute; left: 0; width: 46px; right: auto; z-index: 0; pointer-events: none;
    background: linear-gradient(to right, rgba(var(--band-rgb,148,163,184), 0.13), rgba(var(--band-rgb,148,163,184), 0) 70%); }
  .wg-band::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
    border-radius: 0 3px 3px 0; background: rgba(var(--band-rgb,148,163,184), 0.85); }
  /* Small zone emoji at the band's start, just right of the colour rail (hour number is right-aligned,
     so they don't collide). Day view also shows the name; Week is too tight, so emoji-only. */
  .wg-band-emoji { position: absolute; left: 7px; top: 2px; display: inline-flex; line-height: 1;
    filter: drop-shadow(0 1px 1.5px rgba(0,0,0,0.6)); }
  .wg-half { position: absolute; left: 46px; right: 0; border-top: 1px solid var(--border); opacity: .35; }
  .wg-hlabel { position: absolute; left: 0; width: 42px; transform: translateY(-50%); text-align: right; font-size: 10px; font-weight: 600; color: var(--text-dim); padding-right: 6px; white-space: nowrap; }
  .wg-cols { position: absolute; left: 46px; right: 0; top: 0; bottom: 0; display: flex; z-index: 2; }
  .wg-col { flex: 1 1 0; min-width: 0; position: relative; border-left: 1px solid var(--border); }
  .wg-col.today { background: rgba(var(--accent-rgb),0.05); }
  .wg-col.rest { background: repeating-linear-gradient(45deg, transparent, transparent 7px, rgba(148,163,184,0.05) 7px, rgba(148,163,184,0.05) 14px); }
  /* Drag-to-create surface (under blocks z:2): touch-action auto so a quick swipe still scrolls
     the week; a held drag draws a block. Plus the live amber selection rectangle while drawing. */
  .wg-create-layer { position: absolute; inset: 0; z-index: 1; }
  .wg-create-sel { position: absolute; left: 1px; right: 1px; z-index: 3; border-radius: 8px; background: rgba(var(--accent-rgb),0.22); border: 1.5px dashed var(--accent); pointer-events: none; }
  /* Week blocks: one card per task per day, split into two halves — LEFT = your committed
     self's PLAN, RIGHT = YOU (✓ + emoji if you logged it, faded if you didn't). Emoji
     only, no name/time. Drag the body to reschedule, the bottom grip to resize, tap to edit. */
  /* Each block splits in HALF like the Day view's two lanes: LEFT = YOU (amber, tappable
     check), RIGHT = the committed self's plan (lime). Transparent container; two cards. */
  .wg-block { position: absolute; left: 1px; right: 1px; z-index: 2;
    border: none; padding: 0; overflow: visible; cursor: grab; touch-action: none;
    display: block; background: transparent; color: var(--text); }
  .wg-block:active { cursor: grabbing; }
  .wg-block.dragging { z-index: 6; opacity: .96; }
  .wg-block.dragging .wg-lane { box-shadow: 0 6px 18px rgba(0,0,0,0.5); }
  /* TWO independent sub-lanes per day, like the Day view: the avatar's PLAN block sits in
     the RIGHT half (at its scheduled time); YOUR logged session sits in the LEFT half (at
     the time you actually did it) — so the two can be at different times, not glued together.
     Positioned via inline left/right; .wg-me taps need their own touch-action. */
  .wg-block.me { touch-action: none; cursor: grab; }
  .wg-block.me:active { cursor: grabbing; }
  .wg-lane { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 2px;
    box-sizing: border-box; overflow: hidden; border-radius: 5px; border: 1px solid; box-shadow: 0 1px 2px rgba(0,0,0,0.25); }
  /* avatar PLAN lane = lime/green */
  .wg-lane.plan { background: rgba(var(--accent-rgb),0.12); border-color: rgba(var(--accent-rgb),0.5); }
  .wg-lane.plan.done { background: rgba(var(--accent-rgb),0.2); border-color: rgba(var(--accent-rgb),0.7); }
  .wg-lane.plan.jekdone { border-color: rgba(var(--accent-rgb),0.32); }
  /* Rested ("excused") task = the lime REST theme, matching the Day view (.tl2.av.rested) — NOT
     blue. Blue is reserved for hobby / "just for me", so an excused task must never wear it (the
     committed self rests WITH you in its own lime, same as Day). */
  .wg-lane.plan.excused { background: rgba(var(--accent-rgb),0.12); border-color: rgba(var(--accent-rgb),0.45); }
  /* YOUR session lane = yellow, clearly distinct from the green plan */
  .wg-lane.me { background: rgba(var(--you-rgb),0.26); border-color: rgba(var(--you-rgb),0.85); }
  /* Free ME sessions (logged via ＋, not tied to a block) = DASHED, on the you (left) half.
     Amber for a normal activity, blue for a for-me one — mirrors the Day view's .tl2.me.free. */
  .wg-block.mefree { z-index: 3; cursor: grab; touch-action: none; }
  .wg-block.mefree:active { cursor: grabbing; }
  .wg-lane.mefree { background: rgba(var(--you-rgb),0.20); border-color: rgba(var(--you-rgb),0.75); border-style: dashed; }
  .wg-lane.mefree.hob { background: rgba(56,189,248,0.16); border-color: rgba(56,189,248,0.6); }
  /* YOUR blocks (for-me hobby / logged sessions) sit ABOVE the avatar's plan blocks (z-3 > z-2) so you
     can actually tap-drag-resize them in Week too — same as the green plan blocks. (They used to be z-1,
     painted under the plan, which made them impossible to grab where the two overlapped.) */
  .wg-block.hobby { z-index: 3; }
  .wg-block.me { z-index: 3; }
  .wg-lane.hobby { background: rgba(56,189,248,0.14); border-color: rgba(56,189,248,0.5); }
  .wg-block.avhobby { z-index: 1; left: calc(50% + 2px); right: 1px; pointer-events: none; }
  .wg-lane.avhobby { background: rgba(56,189,248,0.10); border-color: rgba(56,189,248,0.38); }
  .wg-lane.avhobby .wg-row { opacity: 0.8; }
  /* "It's their time NOW" glow — same idea as the Day view's .tl2.av.live ring. Lime for
     the avatar's plan / your sessions, blue for the hobby (for-me) & avatar free-time. */
  .wg-lane.live { box-shadow: 0 0 0 2px var(--accent), 0 1px 2px rgba(0,0,0,0.25); }
  .wg-lane.hobby.live, .wg-lane.avhobby.live { box-shadow: 0 0 0 2px #38bdf8, 0 1px 2px rgba(0,0,0,0.25); }
  /* ✓ sits as a tiny corner badge so the activity emoji can center in the lane (matching
     the plan lane) instead of being shoved off-centre by an inline check. */
  .wg-me-chk { position: absolute; top: 1px; left: 2px; font-size: 8px; font-weight: 900; line-height: 1; color: #fff7ed; pointer-events: none; }
  /* Week check box — the compact mirror of the Day view's check rail. Lives in the block's
     top-right corner; its own pointer handler stops the body drag, so a tap here marks done
     while a tap on the body opens the editor (same split of duties as Day). */
  .wg-box { position: absolute; top: 2px; right: 2px; z-index: 5; padding: 0;
    width: 18px; height: 18px; border-radius: 6px; box-sizing: border-box;
    display: flex; align-items: center; justify-content: center;
    background: rgba(8,12,20,0.45); border: 1.5px solid rgba(var(--accent-rgb),0.6);
    color: #0b1220; font-size: 12px; font-weight: 900; line-height: 1;
    cursor: pointer; touch-action: manipulation; }
  .wg-box:disabled { cursor: default; opacity: 0.4; }
  /* Unchecked = small outline circle (an empty checkbox), like the Day rail's mark. */
  .wg-box-mark { width: 6px; height: 6px; border-radius: 50%; box-sizing: border-box; border: 1.5px solid var(--accent); }
  /* Checked = solid lime fill + ✓. */
  .wg-box.done { background: var(--accent); border-color: var(--accent); }
  /* JEK did it, you didn't = transparent dashed box holding your committed-self's faint face. */
  .wg-box.jekdone { background: transparent; border-style: dashed; border-color: rgba(var(--accent-rgb),0.4); }
  .wg-box-jek { display: flex; align-items: center; justify-content: center; opacity: 0.7; filter: grayscale(0.25); }
  /* Rested (ticketed) = lime chip holding the 🎟️; tap to cancel the rest. */
  .wg-box.rested { background: rgba(var(--accent-rgb),0.9); border-color: rgba(var(--accent-rgb),0.6); font-size: 9px; }
  .wg-box.unrestable { cursor: pointer; }
  /* Goal progress chip (replaces the start-time line on a goal task) — shows logged/target
     (3/8 or 50%), lime, fills solid when the goal is hit. READ-ONLY (a plain span): it only
     surfaces partial progress, so it can't be mistaken for the adjacent check box. */
  .wg-goal { align-self: flex-start; max-width: 100%; margin: 0; padding: 0 5px; height: 13px;
    display: inline-flex; align-items: center; gap: 2px; border-radius: 5px; overflow: hidden;
    background: rgba(var(--accent-rgb),0.16); border: 1px solid rgba(var(--accent-rgb),0.4);
    color: var(--accent); font-size: 9px; font-weight: 800; line-height: 1; white-space: nowrap;
    pointer-events: none; }
  .wg-goal.hit { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
  /* Grade-glyph legend — its OWN full-width line UNDER the tool buttons (order:2), sitting
     right above the day-header row whose ⭐/◑/○ it explains. Keeping it out of the button
     row stops it from crowding/overlapping the week-nav above. */
  .wg-legend { order: 2; flex-basis: 100%; display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 9px; margin: 1px 0 0; font-size: 9px; font-weight: 700; color: var(--text-dim); }
  .wg-legend > span { display: inline-flex; align-items: center; gap: 3px; }
  .wg-lg-g { font-size: 11px; line-height: 1; }
  .wg-lg-g.kept { color: var(--accent); }
  .wg-lg-g.half { color: var(--you); }
  .wg-lg-g.miss { color: var(--text-dim); }
  /* Emoji wrapper inside a lane — kept centered (week blocks show emoji only, no time). */
  .wg-lane .wg-row { display: flex; align-items: center; justify-content: center; }
  /* ── Clean (Google-Calendar style) full-width Week blocks ────────────────────
     One block per task per day, full column width, tinted by the activity's own
     colour (set inline). Name + time show when the block is tall enough; short
     blocks collapse to a centred emoji. */
  .wg-lane.clean { flex-direction: column; align-items: flex-start; justify-content: center; gap: 1px; padding: 1px 5px; }
  .wg-lane.clean:not(.tall) { align-items: center; justify-content: center; padding: 0; }
  .wg-lane.clean:not(.tall) .wg-name, .wg-lane.clean:not(.tall) .wg-time { display: none; }
  .wg-row.clean { display: flex; align-items: center; justify-content: flex-start; gap: 4px; max-width: 100%; min-width: 0; }
  .wg-name { font-size: 10px; font-weight: 600; line-height: 1.15; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
  .wg-time { font-size: 9px; line-height: 1; color: var(--text); opacity: 0.62; }
  .wg-lane.plan.jekdone.clean { opacity: 0.5; border-style: dashed; }
  .wg-lane.clean .wg-me-chk { left: auto; right: 3px; top: 2px; }
  .wg-plan-tix { position: absolute; top: 0; right: 2px; font-size: 11px; }
  .wg-block-resize { position: absolute; left: 0; right: 0; bottom: 0; height: 9px; cursor: ns-resize; touch-action: none; z-index: 4; }
  .wg-block-resize::after { content: ''; position: absolute; left: 50%; bottom: 1px; transform: translateX(-50%); width: 16px; height: 2px; border-radius: 2px; background: rgba(255,255,255,0.4); }
  /* Red "now" line spanning the whole grid, like Google Calendar. */
  .wg-now { position: absolute; left: 46px; right: 0; height: 2px; background: var(--danger); transform: translateY(-50%); z-index: 1; pointer-events: none; }
  .wg-now-dot { position: absolute; left: 0; top: 50%; width: 8px; height: 8px; border-radius: 50%; background: var(--danger); transform: translate(-50%, -50%); }
  /* Week view */
  .wk-wrap { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 14px; }
  .wk-scroll { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; }
  .wk-strip { display: flex; gap: 5px; }
  .wk-day {
    flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 5px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 9px 0;
  }
  .wk-day.today { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
  .wk-day-lbl { font-size: 11px; font-weight: 800; color: var(--text-dim); }
  .wk-day-glyph { font-size: 15px; line-height: 1; }
  .wk-day-glyph.behind { color: var(--danger); }
  .wk-day-glyph.future, .wk-day-glyph.none { opacity: 0.45; }
  .wk-amts { display: flex; flex-direction: column; gap: 10px; }
  .wk-amt-row { display: flex; align-items: center; gap: 12px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 11px 14px; }
  .wk-amt-emoji { flex-shrink: 0; font-size: 22px; line-height: 1; width: 26px; text-align: center; }
  .wk-amt-body { flex: 1; min-width: 0; }
  .wk-amt-top { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
  .wk-amt-name { font-weight: 700; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .wk-amt-val { flex-shrink: 0; font-size: 12px; font-weight: 800; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .wk-amt-track { height: 7px; border-radius: 999px; background: var(--surface-2); overflow: hidden; margin-top: 7px; }
  .wk-amt-fill { height: 100%; border-radius: 999px; transition: width 0.4s ease; }
  /* Empty-day prompt: a centered window floating over a blurred calendar grid. */
  .sched-cal-wrap { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
  /* Friend-compare selector (Schedule): JEK vs each friend; picking one shows their day. */
  .sched-cmp { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
  .sched-cmp-lbl { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
  .sched-cmp-chip { display: inline-flex; align-items: center; gap: 5px; background: var(--surface); border: 1px solid var(--border); border-radius: 999px; padding: 5px 12px; color: var(--text-muted); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; touch-action: manipulation; }
  .sched-cmp-chip.on { background: rgba(var(--accent-rgb),0.12); border-color: rgba(var(--accent-rgb),0.5); color: var(--accent); }
  .sched-cmp-em { font-size: 14px; line-height: 1; }
  .sched-friend { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 10px; }
  .sched-friend-top { display: flex; align-items: center; gap: 8px; }
  .sched-friend-em { font-size: 20px; line-height: 1; }
  .sched-friend-nm { font-weight: 800; font-size: 15px; }
  .sched-friend-pct { margin-left: auto; font-weight: 800; color: var(--accent); font-variant-numeric: tabular-nums; }
  .sched-friend .frd-cal { flex: 1; min-height: 0; }
  .sched-window-overlay {
    position: absolute; inset: 0; z-index: 12;
    display: flex; align-items: center; justify-content: center; padding: 16px;
    background: rgba(8, 12, 20, 0.55);
    -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  }
  .sched-window {
    width: 100%; max-width: 380px;
    display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px;
    background: var(--surface); border: 1px solid var(--border-strong);
    border-radius: var(--radius); padding: 28px 24px 24px;
    box-shadow: 0 24px 60px rgba(0,0,0,0.65);
  }
  .sched-window-icon {
    font-size: 38px; line-height: 1; color: var(--accent); margin-bottom: 6px;
  }
  .sched-window-title { font-weight: 800; font-size: 21px; }
  .sched-window-sub { margin: 4px 0 0; font-size: 13px; color: var(--text-muted); line-height: 1.5; }
  .sched-window-actions { margin-top: 16px; width: 100%; display: flex; flex-direction: column; gap: 10px; }
  .sched-window-actions .btn-primary,
  .sched-window-actions .btn-ghost { width: 100%; padding: 12px 14px; min-height: 0; white-space: nowrap; font-size: 14px; }
  .cal-head { display: flex; align-items: center; gap: 6px; }
  .cal-nav {
    flex-shrink: 0; width: 32px; height: 32px; border-radius: 50%;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    font-size: 15px; line-height: 1; cursor: pointer; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center;
  }
  .cal-nav:active { background: var(--border); }
  .cal-nav:disabled { opacity: 0.3; cursor: default; }
  .cal-date { position: relative; display: flex; align-items: center; gap: 8px; min-width: 0; }
  .cal-date-main { font-weight: 800; font-size: 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Tap the header date to open a date picker and jump to any day. */
  .cal-date-pick { display: inline-flex; align-items: center; gap: 5px; min-width: 0;
    background: none; border: 0; padding: 2px 4px; margin: 0; color: var(--text); cursor: pointer;
    border-radius: 8px; touch-action: manipulation; }
  .cal-date-pick:active { background: var(--surface-2); }
  .cal-date-caret { flex-shrink: 0; font-size: 10px; color: var(--text-dim); }
  /* The native input is invisible but anchored under the date so the picker pops up there. */
  .cal-date-input { position: absolute; left: 0; bottom: 0; width: 1px; height: 1px; opacity: 0; border: 0; padding: 0; pointer-events: none; }
  /* Themed month-calendar popover (replaces the native date picker) */
  .dp-backdrop { position: fixed; inset: 0; z-index: 70; background: rgba(0, 0, 0, 0.4); }
  /* Drops down from the header date button (its .cal-date wrapper is position:relative)
     rather than floating screen-centre, so it reads as a popover off the control. */
  .dp {
    position: absolute; top: calc(100% + 8px); left: 0; z-index: 80;
    width: 278px; max-width: calc(100vw - 28px);
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: 16px;
    padding: 12px; box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
  }
  .dp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
  .dp-month { font-size: 14px; font-weight: 800; color: var(--text); }
  .dp-nav { display: flex; gap: 5px; }
  .dp-arrow {
    width: 36px; height: 36px; border-radius: 9px; border: 1px solid var(--border);
    background: var(--surface-2); color: var(--text); font-size: 15px; line-height: 1;
    cursor: pointer; display: flex; align-items: center; justify-content: center; touch-action: manipulation;
  }
  .dp-arrow:active { background: var(--surface); }
  .dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0; }
  .dp-dow { margin-bottom: 4px; }
  .dp-wd { text-align: center; font-size: 10px; font-weight: 800; letter-spacing: 0.02em; color: var(--text-dim); padding: 2px 0; }
  .dp-cell {
    /* Fixed compact square-ish cell. Explicit height + box-model reset so a global
       <button> style can't inflate the row (that was ballooning the whole calendar). */
    height: 40px; min-width: 0; min-height: 0; padding: 0; margin: 0; box-sizing: border-box;
    border: 0; background: none; color: var(--text); font: inherit; font-size: 13px; font-weight: 600; line-height: 1;
    border-radius: 9px; cursor: pointer; display: flex; align-items: center; justify-content: center; touch-action: manipulation;
    position: relative;
  }
  .dp-cell.empty { pointer-events: none; height: 40px; }
  .dp-cell:not(.empty):not(:disabled):active { background: var(--surface-2); }
  .dp-cell:disabled { color: var(--text-dim); opacity: 0.32; cursor: default; }
  /* Today = a small dot under the number (a quiet marker), NOT a green number — so it never competes
     with the selected-day fill (Day mode) or the week band (Week mode). */
  .dp-cell.today { font-weight: 800; }
  .dp-cell.today::after { content: ''; position: absolute; left: 50%; bottom: 5px; width: 4px; height: 4px;
    border-radius: 50%; background: var(--accent); transform: translateX(-50%); }
  .dp-cell.sel { background: var(--accent); color: var(--accent-text); font-weight: 800; }
  .dp-cell.sel.today::after { background: var(--accent-text); }
  /* Week mode: the whole Mon–Sun row is ONE soft band (no single day stands out), rounded at both ends. */
  .dp-cell.wk-band { background: rgba(var(--accent-rgb), 0.14); color: var(--text); border-radius: 0; }
  .dp-cell.wk-band-first { border-top-left-radius: 9px; border-bottom-left-radius: 9px; }
  .dp-cell.wk-band-last { border-top-right-radius: 9px; border-bottom-right-radius: 9px; }
  .dp-foot { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; }
  .dp-foot-btn {
    background: none; border: 0; color: var(--accent); font: inherit; font-size: 13px; font-weight: 800;
    cursor: pointer; padding: 4px 2px; touch-action: manipulation;
  }
  .dp-foot-btn.ghost { color: var(--text-muted); }
  /* "Jump back to today/this week" shortcut — only shown when viewing another day.
     Neutral pill + a ↩ arrow so it reads as an action, not a "this is today" badge. */
  .cal-today {
    flex-shrink: 0; display: inline-flex; align-items: center; gap: 4px;
    font-size: 11px; font-weight: 700; color: var(--text-muted);
    background: var(--surface-2); border: 1px solid var(--border);
    border-radius: 999px; padding: 4px 10px; cursor: pointer; touch-action: manipulation;
  }
  .cal-today::before { content: '↩'; font-size: 12px; line-height: 1; color: var(--accent); }
  .cal-today:active { background: var(--border); color: var(--text); }
  .cal-pill {
    flex-shrink: 0; font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums;
    border-radius: 999px; padding: 5px 11px; background: var(--surface-2); color: var(--text);
  }
  .cal-pill.good { background: rgba(var(--accent-rgb),0.16); color: var(--accent); }
  .cal-pill.mid { background: rgba(var(--you-rgb),0.14); color: var(--you); }
  .cal-pill.bad { background: rgba(248,113,113,0.14); color: var(--danger); }
  .cal-pill.plan { color: var(--text-muted); }
  /* Forced-rest ticket bar (Schedule Day view) */
  /* margin:0 — spacing handled by .sched-screen flex gap; own margins caused ~22px above / ~18px
     below vs ~16px / ~4px in the compact expanded overlay. */
  .sched-ticket { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 0;
    padding: 7px 11px; border-radius: 10px; background: var(--surface-2);
    border: 1px solid var(--border); font-size: 12px; }
  /* A single rested ("excused") task, with an × to put it back in the grade. */
  .ticket-chip { flex-shrink: 0; display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
    padding: 3px 4px 3px 9px; border-radius: 999px; font-size: 11px; font-weight: 600;
    background: rgba(var(--accent-rgb),0.14); border: 1px solid rgba(var(--accent-rgb),0.5); color: var(--accent); }
  .ticket-chip-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ticket-chip-x { position: relative; flex-shrink: 0; width: 16px; height: 16px; border-radius: 50%; padding: 0; line-height: 1;
    display: inline-flex; align-items: center; justify-content: center; font-size: 13px;
    background: rgba(11,18,32,0.35); border: 0; color: var(--accent); cursor: pointer; touch-action: manipulation; }
  /* Invisible hit-area expander: 16px button → ~32px tap target. -8px (not larger) keeps
     clear of the RestTaskMenu ~13px to the right and of chips on the next wrapped row. */
  .ticket-chip-x::after { content: ''; position: absolute; inset: -8px; }
  .ticket-chip-x:active { background: rgba(11,18,32,0.7); color: #fff; }
  .sched-ticket.on { background: rgba(var(--accent-rgb),0.10); border-color: rgba(var(--accent-rgb),0.4); }
  .sched-ticket-msg { flex: 0 1 auto; min-width: 0; color: var(--text-muted); display: flex; align-items: center; gap: 7px; white-space: nowrap; }
  .sched-ticket-actions { margin-left: auto; flex-shrink: 0; display: flex; align-items: center; flex-wrap: nowrap; gap: 6px; justify-content: flex-end; }
  /* Keep the message on ONE line: the text clips with an ellipsis if ever too narrow,
     while the draggable 🎟️ handle (and its ring) is never clipped. */
  .sched-ticket-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .sched-ticket-emo { flex-shrink: 0; font-size: 17px; line-height: 1; display: inline-block; transform: rotate(45deg); }
  /* The 🎟️ doubles as a drag handle when there are tickets + restable tasks. A soft
     ring + grab cursor + gentle bob hint that it can be picked up and dropped on a task. */
  .sched-ticket-emo.grab { cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none;
    border-radius: 6px; padding: 2px; animation: tixBob 2.4s ease-in-out infinite; }
  .sched-ticket-emo.grab:active { cursor: grabbing; animation: none; }
  @keyframes tixBob { 0%, 100% { transform: rotate(45deg) translateY(0); } 50% { transform: rotate(45deg) translateY(-1.5px); } }
  /* Tilted ticket glyph (45°) — shared by every standalone 🎟️ outside the banner. */
  .tix-tilt { display: inline-block; transform: rotate(45deg); }
  .sched-ticket.on .sched-ticket-msg { color: #7dd3fc; font-weight: 600; }
  .sched-ticket-btn { flex-shrink: 0; font-size: 11px; font-weight: 700; padding: 5px 10px; white-space: nowrap;
    border-radius: 999px; background: var(--accent); color: var(--accent-text); border: 0;
    cursor: pointer; touch-action: manipulation; }
  .sched-ticket-btn.cancel { background: var(--surface); color: var(--text-muted); border: 1px solid var(--border); }
  .sched-ticket-btn:disabled { opacity: 0.45; cursor: default; }
  .sched-ticket-sel { flex-shrink: 0; max-width: 38%; font-size: 11px; font-weight: 600; padding: 5px 8px;
    border-radius: 999px; background: var(--surface); color: var(--text-muted);
    border: 1px solid var(--border); cursor: pointer; touch-action: manipulation; }
  /* Drag a 🎟️ onto a task: floating ghost + lit-up drop target. */
  /* Matches the calendar-mode ghost EXACTLY: no pill background — just the emoji + name floating,
     kept legible by a drop-shadow (emoji) and text-shadow (name). */
  .tix-ghost { position: fixed; z-index: 12000; pointer-events: none; display: none; flex-direction: row;
    align-items: center; gap: 8px; transform: translate(-15px, -50%); white-space: nowrap; line-height: 1; }
  body.tix-dragging, body.tix-dragging * { cursor: grabbing !important; }
  body.tix-dragging { user-select: none; -webkit-user-select: none; }
  /* Every restable JEK block hints as a target while a ticket is in hand; the one
     under the finger lights up brighter. */
  body.tix-dragging .tl2.av[data-restable="1"] { outline: 1.5px dashed rgba(56,189,248,0.4); outline-offset: 2px; border-radius: 12px; }
  .tl2.av.tix-drop-hot { outline: 2px dashed rgba(56,189,248,0.95) !important; outline-offset: 2px;
    box-shadow: 0 0 0 4px rgba(56,189,248,0.20); border-radius: 12px; }
  /* Placement mode lives INSIDE the .sched-ticket bar (toggled via .sched-mode-toggle), so it's the
     exact same height/padding as the rest-ticket bar. Emoji-only draggable chips + a scroll strip. */
  .sched-ticket.place { flex-wrap: nowrap; }
  /* Rest mode = single line too (parity with place mode) so the bar height never jumps on toggle. */
  .sched-ticket:not(.place) { flex-wrap: nowrap; }
  /* The shelf's "drag" hint fits on desktop; on a phone the row is tight (shelf + Rest/Away), so hide it. */
  .place-bar-lbl2 { font-size: 12px; font-weight: 700; color: var(--text-muted); flex: 0 0 auto; line-height: 1; white-space: nowrap; }
  /* Horizontally scrollable palette. Chips start a drag on pointerdown (so a swipe ON a chip can't
     scroll), which used to leave off-screen activities unreachable — no scrollbar, no way to pan.
     Fix: a slim always-usable scrollbar (drag on desktop) + a right-edge fade that signals "more →",
     and the row also scrolls on mouse-wheel (onWheel handler). */
  /* Scroll via the ‹ › arrows (and mouse-wheel) — no visible scrollbar, so the strip adds no extra
     height. A soft right-edge fade still hints there's more to the right. */
  .place-bar-tickets { display: flex; align-items: center; gap: 8px; overflow-x: auto; flex: 1; min-width: 0; padding: 0 4px;
    -webkit-overflow-scrolling: touch; scrollbar-width: none; scroll-behavior: smooth;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent); }
  .place-bar-tickets::-webkit-scrollbar { display: none; }
  .place-ticket { display: grid; place-items: center; width: 28px; height: 28px; flex: 0 0 auto;
    border-radius: 50%; border: 1.5px solid var(--border-strong); background: var(--surface-2);
    cursor: grab; touch-action: none; padding: 0; }
  .place-ticket:active { cursor: grabbing; transform: scale(0.94); }
  /* Already-scheduled activity: stays on the strip, just dimmed (not removed). */
  .place-ticket.placed { opacity: 0.38; }
  .place-ticket-emo { display: grid; place-items: center; width: 16px; height: 16px; }
  /* Scroll arrows for the palette — tap-friendly on touch where a swipe would drag a chip instead. */
  .place-scroll { flex: 0 0 auto; width: 24px; height: 24px; display: grid; place-items: center;
    border-radius: 50%; border: 1px solid var(--border-strong); background: var(--surface-2);
    color: var(--text-dim); font-size: 16px; line-height: 1; cursor: pointer; padding: 0; touch-action: manipulation; }
  .place-scroll:active { background: var(--surface); color: var(--text); }
  /* Rest ↔ Place mode switch, pinned to the bar's LEFT edge (first child of the bar). */
  .sched-mode-toggle { flex: 0 0 auto; display: inline-flex; gap: 2px; margin-right: 4px; padding: 2px;
    border-radius: 999px; border: 1px solid var(--border); background: var(--card2, var(--surface-2)); }
  .sched-mode-toggle .smt { width: 26px; height: 24px; position: relative; display: grid; place-items: center; border: none; border-radius: 999px;
    background: transparent; font-size: 13px; cursor: pointer; opacity: 0.5; touch-action: manipulation; }
  /* Invisible larger tap target so a thumb doesn't miss / hit the wrong mode toggle. */
  .sched-mode-toggle .smt::after { content: ''; position: absolute; inset: -6px; }
  .sched-mode-toggle .smt.on { background: rgba(var(--accent-rgb),0.2); opacity: 1; }
  /* Placement ghost: bare emoji (ticket feel — no pill/circle) that rides under the finger, with
     the activity NAME and drop TIME riding to its RIGHT. A no-gif emoji gets the same gentle
     .emoji-sway as it has in the bar (added in startPlaceDrag, phase-synced globally). The emoji
     is anchored under the cursor (translateX ≈ -½ emoji) so the label flows off to the right. */
  .place-ghost { position: fixed; z-index: 12000; pointer-events: none; display: none; flex-direction: row;
    align-items: center; gap: 8px; transform: translate(-15px, -50%); white-space: nowrap; line-height: 1; }
  .place-ghost-e { width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
    font-size: 26px; line-height: 1; filter: drop-shadow(0 4px 8px rgba(0,0,0,0.5)); }
  .place-ghost-e img { width: 30px; height: 30px; object-fit: contain; }
  /* No pill behind the text now, so a strong shadow keeps the name/time legible over the timeline. */
  .place-ghost-lbl { display: inline-flex; align-items: center; gap: 7px; color: var(--text); font-size: 13px; font-weight: 700;
    text-shadow: 0 1px 3px rgba(0,0,0,0.9), 0 0 2px rgba(0,0,0,0.85); }
  .place-ghost-lbl:empty { display: none; }
  .place-ghost-t { opacity: 0.8; font-weight: 600; }
  .place-ghost-n:empty, .place-ghost-t:empty { display: none; }
  /* ── Ticket mode: the 🎟️ drag chip + its hint. One thing only — the cosmetic status-emoji shelf
     that used to share this strip was cut (it dragged like the 🎟️ but meant nothing). ─────────── */
  .tix-shelf { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; }
  /* The tickets you still hold, fanned like a hand of cards. Overlap keeps 8 of them inside a phone's
     width; each card lifts on hover/press so it reads as a separate, grabbable object. */
  .tix-fan { display: inline-flex; align-items: center; flex: 0 0 auto; padding-right: 6px; }
  .tix-card { width: 30px; height: 30px; flex: 0 0 auto; display: grid; place-items: center; padding: 0;
    margin-right: -13px; /* the fan overlap */
    border-radius: 50%; border: 1px solid rgba(var(--accent-rgb),0.55); background: var(--surface-2);
    box-shadow: 0 2px 6px rgba(0,0,0,0.45); cursor: grab; touch-action: none;
    transition: transform 0.12s ease, box-shadow 0.12s ease; }
  .tix-card:last-child { margin-right: 0; }
  .tix-card.grab:hover { transform: translateY(-3px); box-shadow: 0 6px 12px rgba(0,0,0,0.5); }
  .tix-card.grab:active { cursor: grabbing; transform: translateY(-1px) scale(0.95); }
  .tix-card img { width: 18px; height: 18px; object-fit: contain; }
  .tix-card.off { border-color: var(--border); opacity: 0.35; cursor: default; box-shadow: none; }
  /* The 🎟️ = how many rests are left this week. A WIDER pill (emoji + count inline) so the number
     never gets clipped; the accent ring says "this one does something". */
  .tix-chip { display: inline-flex; align-items: center; justify-content: center; gap: 3px;
    width: auto; padding: 0 9px 0 7px; border-radius: 999px; border-color: rgba(var(--accent-rgb),0.55); }
  .tix-chip .tix-chip-n { font-size: 12px; font-weight: 800; line-height: 1; color: var(--accent);
    font-variant-numeric: tabular-nums; }
  .tix-chip.off { opacity: 0.5; cursor: default; border-color: var(--border); }
  .tix-chip.off .tix-chip-n { color: var(--text-dim); }
  /* Says out loud what the chip is for — a 28px circle has no affordance that reads as "drag me". */
  .tix-shelf-hint { font-size: 11px; color: var(--text-dim); white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; min-width: 0; }
  @media (max-width: 400px) { .tix-shelf-hint { display: none; } }
  /* The floating 🎟️ that rides the finger mid-drag (markup reuses .st-ghost-e/.st-ghost-n). */
  .st-ghost-e { width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
    font-size: 26px; line-height: 1; filter: drop-shadow(0 4px 8px rgba(0,0,0,0.5)); }
  .st-ghost-e img { width: 30px; height: 30px; object-fit: contain; }
  .st-ghost-n { font-size: 13px; font-weight: 700; color: var(--text); white-space: nowrap;
    text-shadow: 0 1px 3px rgba(0,0,0,0.9), 0 0 2px rgba(0,0,0,0.85); }
  .st-ghost-n:empty { display: none; }
  body.place-dragging, body.place-dragging * { cursor: grabbing !important; }
  body.place-dragging { user-select: none; -webkit-user-select: none; }
  .tl-canvas.place-hot { border-radius: 10px; }
  /* Drop preview: a dashed PILL that snaps to the exact slot (JEK lane, same left/right + coord
     system as a real .tl2.av block) where the drop will land — replaces the old whole-canvas
     frame so you see precisely where it goes, right where the time reads out. Injected/positioned
     imperatively in startPlaceDrag; height = the default 45-min block. */
  .place-drop-preview { position: absolute; left: 50%; right: 6px; pointer-events: none; z-index: 20;
    border: 2px dashed rgba(var(--accent-rgb),0.95); border-radius: 999px;
    background: rgba(var(--accent-rgb),0.10); box-shadow: 0 0 0 3px rgba(var(--accent-rgb),0.12); }
  /* Avatar tab: weekly rest-ticket quota stepper. */
  .tix-quota { display: flex; align-items: center; gap: 12px; margin: 2px 0 0; }
  .tix-quota-btn { width: 40px; height: 40px; flex-shrink: 0; border-radius: 9px; font-size: 18px;
    font-weight: 700; background: var(--surface-2); color: var(--text); border: 1px solid var(--border);
    cursor: pointer; touch-action: manipulation; display: inline-flex; align-items: center; justify-content: center; }
  .tix-quota-btn:disabled { opacity: 0.4; cursor: default; }
  .tix-quota-val { min-width: 22px; text-align: center; font-size: 19px; font-weight: 800; color: var(--text); }
  .tix-quota-pips { display: inline-flex; gap: 3px; margin-left: 2px; }
  .tix-pip { font-size: 15px; line-height: 1; transform: rotate(45deg); filter: grayscale(1); opacity: 0.32; }
  .tix-pip.on { filter: none; opacity: 1; }
  /* Custom "Rest a task…" dropdown (replaces the native <select> so the open list matches the dark UI) */
  .rest-menu { position: relative; flex-shrink: 0; }
  .rest-menu-trigger { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 700;
    padding: 5px 10px; border-radius: 999px; background: var(--surface); color: var(--text-muted);
    border: 1px solid var(--border); cursor: pointer; touch-action: manipulation; white-space: nowrap; }
  .rest-menu-trigger:active { background: var(--surface-2); }
  .rest-menu.open .rest-menu-trigger { color: var(--text); border-color: var(--text-dim); }
  .rest-menu-caret { font-size: 9px; opacity: 0.7; transition: transform 0.15s ease; }
  .rest-menu.open .rest-menu-caret { transform: rotate(180deg); }
  /* Opens UPWARD from a strip that always sits in the lower half — so it grows toward the roomy top,
     never down under the bottom nav. Height is capped; only the target list inside scrolls. */
  .rest-menu-pop { position: absolute; bottom: calc(100% + 6px); top: auto; right: 0; z-index: 120; min-width: 172px;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 5px;
    box-shadow: 0 -14px 34px rgba(0,0,0,0.5); display: flex; flex-direction: column; gap: 2px;
    max-height: min(64vh, 440px); overflow: hidden; animation: rest-menu-in 0.13s ease; }
  .rest-menu-scroll { overflow-y: auto; overscroll-behavior: contain; flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column; gap: 2px; }
  @keyframes rest-menu-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
  .rest-menu-head { padding: 4px 9px 6px; font-size: 10px; font-weight: 800; letter-spacing: 0.05em;
    text-transform: uppercase; color: var(--text-dim); }
  .rest-menu-item { display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
    padding: 8px 10px; border-radius: 8px; background: transparent; border: 0; color: var(--text);
    font-size: 13px; font-weight: 600; cursor: pointer; touch-action: manipulation; }
  .rest-menu-item:hover { background: var(--surface); }
  .rest-menu-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: 50%; }
  .rest-menu-emoji { flex-shrink: 0; display: inline-flex; }
  .rest-menu-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .rest-menu-day { color: var(--accent); font-weight: 700; }
  .rest-menu-day.sep { margin-top: 4px; padding-top: 10px; border-top: 1px solid var(--border); }
  .rest-menu-item:disabled { opacity: 0.4; cursor: default; }
  .rest-menu-item:disabled:hover { background: transparent; }
  /* Row = task name (opens the multi-tag picker) + a 🎟️ rest-this-task shortcut on the right. */
  .rest-menu-row { display: flex; align-items: center; gap: 2px; border-radius: 8px; }
  .rest-menu-row .rest-menu-item { flex: 1; }
  .rest-menu-row.tagging { background: var(--surface); }
  .rest-menu-rest { flex-shrink: 0; width: 30px; height: 30px; display: grid; place-items: center;
    border-radius: 8px; background: transparent; border: 0; font-size: 15px; cursor: pointer;
    opacity: 0.75; touch-action: manipulation; }
  .rest-menu-rest:hover { background: var(--surface); opacity: 1; }
  /* Multi-select status grid shown under a task when you tap it — stamp several at once. */
  .rest-menu-tags { padding: 6px 8px 9px; display: flex; flex-direction: column; gap: 8px; }
  .rmt-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 5px; }
  .rmt-chip { width: 100%; aspect-ratio: 1; display: grid; place-items: center; border-radius: 8px;
    background: var(--surface-2); border: 1px solid var(--border); cursor: pointer; padding: 0;
    touch-action: manipulation; transition: border-color 0.1s, transform 0.1s; }
  .rmt-chip:active { transform: scale(0.92); }
  .rmt-chip.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 18%, transparent); }
  .rmt-apply { align-self: stretch; padding: 8px; border-radius: 8px; border: 0; cursor: pointer;
    background: var(--accent); color: var(--accent-text); font-weight: 800; font-size: 13px;
    touch-action: manipulation; }
  .rmt-apply:disabled { opacity: 0.4; cursor: default; }
  /* Head row holds the title + a small Manage/Done toggle. */
  .rest-menu-head { display: flex; align-items: center; justify-content: space-between; }
  .rmt-manage-btn { padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border); background: transparent;
    color: var(--text-muted); font-size: 10px; font-weight: 800; letter-spacing: 0.03em; text-transform: uppercase; cursor: pointer; }
  .rmt-manage-btn.on { color: var(--accent); border-color: var(--accent); }
  /* Manage list: rename (custom name shows on the drag ghost) + delete each status. */
  .rmt-manage-list { display: flex; flex-direction: column; gap: 5px; padding: 4px 4px 8px; }
  .rmt-manage-row { display: flex; align-items: center; gap: 8px; }
  .rmt-manage-emoji { flex: 0 0 auto; width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; }
  .rmt-name-input { flex: 1; min-width: 0; background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
    color: var(--text); font-size: 13px; font-weight: 600; padding: 6px 8px; }
  .rmt-name-input:focus { outline: none; border-color: var(--accent); }
  .rmt-del { flex: 0 0 auto; width: 26px; height: 26px; border-radius: 8px; border: 0; background: transparent;
    color: #ef4444; font-size: 18px; font-weight: 800; line-height: 1; cursor: pointer; }
  .rmt-del:hover { background: rgba(239,68,68,0.12); }
  .rmt-manage-add { margin-top: 2px; padding: 8px; border-radius: 8px; border: 1px dashed var(--border-strong);
    background: transparent; color: var(--text-muted); font-size: 13px; font-weight: 700; cursor: pointer; }
  .rmt-manage-add:hover { border-color: var(--accent); color: var(--accent); }
  /* ＋ add / － manage tool chips at the end of the status grid. */
  .rmt-chip.rmt-tool { color: var(--text-dim); font-size: 16px; font-weight: 800; border-style: dashed; }
  .rmt-chip.rmt-tool.on { color: var(--accent); border-color: var(--accent); border-style: solid; background: color-mix(in srgb, var(--accent) 16%, transparent); }
  /* Remove-mode: a × badge on each deletable chip; a red wash signals "tap to delete". */
  .rmt-chip.removing { border-color: rgba(239,68,68,0.6); background: rgba(239,68,68,0.10); }
  .rmt-chip .rmt-x { position: absolute; top: -5px; right: -5px; width: 15px; height: 15px; border-radius: 50%;
    background: #ef4444; color: #fff; font-size: 11px; font-weight: 800; line-height: 15px; text-align: center;
    box-shadow: 0 0 0 1.5px var(--surface-2); }
  .rmt-chip { position: relative; overflow: visible; }
  /* The ＋-add picker of extra emoji, shown under the status grid. */
  .rmt-addpop { display: grid; grid-template-columns: repeat(6, 1fr); gap: 5px; padding: 4px 4px 8px; }
  .rmt-addpop .st-add-opt { width: 100%; height: auto; aspect-ratio: 1; }
  /* Emoji-first rest menu: a status grid up top, then "apply to all / one task" rows. */
  .rest-status-grid { padding: 2px 4px 6px; }
  .rest-menu-head.sep { margin-top: 4px; padding-top: 8px; border-top: 1px solid var(--border); }
  .rest-menu-all { color: var(--accent); font-weight: 700; }
  .rest-menu-empty { padding: 8px 10px; font-size: 12px; color: var(--text-dim); }
  .cal-add {
    flex-shrink: 0; width: 40px; height: 40px; border-radius: 12px;
    background: var(--accent); color: var(--accent-text); border: 0;
    font-size: 20px; font-weight: 700; line-height: 1; cursor: pointer; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center;
  }
  .cal-add:active { background: var(--accent-hover); }
  /* List/agenda toggle button in the calendar header (sits just left of ＋). */
  .cal-list {
    flex-shrink: 0; margin-left: auto; width: 40px; height: 40px; border-radius: 12px;
    background: var(--surface-2); color: var(--text-muted); border: 1px solid var(--border);
    font-size: 15px; line-height: 1; cursor: pointer; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center;
  }
  .cal-list:active { background: var(--surface); color: var(--text); }
  /* Both toolbar icon buttons share .cal-list, so margin-left:auto applied to BOTH — opening a
     second auto-gap that stranded routines alone in the middle. Only the FIRST of the right
     cluster should push off; reset any following one so they group tight against ＋. */
  .cal-head .cal-list ~ .cal-list { margin-left: 0; }
  /* Expand-to-full-page button (sits between ☰ and ＋; no auto-margin so it groups tight). */
  .cal-expand {
    flex-shrink: 0; width: 40px; height: 40px; border-radius: 12px;
    background: var(--surface-2); color: var(--text-muted); border: 1px solid var(--border);
    font-size: 17px; line-height: 1; cursor: pointer; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center;
  }
  .cal-expand:active { background: var(--surface); color: var(--text); }
  /* Edit (delete-mode) toggle — took the expand button's toolbar slot; icon-only, same chrome as
     ☰, with an accent-lit ON state while delete mode is active. */
  .cal-edit {
    flex-shrink: 0; width: 40px; height: 40px; border-radius: 12px;
    background: var(--surface-2); color: var(--text-muted); border: 1px solid var(--border);
    line-height: 1; cursor: pointer; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center;
  }
  .cal-edit:active { background: var(--surface); color: var(--text); }
  .cal-edit.on { background: rgba(var(--accent-rgb),0.18); border-color: rgba(var(--accent-rgb),0.55); color: var(--accent); }
  /* Ultra-narrow phones (≤360, e.g. iPhone SE): tighten the day header so ＋ never bleeds off-edge. */
  @media (max-width: 360px) {
    .cal-head { gap: 6px; }
    .cal-nav, .cal-add, .cal-list, .cal-expand, .cal-edit { width: 30px; height: 30px; }
    .cal-nav { font-size: 14px; }
    .cal-add { font-size: 18px; }
    /* The day-total pill duplicates the TODAY card right above — drop it on tiny screens so the
       date ("Today") shows in full and the ＋ never bleeds off the edge. */
    .cal-pill { display: none; }
  }
  /* In the non-expanded day view, the ticket bar sits in the .sched-screen flex column (gap:14px).
     Pull the timeline up by 10px so the ticket→grid gap is ~4px — matching the expanded overlay
     where .sched-ticket margin-bottom(4px)+no flex gap = 4px total. Only fires in day view
     (week view has no .sched-ticket sibling before .sched-cal-wrap). */
  .sched-ticket + .tix-ghost + .sched-cal-wrap:not(.full) { margin-top: -10px; }
  /* Expanded timeline: fills the app frame's content area (below header, above nav) — NOT the
     whole desktop viewport. Positioned via JS-measured fixed rect (matches .app-main) so it does
     NOT introduce a positioned ancestor that would re-anchor the bottom sheets. */
  .sched-cal-wrap.full {
    position: fixed; z-index: 50; flex: none;
    background: var(--bg); padding: 10px 14px 12px;
  }
  /* Day toolbar + rest-ticket / Away bar pinned to the top of the expanded page (don't scroll
     with the timeline). flex:0 0 auto so they keep their height and the timeline takes the rest. */
  .sched-full-head { flex: 0 0 auto; }
  .sched-full-head .cal-head { margin-bottom: 8px; }
  /* In expanded mode the ticket bar sits in .sched-full-head (no flex gap), so restore the
     small gap below it that the global .sched-ticket{margin:0} reset removed — matches the
     ~4px the day view gets via the -10px timeline pull. */
  .sched-full-head .sched-ticket { margin-bottom: 4px; }
  /* Toolbar across the top of the expanded timeline: day-nav on the LEFT, actions on the RIGHT
     (Edit · 📋 copy · ☰ list · ＋ add · ✕ close). Wraps if too tight. */
  .sched-full-bar { flex: 0 0 auto; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px; padding: 0 0 8px; }
  .sched-full-date { display: flex; align-items: center; gap: 2px; min-width: 0; }
  .sched-full-date .cal-nav { width: 32px; height: 32px; font-size: 15px; }
  .sched-full-date .cal-date-main { font-size: 15px; }
  .sched-full-date .cal-date-pick { padding: 2px 2px; }
  .sched-full-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 6px; }
  /* Compact the action buttons so the day-nav + actions fit one line. */
  .sched-full-actions .sched-bar-icon, .sched-full-actions .sched-collapse { width: 33px; height: 33px; }
  .sched-full-actions .act-edit-toggle { padding: 5px 10px; }
  .sched-bar-icon {
    flex-shrink: 0; width: 38px; height: 38px; border-radius: 50%;
    background: var(--surface-2); color: var(--text-muted); border: 1px solid var(--border);
    font-size: 18px; line-height: 1; cursor: pointer; touch-action: manipulation;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .sched-bar-icon:active { background: var(--surface); color: var(--text); }
  .sched-bar-icon.add { background: var(--accent); color: var(--accent-text); border-color: var(--accent); font-weight: 700; }
  .sched-bar-icon.add:active { background: var(--accent-hover); }
  .sched-collapse {
    flex-shrink: 0; z-index: 9001;
    width: 38px; height: 38px; border-radius: 50%;
    background: var(--surface-2); color: var(--text); border: 1px solid var(--border);
    font-size: 16px; line-height: 1; cursor: pointer; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 2px 10px rgba(0,0,0,0.35);
  }
  .sched-collapse:active { background: var(--surface); }
  /* Routines sheet — named day-templates you slot onto each weekday */
  .rt-section-lbl { font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-dim); margin: 14px 0 6px; }
  .rt-list { display: flex; flex-direction: column; gap: 6px; }
  .rt-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 12px; background: var(--surface-2); }
  .rt-emo { font-size: 18px; line-height: 1; }
  .rt-name { flex: 1; min-width: 0; font-size: 14px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .rt-count { font-size: 12px; color: var(--text-muted); background: var(--surface); border-radius: 999px; padding: 2px 8px; }
  /* Thumb-sized (was 26px — under the ~44px target on the one sheet he taps daily). Armed = the
     in-theme two-tap confirm that replaced the native confirm() dialog. */
  .rt-del { min-width: 34px; height: 34px; padding: 0 8px; border-radius: 999px; border: none; background: transparent; color: var(--text-muted); font-size: 13px; cursor: pointer; flex-shrink: 0; }
  .rt-del.armed { background: rgba(239,68,68,0.16); color: #ef4444; font-size: 11px; font-weight: 800; border: 1px solid rgba(239,68,68,0.5); }
  .rt-del:active { background: var(--surface); color: var(--text); }
  /* "Use" = load a saved week routine into the day grid (accent pill, distinct from ✕). */
  .rt-load { flex-shrink: 0; border: 1px solid rgba(var(--accent-rgb),0.5); background: rgba(var(--accent-rgb),0.12); color: var(--accent); font-size: 12px; font-weight: 700; border-radius: 999px; padding: 4px 12px; cursor: pointer; }
  .rt-load:active { background: rgba(var(--accent-rgb),0.22); }
  .rt-save { display: flex; gap: 8px; margin-top: 10px; }
  .rt-input { flex: 1; min-width: 0; padding: 9px 12px; border-radius: 12px; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); font-size: 14px; }
  .rt-input::placeholder { color: var(--text-muted); }
  .rt-week { display: flex; flex-direction: column; gap: 6px; }
  .rt-weekrow { display: flex; align-items: center; gap: 10px; }
  .rt-wd { width: 34px; flex-shrink: 0; font-size: 13px; font-weight: 700; color: var(--text-dim); }
  .rt-select { flex: 1; min-width: 0; padding: 8px 10px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); font-size: 14px; }
  /* "Copy a day" model — the real 7 weekdays; tap a day to expand its activities, or Copy to… others */
  .rt-day { border: 1px solid var(--border); border-radius: 12px; background: var(--surface-2); overflow: hidden; }
  /* Row whose inline picker is open — a NEUTRAL emphasis (not accent). Accent is reserved for the
     weekday chips you actually pick, so accent always means "the day(s) you selected", never shifts
     meaning between the copy/borrow directions. */
  .rt-day.src { border-color: var(--text-dim); background: var(--surface); }
  /* Brief confirmation flash on days that just received a copy. */
  .rt-day.flash { animation: rt-flash 1.2s ease-out; }
  @keyframes rt-flash { 0%,15% { background: rgba(52,211,153,0.28); border-color: #34d399; } 100% { background: var(--surface-2); border-color: var(--border); } }
  .rt-dayrow { display: flex; align-items: center; gap: 8px; padding-right: 12px; }
  .rt-dayhead { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; background: none; border: none; padding: 11px 12px; cursor: pointer; text-align: left; color: inherit; }
  .rt-dayhead:disabled { cursor: default; }
  .rt-dayhead .rt-wd { width: auto; min-width: 40px; font-size: 14px; font-weight: 700; color: var(--text); }
  .rt-daycount { flex: 1; min-width: 0; display: flex; align-items: center; gap: 7px; overflow: hidden; }
  .rt-daynum { flex-shrink: 0; font-size: 12px; color: var(--text-muted); }
  .rt-dayemos { flex: 1; display: inline-flex; align-items: center; gap: 2px; min-width: 0; overflow: hidden; white-space: nowrap; font-size: 15px; line-height: 1; }
  .rt-chev { flex-shrink: 0; color: var(--text-muted); font-size: 11px; transition: transform .15s; }
  .rt-chev.open { transform: rotate(90deg); }
  /* Expanded activity list — a darker inset (like the sheet base) so the surface-2 agenda-row cards
     inside it pop exactly like the "Today's tasks" agenda. agenda-row carries its own margin-bottom. */
  /* The chevron already rotates over 150ms; the body it points at used to pop in at 0ms — they now
     settle together. */
  @keyframes rtBodyIn { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: none; } }
  .rt-daybody { background: var(--bg); padding: 8px 10px 2px; animation: rtBodyIn .16s ease-out; }
  /* Compact rows inside the routine's day-expansion (the full agenda-row is too tall for a long day). */
  .rt-daybody .agenda-row { cursor: default; padding: 6px 10px; margin-bottom: 4px; border-radius: 9px; gap: 8px; }
  .rt-daybody .agenda-row:active { border-color: var(--border); }
  .rt-daybody .agenda-time { width: 82px; font-size: 11px; }
  .rt-daybody .agenda-name { font-size: 13px; }
  .rt-daybody .agenda-dot { width: 8px; height: 8px; }
  /* Borrow-preview variant sits inside an actionbox (not a day card) — round its corners itself. */
  .rt-daybody--inset { border-radius: 10px; margin-bottom: 10px; }
  .rt-emoji { display: inline-flex; align-items: center; line-height: 1; }
  /* Saved-routines: "+ Save a day" button + the save form card. */
  .rt-savebtn { width: 100%; margin-top: 8px; padding: 9px; text-align: center; }
  .rt-saveform { border: 1px solid var(--border); border-radius: 12px; margin-top: 8px; }
  .rt-saveform .rt-input { width: 100%; box-sizing: border-box; }
  .rt-copybtn { flex-shrink: 0; border: 1px solid rgba(var(--accent-rgb),0.5); background: rgba(var(--accent-rgb),0.12); color: var(--accent); font-size: 12px; font-weight: 700; border-radius: 999px; padding: 9px 14px; cursor: pointer; }
  .rt-copybtn:active { background: rgba(var(--accent-rgb),0.22); }
  .rt-copybtn:disabled { opacity: .4; cursor: default; border-color: var(--border); background: transparent; color: var(--text-muted); }
  /* "Make like another day" — the borrow action on empty days. Neutral outline so it reads as a
     secondary, non-accent action distinct from the accent-filled "Copy to…". */
  .rt-copybtn.borrow { border-color: var(--border); background: transparent; color: var(--text-dim); font-weight: 600; }
  .rt-copybtn.borrow:active { background: var(--surface); color: var(--text); }
  /* Button reads "active" while its inline picker is open, so it's clear which day you're acting on. */
  .rt-copybtn.on { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
  /* Inline copy/borrow picker — opens right under the day row, separated by a hairline inside the card. */
  .rt-actionbox { padding: 10px 12px 12px; border-top: 1px solid var(--border); }
  .rt-actionbox .weekday-row { margin: 6px 0 12px; }
  .rt-actionbox .rt-section-lbl { margin: 0 0 2px; }
  .weekday-chip:disabled { opacity: .32; cursor: default; }
  .rt-copybox { margin-top: 14px; padding: 12px; border: 1px solid var(--accent); border-radius: 14px; background: rgba(var(--accent-rgb),0.06); }
  .rt-targets { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 12px; }
  .rt-chip { display: inline-flex; align-items: center; gap: 6px; padding: 7px 13px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); font-size: 14px; font-weight: 600; cursor: pointer; }
  .rt-chip.on { background: rgba(var(--accent-rgb),0.16); border-color: var(--accent); color: var(--accent); }
  .rt-chip input { accent-color: var(--accent); }
  .rt-copyactions { display: flex; gap: 8px; }
  .rt-copyactions .btn-primary, .rt-copyactions .btn-ghost { flex: 1; }
  /* "Clear week" demoted from a full-width button to a small centered text link — it's a rare,
     destructive utility action, not a primary path, so it shouldn't compete visually with saving/
     applying routines. Keeps the same two-tap confirm color swap (dim → red). */
  .rt-clearlink { display: block; width: 100%; text-align: center; background: none; border: none; padding: 10px 0 2px; font-size: 12px; text-decoration: underline; cursor: pointer; }
  .rt-hr { border: none; border-top: 1px solid var(--border); margin: 18px 0 4px; }
  /* Away sheet — declare a sick/trip/rest range off */
  .sched-ticket-btn.away { background: rgba(var(--accent-rgb), 0.12); border-color: rgba(var(--accent-rgb), 0.5); color: var(--accent); }
  .away-reasons { display: flex; gap: 8px; flex-wrap: wrap; }
  .away-chip { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); font-size: 14px; font-weight: 600; cursor: pointer; }
  .away-chip.on { background: rgba(var(--accent-rgb), 0.16); border-color: var(--accent); color: var(--accent); }
  .away-chip-emo { display: inline-flex; align-items: center; line-height: 1; }
  .sched-away-emo { flex-shrink: 0; display: inline-flex; align-items: center; line-height: 1; }
  .away-range { display: flex; gap: 10px; }
  .away-date { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--text-dim); font-weight: 600; }
  .away-date input { padding: 9px 10px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); font-size: 14px; }
  .wg-allbtn.routines { gap: 5px; }
  .rt-pro { color: var(--accent); }
  .rt-pro-badge { margin-left: 7px; font-size: 9px; font-weight: 800; letter-spacing: .06em; color: var(--accent-text); background: var(--accent); border-radius: 999px; padding: 2px 6px; vertical-align: middle; }
  .rt-warn { color: #fbbf24; } /* honest heads-up that a program's blocks overlap the user's existing schedule — not a hard block, side-by-side is allowed */
  /* Program Library — curated ship-with-the-app whole-week templates (content-as-Pro) */
  .prog-list { display: flex; flex-direction: column; gap: 8px; }
  .prog-card { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2); text-align: left; cursor: pointer; width: 100%; }
  .prog-card:active { background: var(--surface); }
  .prog-card-emoji { flex-shrink: 0; font-size: 22px; line-height: 1; margin-top: 1px; }
  .prog-card-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
  .prog-card-name { font-size: 14px; font-weight: 700; color: var(--text); }
  .prog-card-desc { font-size: 12px; color: var(--text-dim); line-height: 1.35; }
  .prog-card-lock { flex-shrink: 0; font-size: 15px; margin-top: 2px; opacity: .85; }
  .prog-week-list { display: flex; flex-direction: column; gap: 4px; }
  .prog-day-row { display: flex; gap: 10px; padding: 6px 2px; border-bottom: 1px solid var(--border); font-size: 12.5px; }
  .prog-day-row:last-child { border-bottom: none; }
  .prog-day-label { width: 32px; flex-shrink: 0; font-weight: 700; color: var(--text-dim); }
  .prog-day-items { flex: 1; min-width: 0; color: var(--text); }
  /* Soft-away block: the day is "off" but still doable. The away/reason emoji sits in the check
     box (in place of the empty circle) to flag the rest day per-task; the block keeps its normal
     background and stays fully tappable (tap the emoji to mark done). No dimming. */
  /* Weekly Away tally — "🤒 1 · ✈️ 2 off this week" under the day strip */
  .wrec-away { display: flex; align-items: center; gap: 10px; margin-top: 10px; flex-wrap: wrap; font-size: 12px; }
  .wrec-away { gap: 8px; }
  .wrec-away-item { display: inline-flex; align-items: center; gap: 4px; font-weight: 700; color: var(--text); }
  .wrec-away-item + .wrec-away-item::before { content: '·'; margin-right: 8px; color: var(--text-muted); font-weight: 400; }
  .wrec-away-lbl { color: var(--text-muted); margin-left: 2px; }
  /* "See full recap ›" — quiet text-link at the card foot that opens the full recap modal. */
  .wrec-see-more {
    display: block; margin: 12px 0 0 auto; padding: 6px 2px; min-height: 44px;
    background: none; border: none; cursor: pointer;
    font-size: 13px; font-weight: 700; color: var(--accent);
    text-align: right;
  }
  .wrec-see-more:hover { color: var(--accent-hover); }
  /* In-place delete mode: a muted red ✕ (.act-card-del) floats at each task's top-right corner,
     and every task's outline turns red to signal the whole timeline is in delete mode. */
  .tl2.av.delmode { overflow: visible; z-index: 10; border-color: var(--danger,#ef4444) !important; } /* z-10 > sticky caps (z-9) so the ✕ delete buttons on top-row tasks aren't painted behind the header */
  /* The whole timeline is in delete mode, so the "avatar is doing this NOW" glow ring (normally the
     theme accent / teal) must read red too — otherwise a live task keeps its accent halo over the red outline. */
  .tl2.av.delmode.live,
  .tl2.av.delmode.rest-now,
  .tl2.av.delmode.hobby.live { box-shadow: 0 0 0 2px var(--danger,#ef4444) !important; }
  .tl2-del {
    position: absolute; top: -10px; right: -9px; z-index: 14;
    border: none; /* it's a <button>; drop the UA default outset border (the dark ring) */
    touch-action: manipulation;
  }

  /* Day "all tasks" agenda list (opened from the ☰ button) */
  .agenda-row {
    display: flex; align-items: center; gap: 10px; width: 100%;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px;
    padding: 11px 12px; margin-bottom: 8px; color: inherit; font: inherit;
    cursor: pointer; touch-action: manipulation; text-align: left;
  }
  .agenda-row:active { border-color: var(--border-strong); }
  /* Band group header in the agenda (เช้า/เที่ยง/เย็น) — a clean section header: emoji in a
     tinted rounded chip, name in high-contrast text, time as a tabular accent on the right,
     with a band-colored hairline rule underneath. (color is never the only signal: emoji+text.) */
  .agenda-band-head { display: flex; align-items: center; gap: 9px; margin: 18px 2px 9px; padding: 0 2px 7px;
    background: transparent; border: none; border-bottom: 1px solid rgba(var(--band-rgb,148,163,184), 0.30); }
  .agenda-band-head:first-child { margin-top: 4px; }
  .agenda-band-emoji { display: grid; place-items: center; flex-shrink: 0; width: 26px; height: 26px; border-radius: 9px;
    font-size: 14px; line-height: 1; background: rgba(var(--band-rgb,148,163,184), 0.16); box-shadow: inset 0 0 0 1px rgba(var(--band-rgb,148,163,184), 0.30); }
  .agenda-band-name { flex: 1; min-width: 0; font-size: 13.5px; font-weight: 800; letter-spacing: 0.01em; color: var(--text); }
  .agenda-band-time { flex-shrink: 0; font-size: 11px; font-weight: 800; color: var(--band); font-variant-numeric: tabular-nums; letter-spacing: 0.02em; }
  /* Zone header is a button → opens the band editor; ✎ hints it's tappable. */
  button.agenda-band-head { width: 100%; background: transparent; font: inherit; cursor: pointer; text-align: left; -webkit-tap-highlight-color: transparent; }
  button.agenda-band-head:active { opacity: 0.6; }
  .agenda-band-edit { flex-shrink: 0; margin-left: 6px; font-size: 12px; color: var(--text-dim); }
  /* Settings: time-of-day band editor rows — a left color rail identifies the band, comfortable
     touch targets (≥44px), tabular time fields, and a round color swatch. */
  .band-edit-row { position: relative; display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px;
    padding: 10px 10px 10px 18px; border-radius: 14px;
    background: rgba(var(--band-rgb,148,163,184), 0.07); border: 1px solid rgba(var(--band-rgb,148,163,184), 0.22); }
  .band-edit-row::before { content: ''; position: absolute; left: 7px; top: 10px; bottom: 10px; width: 4px;
    border-radius: 3px; background: rgba(var(--band-rgb,148,163,184), 0.9); }
  .band-edit-row.hl { box-shadow: 0 0 0 2px rgba(var(--band-rgb,148,163,184), 0.95); border-color: transparent; }
  .ber-top { display: flex; align-items: center; gap: 8px; }
  .ber-times { display: flex; align-items: center; gap: 8px; }
  .band-edit-row input { background: var(--surface-2); border: 1px solid var(--border); border-radius: 9px; color: var(--text); font: inherit; padding: 8px 8px; min-width: 0; }
  .band-edit-row input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.25); }
  /* Emoji cell shows the ANIMATED Noto webp (overlay) while the real <input> sits underneath with
     transparent text so it stays tappable to type a new emoji; the caret stays visible. */
  /* Tap → opens the same full "Pick an emoji" picker tasks use (EmojiGifPicker). */
  .band-edit-emoji-btn { width: 42px; height: 38px; flex-shrink: 0; display: flex; align-items: center;
    justify-content: center; cursor: pointer; border: 1px solid var(--border); border-radius: 10px;
    background: var(--surface); padding: 0; }
  .band-edit-emoji-btn:active { transform: scale(0.94); }
  .band-edit-name { flex: 1; min-width: 0; font-size: 14px; font-weight: 700; }
  .band-edit-dash { flex-shrink: 0; color: var(--text-dim); font-weight: 700; }
  .band-edit-color { width: 40px; height: 40px; flex-shrink: 0; padding: 0; border: none; border-radius: 50%; overflow: hidden; cursor: pointer; background: none; }
  .band-edit-color::-webkit-color-swatch-wrapper { padding: 0; }
  .band-edit-color::-webkit-color-swatch { border: 2px solid var(--border); border-radius: 50%; }
  .band-edit-del { flex-shrink: 0; width: 44px; height: 44px; border-radius: 50%; border: none; display: flex; align-items: center; justify-content: center;
    font-size: 14px; font-weight: 800; line-height: 1; color: var(--danger,#ef4444); background: rgba(var(--danger-rgb,239,68,68),0.14); cursor: pointer; }
  .band-edit-hide { flex-shrink: 0; width: 44px; height: 44px; border-radius: 50%; border: none; display: flex; align-items: center; justify-content: center;
    color: var(--text-muted); background: var(--surface-2); cursor: pointer; }
  .band-edit-move { flex-shrink: 0; width: 30px; height: 30px; border-radius: 8px; border: none; display: flex; align-items: center; justify-content: center;
    font-size: 11px; color: var(--text-muted); background: var(--surface-2); cursor: pointer; padding: 0; }
  .band-edit-move:disabled { opacity: 0.3; cursor: default; }
  .band-edit-move:active:not(:disabled) { background: var(--surface); color: var(--text); }
  .band-edit-hide.off { color: var(--accent); background: rgba(var(--accent-rgb),0.16); }
  /* A hidden band dims (still editable + un-hideable via the eye). The eye keeps full opacity so the
     way back is always obvious. */
  .band-edit-row.is-hidden { opacity: 0.55; }
  .band-edit-row.is-hidden .band-edit-hide { opacity: 1; }
  .band-edit-actions { display: flex; gap: 8px; margin-top: 6px; }
  .band-edit-actions .btn-ghost { flex: 1; font-size: 13px; min-height: 44px; }
  /* Armed "Reset to default" — tap-again-to-confirm state. */
  .band-edit-actions .btn-ghost.danger { color: var(--danger); border-color: var(--danger);
    background: rgba(248,113,113,0.1); }
  .agenda-dot { flex-shrink: 0; width: 10px; height: 10px; border-radius: 50%; }
  .agenda-emoji { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; }
  .agenda-emoji img, .agenda-emoji .action-emoji { width: 17px; height: 17px; }
  .agenda-time { flex-shrink: 0; width: 96px; font-size: 12px; font-weight: 700; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .agenda-name { flex: 1; min-width: 0; font-weight: 700; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .agenda-who { flex-shrink: 0; font-size: 11px; font-weight: 800; color: var(--text-dim); }
  .agenda-row.jek .agenda-who { color: var(--accent); }
  .agenda-row.me .agenda-who { color: var(--you); }
  .agenda-row.hobby .agenda-who { color: #7dd3fc; }
  .agenda-row.editing { cursor: default; }
  .agenda-del { flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; line-height: 1; color: var(--danger,#ef4444); background: rgba(var(--danger-rgb,239,68,68),0.14); cursor: pointer; }
  .agenda-del:active { transform: scale(0.92); }
  /* Full-screen 24h time grid (Option B): tap a free hour to schedule there. */
  .slotgrid { display: flex; flex-direction: column; gap: 4px; }
  .slot-row {
    display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px;
    padding: 8px 12px; color: inherit; font: inherit; text-align: left;
  }
  .slot-row.free { cursor: pointer; touch-action: manipulation; border-style: dashed; }
  .slot-row.free:active { border-color: var(--accent); background: rgba(var(--accent-rgb),0.08); }
  .slot-row.busy { background: var(--surface); }
  .slot-time { flex-shrink: 0; width: 72px; font-size: 12px; font-weight: 700; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .slot-free { color: var(--text-dim); font-size: 13px; font-weight: 700; }
  .slot-busy { flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
  .slot-chip {
    display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px;
    padding: 4px 10px; font: inherit; font-size: 13px; font-weight: 700; color: var(--text);
    cursor: pointer; touch-action: manipulation; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .slot-chip-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: 50%; }
  .slot-cont { font-size: 11px; font-weight: 700; color: var(--text-dim); }
  .agenda-emoji { display: inline-block; vertical-align: -2px; margin-right: 5px; }

  /* Google-Calendar-style day view */
  .tl-scroll {
    flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;
    border: 1px solid var(--border); border-radius: var(--radius);
    background: var(--surface);
  }
  .tl-canvas { position: relative; width: 100%; }
  /* Time-of-day bands (Day gutter): thin colour RAIL on the left edge + gentle fade to the right —
     mirrors the Week-mode look (.wg-band) the user asked Day to match. Stays in the gutter (x<50)
     so the rail never overlaps a task block. */
  .tl-band { position: absolute; left: 0; width: 50px; right: auto; pointer-events: none; z-index: 0;
    background: linear-gradient(to right, rgba(var(--band-rgb), 0.13), rgba(var(--band-rgb), 0) 70%); }
  .tl-band::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
    border-radius: 0 3px 3px 0; background: rgba(var(--band-rgb), 0.85); }
  /* Chapter divider: a faint full-width hairline across the task lane at each zone's start, so the
     day visibly breaks into chapters as you scroll (pointer-events:none → tap-to-create passes through). */
  .tl-band-rule { position: absolute; left: 50px; right: 0; height: 0; z-index: 1; pointer-events: none;
    border-top: 1px dashed rgba(var(--band-rgb), 0.4); }
  /* Zone label PILL at the band start: emoji + zone name, sitting on the divider line top-left.
     Tappable → opens the band editor. Day shows the name (Week is too tight → emoji-only). The pill
     can spill just past the 50px gutter into the lane at the zone boundary (above any task), as the
     user asked (image ref). */
  /* pill is vertically CENTERED on the band-top dashed line (translateY(-50%)), not hanging below it. */
  .tl-band-gem { position: absolute; left: 3px; transform: translateY(-50%); z-index: 3;
    display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px 2px 6px;
    border: 1px solid rgba(var(--band-rgb), 0.55); border-radius: 999px;
    background: rgba(var(--band-rgb), 0.18); cursor: pointer; line-height: 1; white-space: nowrap;
    filter: drop-shadow(0 1px 2px rgba(0,0,0,0.4)); }
  .tl-band-name { font-size: 11px; font-weight: 600; color: var(--text); letter-spacing: .2px; }
  /* edit-affordance pen at the back of the pill (tap pill → opens band editor); thin ✎ tinted to the
     zone colour, matching the app's standard edit glyph (agenda/dash/settings all use ✎). */
  .tl-band-pen { font-size: 12px; line-height: 1; margin-left: 1px; color: rgba(var(--band-rgb), 0.95); }
  .tl-band-gem:active { transform: translateY(-50%) scale(0.96); }
  /* Empty-day coachmark for the tap/drag-to-create gesture (pointer-events:none → tap passes through). */
  .tl-empty-hint { position: absolute; left: 50%; top: 84px; transform: translateX(-50%); width: 80%; max-width: 280px; text-align: center; color: var(--text-dim); font-size: 13px; line-height: 1.5; pointer-events: none; }
  .tl-hline { position: absolute; left: 50px; right: 0; border-top: 1px solid var(--border); }
  .tl-hline.half { opacity: 0.4; }
  .tl-hlabel {
    position: absolute; left: 0; width: 42px; text-align: right;
    transform: translateY(-50%);
    font-size: 10px; font-weight: 600; color: var(--text-dim);
    font-variant-numeric: tabular-nums; letter-spacing: 0.02em;
  }
  .tlc {
    position: absolute; left: 52px; right: 8px;
    border: 1px solid; border-radius: 12px; overflow: hidden;
    display: flex; z-index: 2;
  }
  .tlc.upcoming { opacity: 0.66; }
  .tlc.missed { opacity: 0.5; }
  .tlc.live { box-shadow: 0 0 0 2px var(--accent); }
  .tlc-main {
    flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
    background: transparent; border: 0; color: var(--text); text-align: left;
    font: inherit; cursor: pointer; padding: 6px 4px 6px 9px; touch-action: manipulation;
  }
  .tlc-main:disabled { cursor: default; }
  .tlc-emoji {
    flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%;
    background: var(--bg); border: 2px solid; display: flex; align-items: center; justify-content: center;
    font-size: 16px; line-height: 1;
  }
  .tlc-info { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
  .tlc-name { font-weight: 700; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tlc.done .tlc-name { text-decoration: line-through; opacity: 0.7; }
  .tlc-meta { display: flex; align-items: center; gap: 7px; }
  .tlc-range { font-size: 11px; color: var(--text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
  .tlc-dur {
    font-size: 10px; font-weight: 700; color: var(--text-dim);
    background: rgba(255,255,255,0.06); border-radius: 6px; padding: 1px 6px; white-space: nowrap;
    font-variant-numeric: tabular-nums;
  }
  .tlc-edit {
    flex-shrink: 0; align-self: flex-start; width: 30px; height: 30px;
    background: transparent; border: 0; color: var(--text-dim);
    font-size: 14px; cursor: pointer; touch-action: manipulation;
  }
  .tlc-edit:active { color: var(--text); }

  .tl-gap {
    position: absolute; left: 50px; right: 0; z-index: 1; pointer-events: none;
    background: repeating-linear-gradient(45deg, rgba(var(--you-rgb),0.13), rgba(var(--you-rgb),0.13) 7px, rgba(var(--you-rgb),0.04) 7px, rgba(var(--you-rgb),0.04) 14px);
    border-top: 1px dashed rgba(var(--you-rgb),0.55); border-bottom: 1px dashed rgba(var(--you-rgb),0.55);
  }
  .tl-mark { position: absolute; left: 0; right: 0; height: 0; pointer-events: none; }
  .tl-mark.you { z-index: 6; }
  .tl-mark.me { z-index: 7; }
  .tl-dot {
    position: absolute; left: 50px; top: 0; width: 11px; height: 11px;
    border-radius: 50%; transform: translate(-50%, -50%);
    box-shadow: 0 0 0 2px var(--surface);
  }
  .tl-dot.me { background: var(--danger); }
  .tl-dot.you { background: var(--you); }
  .tl-mark-line { position: absolute; left: 50px; right: 30px; top: 0; transform: translateY(-50%); height: 2px; }
  .tl-mark.me .tl-mark-line { background: var(--danger); }
  .tl-mark.you .tl-mark-line { background: var(--you); opacity: 0.8; }
  /* Current-time marker = a solid red pill tucked in the left gutter (Google-Calendar
     style), not bare red text — so where the now-line crosses a block the time stays
     legible and reads as its own chip instead of colliding with the block's text. */
  .tl-now-time {
    /* Sits inside the 46px hour gutter; never bleeds onto blocks (right edge < 44px).
       No red glow ring — the halo used to spill past the gutter and clash with a block
       that starts at "now" (looked chaotic). A soft drop shadow keeps it legible instead. */
    position: absolute; left: 2px; max-width: 42px; transform: translateY(-50%);
    padding: 1px 5px; border-radius: 999px; white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; box-sizing: border-box;
    background: var(--danger); color: #fff;
    font-size: 10px; font-weight: 800; line-height: 1.4;
    font-variant-numeric: tabular-nums; z-index: 9; pointer-events: none;
    box-shadow: 0 1px 4px rgba(0,0,0,0.35);
  }
  .tl-mark-emoji {
    position: absolute; right: 4px; top: 0; transform: translateY(-50%);
    font-size: 19px; line-height: 1; filter: drop-shadow(0 1px 3px rgba(0,0,0,0.6));
  }
  .tl-mark-emoji.big { font-size: 24px; animation: avatarRun 0.7s ease-in-out infinite; }
  @media (prefers-reduced-motion: reduce) { .tl-mark-emoji.big { animation: none; } }

  /* --- You vs committed-self race bars --- */
  .self-avatar.tone-behind { border-color: rgba(var(--you-rgb),0.4); background: rgba(var(--you-rgb),0.05); }
  .race-bars {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 14px; padding: 12px 14px;
    display: flex; flex-direction: column; gap: 8px;
  }
  .race-bars.behind { border-color: rgba(var(--you-rgb),0.4); background: rgba(var(--you-rgb),0.05); }
  .race-row { display: flex; align-items: center; gap: 10px; }
  .race-tag { width: 30px; flex-shrink: 0; font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; }
  .race-tag.you { color: var(--text-dim); }
  .race-tag.me { color: var(--accent); }
  .race-track { flex: 1; height: 9px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
  .race-fill { height: 100%; border-radius: 999px; transition: width 0.5s ease; }
  .race-fill.you { background: var(--text-muted); }
  .race-fill.me { background: var(--accent); }
  .race-val { width: 54px; flex-shrink: 0; text-align: right; font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums; }
  .race-status { font-size: 12px; font-weight: 700; text-align: center; margin-top: 2px; }
  .race-bars.behind .race-status { color: var(--you); }
  .race-bars.instep .race-status { color: var(--accent); }

  /* --- Dashboard (Main tab) --- */
  .dash-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
  /* TODAY race mini, relocated into the header (flows here instead of absolute in the hero). */
  /* Avatar pill + streak stat, side by side on one row at the top-right corner (streak pill
     left, JEK pill in the corner). margin-left:auto pushes the group right; the greeting
     holds the far left. */
  .dash-top-r { display: flex; align-items: center; gap: 6px; margin-left: auto; flex-shrink: 0; }
  /* Header version of the streak stat: a tiny pill — milestone emoji + "Streak" + count,
     no next-goal text — with the same amber progress fill behind it. */
  .dash-top-r .dash-badge { width: auto; flex: 0 1 auto; min-width: 0; gap: 6px; padding: 4px 11px 4px 4px; }
  .dash-top-r .dash-badge-face { width: 27px; height: 27px; font-size: 15px; flex: 0 0 auto; }
  .dash-top-r .dash-badge-text { display: none; }
  .dash-top-r .dash-badge-name { position: relative; z-index: 1; font-size: 12px; font-weight: 800; color: var(--text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
  .dash-top-r .dash-badge-count { font-size: 12px; flex: 0 0 auto; }
  /* Left side yields first: the greeting/date ellipsize so the name chip keeps its room
     (a long EN date used to squeeze the chip and clip "JEK" → "J"). */
  .dash-top-l { min-width: 0; }
  .dash-greet { font-size: 19px; font-weight: 800; letter-spacing: -0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dash-date { font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dash-name-chip {
    display: inline-flex; align-items: center; gap: 7px; flex-shrink: 0;
    background: var(--surface); border: 1px solid var(--border); border-radius: 999px;
    padding: 6px 12px 6px 8px; color: var(--text); font: inherit; cursor: pointer; touch-action: manipulation;
  }
  .dash-name-chip:active { background: var(--surface-2); }
  .dash-name-face { display: inline-flex; line-height: 0; }
  /* Cap the NAME (not the whole chip) so short names like "JEK"/"Fan" always show in full
     and only genuinely long names ellipsize. */
  .dash-name-txt { font-size: 13px; font-weight: 800; max-width: 104px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dash-name-edit { font-size: 11px; color: var(--accent); flex-shrink: 0; }

  /* JEK's proactive daily check-in bubble — the avatar greeting you first. */
  .jek-checkin {
    display: flex; align-items: center; gap: 11px; margin-top: 12px;
    background: rgba(var(--accent-rgb),0.07); border: 1px solid rgba(var(--accent-rgb),0.28);
    border-radius: 16px; padding: 11px 12px;
    animation: checkinIn 0.32s cubic-bezier(0.22,1,0.36,1) both;
  }
  @keyframes checkinIn { from { opacity: 0; transform: translateY(-6px) scale(0.985); } to { opacity: 1; transform: none; } }
  .jek-checkin-face { display: inline-flex; line-height: 0; flex-shrink: 0; }
  .jek-checkin-body { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
  .jek-checkin-name { font-size: 11px; font-weight: 800; color: var(--accent); letter-spacing: 0.02em; }
  .jek-checkin-msg { font-size: 13.5px; font-weight: 600; line-height: 1.32; color: var(--text); }
  .jek-checkin-x {
    flex-shrink: 0; align-self: flex-start; width: 32px; height: 32px; border-radius: 999px;
    border: none; background: transparent; color: var(--text-dim); font-size: 13px; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; touch-action: manipulation;
  }
  .jek-checkin-x:active { background: rgba(var(--accent-rgb),0.14); }
  /* Free (locked) taste: a PRO tag on the name + an upgrade CTA under the greeting. */
  .jek-checkin-pro { margin-left: 6px; font-size: 9px; font-weight: 800; color: var(--accent-text); background: var(--accent); border-radius: 999px; padding: 1px 6px; letter-spacing: 0.04em; vertical-align: middle; }
  .jek-checkin-cta { margin-top: 6px; align-self: flex-start; background: none; border: 0; padding: 0; color: var(--accent); font: inherit; font-size: 12px; font-weight: 800; cursor: pointer; touch-action: manipulation; }
  .jek-checkin-cta:active { opacity: 0.7; }

  /* Up next card */
  .dash-next {
    display: flex; align-items: center; gap: 13px; width: 100%; text-align: left;
    background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
    padding: 14px 14px; color: var(--text); font: inherit; cursor: pointer; touch-action: manipulation;
  }
  .dash-next:active { background: var(--surface-2); }
  .dash-next.tone-live { border-color: rgba(var(--accent-rgb),0.45); background: rgba(var(--accent-rgb),0.06); }
  .dash-next.tone-next { border-color: var(--border-strong); }
  .dash-next-glyph {
    flex-shrink: 0; width: 44px; height: 44px; border-radius: 12px; background: var(--surface-2);
    display: flex; align-items: center; justify-content: center; font-size: 24px; line-height: 1;
  }
  .dash-next.tone-live .dash-next-glyph { background: rgba(var(--accent-rgb),0.14); }
  .dash-next-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .dash-next-label { font-size: 14px; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dash-next-time { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .dash-next-arrow { flex-shrink: 0; font-size: 22px; color: var(--text-dim); }

  /* Week card wrapper (reuses History's WeekCard, made tappable) */
  .dash-week-btn {
    display: block; width: 100%; padding: 0; border: none; background: none; color: inherit; font: inherit;
    cursor: pointer; touch-action: manipulation; text-align: left;
  }
  .dash-week-btn .week-card { transition: border-color 0.15s ease; }
  .dash-week-btn:active .week-card { border-color: var(--border-strong); }
  /* Condensed week card for the dashboard — smaller than the full Progress-tab one
     so a slice of the activity list shows below without scrolling. */
  .dash-week-btn .week-card { padding: 12px 13px; gap: 8px; border-radius: 14px; }
  .dash-week-btn .week-headline { font-size: 16px; }
  .dash-week-btn .week-sub { font-size: 11px; margin-top: 2px; }
  .dash-week-btn .week-bar { height: 6px; }
  .dash-week-btn .week-strip { gap: 4px; }
  .dash-week-btn .week-day { padding: 4px 0; gap: 2px; border-radius: 8px; }
  .dash-week-btn .week-day-lbl { font-size: 9px; }
  .dash-week-btn .week-day-glyph { font-size: 12px; }
  .dash-week-btn .week-streak { font-size: 11px; padding: 2px 8px; }
  .dash-week-cta { display: block; text-align: right; font-size: 11px; font-weight: 800; color: var(--accent); margin-top: 6px; }
  /* Friends / Multiplayer quick-access row on the dashboard (mirrors .dash-next chrome). */
  .dash-friends {
    display: flex; align-items: center; gap: 13px; width: 100%; text-align: left; margin-top: 12px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
    padding: 12px 14px; color: var(--text); font: inherit; cursor: pointer; touch-action: manipulation;
  }
  .dash-friends:active { background: var(--surface-2); }
  .dash-friends-ico {
    flex-shrink: 0; width: 40px; height: 40px; border-radius: 12px; font-size: 21px; line-height: 1;
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg, rgba(var(--accent-rgb),0.20), rgba(var(--accent-rgb),0.06));
    border: 1px solid rgba(var(--accent-rgb),0.30);
  }
  /* Animated 3D trophy (Google Noto animated emoji GIF — it loops on its own).
     translateZ(0)+will-change isolates the GIF on its OWN compositing layer so its
     per-frame repaint can't re-rasterize the scroll content → no scroll jitter
     (same fix as the rounded-clip note up top: never let a repaint sit on the scroller). */
  .dash-trophy-anim {
    width: 28px; height: 28px; object-fit: contain; display: block;
    transform: translateZ(0); will-change: transform; contain: paint;
  }
  .dash-friends-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .dash-friends-title { font-size: 14px; font-weight: 800; }
  .dash-friends-sub { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dash-friends-avs { flex-shrink: 0; display: flex; align-items: center; }
  .dash-friends-av {
    width: 30px; height: 30px; border-radius: 50%; overflow: hidden; background: var(--surface-2);
    border: 2px solid var(--surface); margin-left: -9px; display: flex; align-items: center; justify-content: center; font-size: 17px;
  }
  .dash-friends-av:first-child { margin-left: 0; }
  .dash-friends-av.fav { border-color: #fbbf24; } /* starred favorites wear a gold ring */
  .dash-friends-more { font-size: 11px; font-weight: 800; color: var(--text-dim); margin-left: 5px; }
  .dash-friends-arrow { flex-shrink: 0; font-size: 22px; color: var(--text-dim); }
  /* Compact "next badge" stat on the dashboard (taps through to Progress).
     Styled to echo the avatar name-pill: one fully-rounded pill whose background
     quietly fills with your streak progress (amber "you" tint), an emoji face in a
     circle, the goal inline, and the count on the right. */
  .dash-badge { position: relative; overflow: hidden; width: 100%; display: flex; align-items: center; gap: 10px; text-align: left;
    background: var(--surface); border: 1px solid var(--border); border-radius: 999px; padding: 7px 15px 7px 7px; color: var(--text); font: inherit; cursor: pointer; touch-action: manipulation; }
  .dash-badge:active { background: var(--surface-2); }
  /* Progress fill behind the content — left-anchored, width = % to next milestone. */
  .dash-badge-fill { position: absolute; top: 0; bottom: 0; left: 0; z-index: 0; background: rgba(var(--you-rgb),0.16); transition: width 0.5s ease; }
  .dash-badge-face { position: relative; z-index: 1; flex: 0 0 auto; width: 34px; height: 34px; border-radius: 999px; background: var(--surface-2);
    display: inline-flex; align-items: center; justify-content: center; font-size: 19px; line-height: 1; }
  .dash-badge-text { position: relative; z-index: 1; flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 7px; overflow: hidden; }
  .dash-badge-lbl { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); flex: 0 0 auto; }
  .dash-badge-goal { font-size: 13px; font-weight: 800; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .dash-badge-count { position: relative; z-index: 1; flex: 0 0 auto; font-size: 12.5px; font-weight: 800; color: var(--you); font-variant-numeric: tabular-nums; }
  /* The activity list's "ACTIVITIES" label carries a 22px top margin that stacked on
     the main-screen gap → too much air before it on the dashboard. Zero it here. */
  .main-screen .activity-screen > .section-label:first-child { margin-top: 0; }

  /* First-run / rename modal */
  .modal-backdrop {
    position: fixed; inset: 0; z-index: 120; display: flex; align-items: center; justify-content: center;
    padding: 24px; background: rgba(3,6,12,0.74); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
    overflow-y: auto; /* short / landscape phones: let a tall modal scroll instead of clipping its buttons */
  }
  .modal-card {
    width: 100%; max-width: 360px; margin: auto; background: var(--surface); border: 1px solid var(--border-strong);
    border-radius: 22px; padding: 24px 20px 18px; display: flex; flex-direction: column; align-items: center;
    box-shadow: 0 24px 60px rgba(0,0,0,0.55);
  }
  .modal-face { line-height: 0; filter: drop-shadow(0 4px 12px rgba(0,0,0,0.5)); margin-bottom: 12px; }
  .modal-title { font-size: 19px; font-weight: 800; text-align: center; letter-spacing: -0.01em; }
  .modal-intro { font-size: 13px; color: var(--text-muted); text-align: center; margin-top: 8px; line-height: 1.5; }
  .modal-input { width: 100%; margin-top: 18px; text-align: center; font-size: 17px; font-weight: 700; }
  /* Tap-to-enlarge: a small face popover that pops up right over the tapped item — just big
     enough to see clearly, not a full-screen window. Tap anywhere (or scroll) to dismiss. */
  .face-preview-layer { position: fixed; inset: 0; z-index: 200; background: transparent; }
  .face-preview-pop { position: fixed; background: var(--surface); border: 1px solid var(--border-strong); border-radius: 16px; padding: 8px; line-height: 0; box-shadow: 0 14px 34px rgba(0,0,0,0.5); transform-origin: center bottom; animation: facePop 0.13s ease-out; }
  .face-preview-pop img, .face-preview-pop video { border-radius: 11px; object-fit: cover; display: block; }
  @keyframes facePop { from { transform: scale(0.55); opacity: 0; } to { transform: scale(1); opacity: 1; } }
  @media (prefers-reduced-motion: reduce) { .face-preview-pop { animation: none; } }
  .modal-faces { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 16px; }
  .modal-face-opt {
    width: 42px; height: 42px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border);
    display: flex; align-items: center; justify-content: center; font-size: 22px; line-height: 0;
    cursor: pointer; touch-action: manipulation; padding: 0;
  }
  .modal-face-opt.is-sel { border-color: var(--accent); background: rgba(var(--accent-rgb),0.12); box-shadow: 0 0 0 1px var(--accent) inset; }
  .modal-actions { display: flex; gap: 10px; width: 100%; margin-top: 22px; }
  .modal-actions .btn-primary, .modal-actions .btn-ghost { flex: 1; }
  /* PromptPay checkout modal */
  .pp-qr-wrap { width: 232px; height: 232px; margin-top: 16px; border-radius: 16px; background: #fff; display: flex; align-items: center; justify-content: center; padding: 12px; }
  .pp-qr-wrap img { width: 100%; height: 100%; object-fit: contain; }
  .pp-amt { margin-top: 14px; font-size: 22px; font-weight: 900; letter-spacing: -0.01em; }
  .pp-status { margin-top: 10px; font-size: 13px; font-weight: 700; color: var(--text-muted); display: flex; align-items: center; gap: 8px; min-height: 20px; text-align: center; }
  .pp-status.paid { color: var(--accent); }
  .pp-status.err { color: #f87171; }
  .pp-spin { width: 14px; height: 14px; border: 2px solid var(--border-strong); border-top-color: var(--accent); border-radius: 50%; animation: ppspin 0.7s linear infinite; flex: 0 0 auto; }
  @keyframes ppspin { to { transform: rotate(360deg); } }
  .pp-dev { margin-top: 14px; background: none; border: none; color: var(--text-dim); font: inherit; font-size: 11.5px; font-weight: 700; text-decoration: underline; cursor: pointer; }
  .billing-region-msg { margin-top: 14px; font-size: 12.5px; line-height: 1.5; color: var(--text-muted); text-align: center; }

  /* --- Boot / loading splash --- (static #boot-splash in train.html + React <BootSplash/>)
     Animations are transform/opacity only, so they stay smooth (GPU-composited) even while
     Babel is hogging the main thread — a rotating border like .pp-spin visibly stutters there. */
  /* Outer = the dark page behind the phone column (mirrors #root); inner .boot-frame is the
     480px phone shell (rounded + shadowed on desktop, exactly like .app) so the splash sits in
     the same frame as the app instead of stretching edge-to-edge on a wide screen. */
  .boot-splash {
    position: fixed; inset: 0; z-index: 9999;
    display: flex; justify-content: center; background: #05080f;
    transition: opacity 0.45s ease, visibility 0.45s ease;
    /* Own compositor layer so the fade-out is pure GPU opacity and never repaints the Main page
       painting underneath it — that repaint was part of the post-splash jank. */
    will-change: opacity; transform: translateZ(0);
  }
  .boot-splash.is-hidden { opacity: 0; visibility: hidden; pointer-events: none; }
  .boot-frame {
    width: 100%; max-width: var(--app-max); height: 100%;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 13px;
    background: radial-gradient(125% 80% at 50% 36%, #15233c 0%, var(--bg) 58%, #070b14 100%);
  }
  @media (min-width: 520px) {
    .boot-frame {
      box-shadow: 0 30px 80px rgba(0,0,0,0.55), 0 0 0 1px var(--border);
      border-radius: 28px; margin: 24px 0; max-height: calc(100% - 48px);
    }
  }
  /* Logo: gently floats while a lime glow breathes behind it — alive, not the dead-still mark
     it was. The whole point of Ijek is forward motion, so the splash should imply it. */
  .boot-logo { position: relative; width: 96px; height: 96px; display: grid; place-items: center; animation: bootFloat 3.2s ease-in-out infinite; }
  .boot-logo::before { content: ''; position: absolute; inset: -26%; border-radius: 50%; background: radial-gradient(circle, rgba(163,230,53,0.30) 0%, rgba(163,230,53,0) 68%); animation: bootGlow 2.4s ease-in-out infinite; }
  .boot-logo svg { position: relative; width: 100%; height: 100%; display: block; filter: drop-shadow(0 6px 16px rgba(163,230,53,0.25)); }
  .boot-word { margin-top: 4px; font-size: 28px; font-weight: 800; letter-spacing: 0.05em; color: var(--text); }
  .boot-sub { font-size: 12.5px; font-weight: 500; letter-spacing: 0.02em; color: var(--text-dim); }
  /* "Comet" loader: a lime head with a fading trail RACES across the track and loops —
     embodies "race to keep up" instead of a faint static line. */
  .boot-bar { position: relative; margin-top: 16px; width: 152px; height: 3px; border-radius: 99px; background: rgba(255,255,255,0.06); overflow: hidden; }
  .boot-bar span { position: absolute; top: 0; left: 0; height: 100%; width: 46%; border-radius: 99px; background: linear-gradient(90deg, rgba(163,230,53,0) 0%, rgba(163,230,53,0.35) 55%, var(--accent) 100%); box-shadow: 0 0 12px rgba(163,230,53,0.55); animation: bootComet 1.3s cubic-bezier(0.5,0.08,0.3,1) infinite; }
  /* Escape hatch that fades into the splash if boot wedges (see the watchdog in train.html). */
  .boot-retry { margin-top: 22px; padding: 9px 16px; border-radius: 999px; cursor: pointer;
    font-size: 12.5px; font-weight: 700; color: var(--text); background: var(--surface-2);
    border: 1px solid var(--border-strong); opacity: 0; animation: bootRetryIn 0.4s ease forwards; }
  .boot-retry:active { transform: scale(0.96); }
  @keyframes bootRetryIn { to { opacity: 1; } }
  @keyframes bootFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
  @keyframes bootGlow { 0%, 100% { opacity: 0.4; transform: scale(0.9); } 50% { opacity: 0.95; transform: scale(1.1); } }
  @keyframes bootComet { 0% { transform: translateX(-110%); } 100% { transform: translateX(353%); } }
  @media (prefers-reduced-motion: reduce) {
    .boot-logo, .boot-logo::before { animation: none; }
    .boot-bar span { animation: none; width: 100%; background: var(--accent); }
  }

  /* --- Login --- */
  .login {
    position: fixed; inset: 0; z-index: 200; display: flex; justify-content: center; overflow-y: auto;
    background: radial-gradient(120% 80% at 50% -10%, #16223c 0%, var(--bg) 55%, #05080f 100%);
  }
  .login-inner {
    width: 100%; max-width: var(--app-max); min-height: 100%; display: flex; flex-direction: column;
    padding: calc(28px + var(--safe-top)) 26px calc(26px + var(--safe-bottom));
  }
  /* Frameless (original style): form sits directly on the login gradient — NO card box.
     Keep margin:auto + max-width so it stays vertically centred and doesn't stretch on wide screens. */
  .login-card {
    margin: auto; width: 100%; max-width: 380px;
  }
  .login-brand { display: flex; align-items: center; gap: 8px; font-weight: 800; letter-spacing: -0.01em; }
  .login-mark { height: 26px; width: auto; display: block; }
  .login-word { font-size: 15px; }
  .login-hero { margin: 0; text-align: center; padding: 4px 0; }
  .login-hero-face {
    font-size: 96px; line-height: 1; display: inline-block;
    filter: drop-shadow(0 8px 22px rgba(0,0,0,0.55));
    transform-origin: 50% 90%;
    animation: loginFloat 3.4s ease-in-out infinite;
  }
  @keyframes loginFloat {
    0%   { transform: translateY(0)     rotate(0deg)  scale(1); }
    25%  { transform: translateY(-9px)  rotate(-4deg) scale(1.03); }
    50%  { transform: translateY(0)     rotate(0deg)  scale(1); }
    75%  { transform: translateY(-5px)  rotate(4deg)  scale(1.02); }
    100% { transform: translateY(0)     rotate(0deg)  scale(1); }
  }
  @media (prefers-reduced-motion: reduce) { .login-hero-face { animation: none; } }
  .login-title { font-size: 27px; line-height: 1.18; font-weight: 800; letter-spacing: -0.02em; margin: 16px 0 0; }
  .login-tag { color: var(--text-muted); font-size: 14px; line-height: 1.5; margin: 10px 6px 0; }
  /* Feature highlights on the (Google-only) login — fill the space so it reads intentional, not empty. */
  .login-feats { display: flex; flex-direction: column; gap: 12px; margin: 26px 4px 2px; }
  .login-feat { display: flex; align-items: center; gap: 12px; text-align: left; color: var(--text); font-size: 14.5px; line-height: 1.35; }
  .login-feat-ic { flex: 0 0 auto; width: 34px; height: 34px; display: flex; align-items: center; justify-content: center;
    font-size: 18px; background: var(--surface); border: 1px solid var(--border); border-radius: 11px; }
  .login-form { display: flex; flex-direction: column; gap: 10px; margin-top: 22px; }
  .login-social {
    display: flex; align-items: center; justify-content: center; gap: 10px; min-height: 54px;
    border-radius: 14px; font: inherit; font-weight: 700; font-size: 16px; cursor: pointer; touch-action: manipulation;
    border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
    transition: transform 0.12s ease, box-shadow 0.2s ease;
  }
  .login-social svg { display: block; flex: 0 0 auto; }
  .login-social.google { background: #fff; color: #1f1f1f; border-color: transparent; box-shadow: 0 10px 28px rgba(0,0,0,0.32); }
  .login-social.google:hover { transform: translateY(-1px); box-shadow: 0 14px 34px rgba(0,0,0,0.4); }
  .login-social.apple { background: #000; color: #fff; border-color: #000; }
  .login-social:active { opacity: 0.82; }
  /* "soon" pill on the social buttons — flags that OAuth isn't wired yet (no fake login). */
  .login-social-soon { font-size: 10px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase;
    padding: 2px 7px; border-radius: 999px; background: rgba(120,130,150,0.22); color: inherit; opacity: 0.7; }
  .login-note { color: var(--text-muted); font-size: 13px; line-height: 1.45; background: var(--surface);
    border: 1px solid var(--border); border-radius: 10px; padding: 9px 11px; }
  .login-or { display: flex; align-items: center; gap: 12px; color: var(--text-dim); font-size: 12px; margin: 4px 0; }
  .login-or::before, .login-or::after { content: ''; height: 1px; flex: 1; background: var(--border); }
  .login-input {
    width: 100%; background: var(--surface); border: 1px solid var(--border-strong); border-radius: 12px;
    padding: 13px 14px; color: var(--text); font: inherit; font-size: 16px; min-height: 48px;
  }
  .login-input:focus { outline: none; border-color: var(--accent); }
  .login-input::placeholder { color: var(--text-dim); }
  /* Chrome paints autofilled/recognized fields with a pale background + black text
     that `background` can't override — repaint the surface via an inset box-shadow
     and force the text color so a filled email stays dark like the rest of the form. */
  .login-input:-webkit-autofill,
  .login-input:-webkit-autofill:hover,
  .login-input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--text);
    -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
    box-shadow: 0 0 0 1000px var(--surface) inset;
    caret-color: var(--text);
    transition: background-color 9999s ease-out 0s; /* defer Chrome's yellow flash */
  }
  .login-pass { position: relative; }
  .login-pass .login-input { padding-right: 64px; }
  .login-pass-toggle {
    position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
    background: none; border: 0; color: var(--text-muted); font: inherit; font-size: 13px;
    font-weight: 700; cursor: pointer; padding: 8px; touch-action: manipulation;
  }
  .login-err { color: var(--danger); font-size: 13px; }
  .login-go { min-height: 50px; border-radius: 12px; font-size: 16px; margin-top: 2px; }
  .login-switch { text-align: center; color: var(--text-muted); font-size: 13px; margin-top: 18px; }
  .login-link { background: none; border: 0; color: var(--accent); font: inherit; font-weight: 700; cursor: pointer; padding: 0; }
  .login-fine { text-align: center; color: var(--text-dim); font-size: 12px; line-height: 1.5; margin: 20px auto 0; max-width: 320px; }
  .login-consent { text-align: center; color: var(--text-dim); font-size: 11.5px; line-height: 1.5; margin: 8px auto 0; max-width: 320px; }
  .login-consent a { color: var(--text-muted); text-decoration: underline; }
  /* Duolingo-style login: mascot+name+tagline centred (stage grows to fill), CTA pinned low. */
  .login-stage { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 2px; padding: 20px 0; }
  .login-brand-word { font-size: 38px; font-weight: 900; letter-spacing: -0.02em; color: var(--accent); margin-top: 20px; line-height: 1; }
  .login-brand-sub { font-size: 16px; font-weight: 800; color: var(--text); letter-spacing: 0.01em; margin-top: 6px; }
  .login-stage .login-tag { max-width: 290px; margin: 8px auto 0; }
  .login-cta { display: flex; flex-direction: column; gap: 11px; width: 100%; max-width: 380px; margin: 0 auto; }
  /* Chunky "press" button (Duolingo feel) via a solid offset shadow — theme-safe dark lip. */
  .login-start { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 54px; border-radius: 16px; font-size: 15.5px; font-weight: 900; letter-spacing: 0.02em; box-shadow: 0 4px 0 rgba(0,0,0,0.30); }
  .login-start svg { flex: 0 0 auto; background: #fff; border-radius: 50%; padding: 2px; box-sizing: content-box; }
  .login-start:active { transform: translateY(2px); box-shadow: 0 2px 0 rgba(0,0,0,0.30); }
  .login-have { background: none; border: 0; color: var(--accent); font-size: 13.5px; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; padding: 13px; cursor: pointer; touch-action: manipulation; }
  .login-have:active { opacity: 0.6; }

  /* --- Onboarding wizard (full-screen Q&A, shown after sign-up before the tour) --- */
  .ob {
    position: fixed; inset: 0; z-index: 215; display: flex; justify-content: center; overflow-y: auto;
    background: radial-gradient(120% 80% at 50% -10%, #16223c 0%, var(--bg) 55%, #05080f 100%);
  }
  .ob-inner {
    width: 100%; max-width: var(--app-max); min-height: 100%; display: flex; flex-direction: column;
    padding: calc(14px + var(--safe-top)) 22px calc(18px + var(--safe-bottom));
  }
  .ob-top { display: flex; align-items: center; gap: 12px; padding: 6px 0 18px; }
  .ob-back {
    width: 40px; height: 40px; flex: 0 0 auto; background: none; border: 0; color: var(--text-muted);
    font-size: 26px; line-height: 1; cursor: pointer; padding: 0; touch-action: manipulation;
  }
  .ob-back.hidden { visibility: hidden; }
  .ob-progress { flex: 1; height: 8px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
  .ob-progress-fill { height: 100%; background: var(--accent); border-radius: 999px; transition: width .35s cubic-bezier(.4,0,.2,1); }
  .ob-body { flex: 1; display: flex; flex-direction: column; }
  .ob-content { flex: 1; display: flex; flex-direction: column; animation: obFade .3s ease both; }
  @keyframes obFade { from { opacity: 0; } to { opacity: 1; } }
  /* Staggered entrance for the whole board: the glyph pops, then title / sub / each option
     rise in turn so the page reads as it assembles. Replays on every step because
     .ob-content is keyed by `page` (remount → animations restart). */
  @keyframes obPop { 0% { opacity: 0; transform: scale(.45) translateY(8px); } 60% { transform: scale(1.14); } 100% { opacity: 1; transform: scale(1); } }
  @keyframes obRise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
  @keyframes obHalo { 0%,100% { opacity: .45; transform: translate(-50%,-50%) scale(1); } 50% { opacity: .8; transform: translate(-50%,-50%) scale(1.14); } }
  .ob-head { text-align: center; padding: 16px 0 2px; }
  .ob-glyph {
    position: relative; font-size: 66px; line-height: 1; display: inline-block;
    filter: drop-shadow(0 10px 24px rgba(0,0,0,0.55));
    animation: obPop .6s cubic-bezier(.2,.9,.3,1.35) both;
  }
  /* Soft glowing stage behind the glyph — makes the globe (and every step's icon) the hero. */
  .ob-glyph::after {
    content: ''; position: absolute; left: 50%; top: 50%; z-index: -1;
    width: 132%; height: 132%; border-radius: 50%;
    background: radial-gradient(circle, rgba(var(--accent-rgb),0.30) 0%, rgba(var(--accent-rgb),0) 70%);
    transform: translate(-50%,-50%); animation: obHalo 3.4s ease-in-out infinite;
  }
  .ob-title { font-size: 23px; font-weight: 800; letter-spacing: -0.02em; margin: 16px 0 0; animation: obRise .42s ease both .12s; }
  .ob-sub { color: var(--text-muted); font-size: 14px; line-height: 1.5; margin: 9px 6px 0; animation: obRise .42s ease both .2s; }
  .ob-options { display: flex; flex-direction: column; gap: 10px; margin-top: 24px; }
  /* Cascade the option rows in just after the head settles. */
  .ob-options .ob-opt { animation: obRise .42s ease both; }
  .ob-options .ob-opt:nth-child(1) { animation-delay: .28s; }
  .ob-options .ob-opt:nth-child(2) { animation-delay: .36s; }
  .ob-options .ob-opt:nth-child(3) { animation-delay: .44s; }
  .ob-options .ob-opt:nth-child(4) { animation-delay: .52s; }
  .ob-options .ob-opt:nth-child(5) { animation-delay: .60s; }
  .ob-options .ob-opt:nth-child(6) { animation-delay: .68s; }
  .ob-options .ob-opt:nth-child(7) { animation-delay: .76s; }
  .ob-opt {
    display: flex; align-items: center; gap: 13px; width: 100%; text-align: left; min-height: 56px;
    padding: 12px 15px; border-radius: 14px; border: 1.5px solid var(--border-strong);
    background: var(--surface); color: var(--text); font: inherit; font-weight: 700; font-size: 15px;
    cursor: pointer; touch-action: manipulation; transition: border-color .15s, background .15s, transform .06s;
  }
  .ob-opt:active { transform: scale(0.985); }
  .ob-opt.on { border-color: var(--accent); background: rgba(var(--accent-rgb),0.12); }
  .ob-opt-emoji { font-size: 23px; line-height: 1; flex: 0 0 auto; }
  .ob-opt-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .ob-opt-desc { color: var(--text-muted); font-weight: 600; font-size: 12.5px; line-height: 1.3; }
  .ob-opt-hint { color: var(--text-muted); font-weight: 700; font-size: 13px; flex: 0 0 auto; }
  .ob-opt-check { color: var(--accent); font-weight: 800; flex: 0 0 auto; opacity: 0; transform: scale(.4); transition: opacity .18s ease, transform .18s cubic-bezier(.2,1.4,.4,1); }
  .ob-opt.on .ob-opt-check { opacity: 1; transform: scale(1); }
  /* Language flags render as plain "GB"/"TH" letters on Windows (no regional-flag glyphs),
     so frame them as a deliberate country-code chip — looks designed on every platform. */
  .ob-opt-emoji.ob-flag {
    min-width: 36px; height: 28px; padding: 0 8px; border-radius: 8px;
    background: var(--surface-2); border: 1px solid var(--border-strong);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 14px; font-weight: 800; letter-spacing: 0.06em; color: var(--text);
  }
  .ob-opt.on .ob-opt-emoji.ob-flag { border-color: var(--accent); color: var(--accent); }
  /* Hype / streak page */
  .ob-streak { display: flex; flex-direction: column; align-items: center; gap: 18px; margin-top: 14px; }
  .ob-flame { font-size: 92px; line-height: 1; filter: drop-shadow(0 12px 32px rgba(251,146,60,0.5)); animation: obFlame 2.6s ease-in-out infinite; }
  @keyframes obFlame { 0%,100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-6px) scale(1.05); } }
  .ob-days { display: flex; gap: 9px; }
  .ob-day {
    width: 30px; height: 30px; border-radius: 50%; background: var(--surface-2); border: 2px solid var(--border-strong);
    display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 800; color: var(--text-muted);
  }
  .ob-day.on { background: var(--accent); border-color: var(--accent); color: #0b1220; }
  /* Avatar page */
  .ob-name { width: 100%; margin-top: 18px; text-align: center; font-size: 17px; }
  .ob-faces { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 16px; }
  .ob-face-opt {
    width: 46px; height: 46px; border-radius: 12px; border: 1.5px solid var(--border-strong); background: var(--surface);
    display: flex; align-items: center; justify-content: center; cursor: pointer; touch-action: manipulation;
  }
  .ob-face-opt.on { border-color: var(--accent); background: rgba(var(--accent-rgb),0.14); }
  .ob-foot { padding-top: 16px; }
  .ob-next { width: 100%; min-height: 52px; border-radius: 13px; font-size: 16px; }
  .ob-next:disabled { opacity: 0.4; cursor: default; }
  .ob-skip { display: block; width: 100%; margin-bottom: 8px; background: none; border: 0; color: var(--text-muted); font: inherit; font-weight: 600; font-size: 14px; padding: 8px; cursor: pointer; }
  .ob-skip:hover { color: var(--text); }
  @media (prefers-reduced-motion: reduce) {
    .ob-content, .ob-flame, .ob-glyph, .ob-glyph::after, .ob-title, .ob-sub, .ob-options .ob-opt { animation: none; }
    .ob-progress-fill { transition: none; }
  }

  /* --- Intro tutorial carousel --- */
  .tut {
    position: fixed; inset: 0; z-index: 210; display: flex; flex-direction: column;
    padding: calc(14px + var(--safe-top)) 0 calc(22px + var(--safe-bottom));
    background: radial-gradient(120% 80% at 50% 0%, #16223c 0%, var(--bg) 60%, #05080f 100%);
  }
  .tut-skip { align-self: flex-end; margin-right: 18px; background: none; border: 0; color: var(--text-muted); font: inherit; font-weight: 600; cursor: pointer; padding: 8px; }
  .tut-stage { flex: 1; overflow: hidden; display: flex; touch-action: pan-y; }
  .tut-track { display: flex; width: 100%; transition: transform .32s cubic-bezier(.4, 0, .2, 1); }
  .tut-slide { flex: 0 0 100%; width: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 0 38px; }
  .tut-glyph { font-size: 88px; line-height: 1; filter: drop-shadow(0 10px 28px rgba(0,0,0,0.55)); }
  .tut-title { font-size: 25px; font-weight: 800; letter-spacing: -0.02em; margin: 26px 0 0; }
  .tut-body { color: var(--text-muted); font-size: 15px; line-height: 1.6; margin: 12px 6px 0; max-width: 340px; }
  .tut-foot { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 8px 26px 0; }
  .tut-dots { display: flex; gap: 8px; }
  .tut-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--border-strong); border: 0; padding: 0; cursor: pointer; transition: background .2s, width .2s; }
  .tut-dot.on { background: var(--accent); width: 22px; border-radius: 4px; }
  .tut-next { width: 100%; max-width: 340px; min-height: 50px; border-radius: 12px; font-size: 16px; }
  .tut-back { background: none; border: 0; color: var(--text-muted); font: inherit; cursor: pointer; padding: 4px; }

  /* --- Guided spotlight tour (walks the real tabs + highlights live UI) --- */
  .tour { position: fixed; inset: 0; z-index: 210; }
  /* Spotlight steps: a transparent catcher absorbs taps so the app behind stays
     read-only; the dimming itself comes from the hole's huge box-shadow. */
  .tour-catch { position: fixed; inset: 0; background: transparent; }
  /* Centered steps (welcome / finish): a full dim scrim instead of a hole. */
  .tour-scrim { position: fixed; inset: 0; background: radial-gradient(120% 80% at 50% 0%, rgba(22,34,60,0.93) 0%, rgba(5,8,15,0.93) 70%); }
  .tour-hole {
    position: fixed; border: 2px solid var(--accent); border-radius: 14px; pointer-events: none;
    box-shadow: 0 0 0 9999px rgba(4,7,14,0.80), 0 0 0 4px rgba(var(--accent-rgb),0.25);
    transition: top .28s cubic-bezier(.4,0,.2,1), left .28s cubic-bezier(.4,0,.2,1), width .28s cubic-bezier(.4,0,.2,1), height .28s cubic-bezier(.4,0,.2,1);
  }
  /* Centered steps (welcome/finish): a 0×0 hole = plain full dim, no green ring/dot. The
     geometry still transitions, so the spotlight grows out of / shrinks into screen centre. */
  .tour-hole.full { border-color: transparent; box-shadow: 0 0 0 9999px rgba(4,7,14,0.86); }
  .tour-skip {
    /* Pin to the RIGHT EDGE OF THE APP COLUMN (max 480px, centered) — not the viewport —
       so on a wide screen it doesn't float off in the dark margin beside the app card.
       On mobile (viewport ≤ app width) the max() collapses to 16px from the screen edge. */
    position: fixed; top: calc(10px + var(--safe-top)); right: max(16px, calc(50vw - var(--app-max) / 2 + 16px)); z-index: 4;
    display: inline-flex; align-items: center; gap: 6px;
    background: rgba(17,21,28,0.66); border: 1px solid rgba(255,255,255,0.16); color: rgba(255,255,255,0.78);
    font: inherit; font-weight: 600; font-size: 13px; letter-spacing: .02em;
    cursor: pointer; padding: 8px 9px 8px 15px; border-radius: 999px;
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); box-shadow: 0 2px 12px rgba(0,0,0,0.35);
    transition: color .16s, border-color .16s, background .16s, transform .12s;
  }
  .tour-skip:hover { color: #fff; border-color: rgba(255,255,255,0.3); background: rgba(26,31,40,0.8); }
  .tour-skip:active { transform: scale(.96); }
  /* The chevron lives in its own circular chip so the button reads as a clear forward action. */
  .tour-skip-chev {
    display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px;
    border-radius: 999px; background: rgba(255,255,255,0.12); color: #fff; font-size: 12px; line-height: 1;
    transition: transform .16s, background .16s;
  }
  .tour-skip:hover .tour-skip-chev { background: var(--accent); color: #0f1115; transform: translateX(2px); }
  .tour-card {
    position: fixed; left: 14px; right: 14px; margin: 0 auto; max-width: 360px; z-index: 2;
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: 18px;
    padding: 18px 18px 16px; box-shadow: 0 18px 50px rgba(0,0,0,0.55);
    /* The card persists across steps (only its content remounts), so animating top/transform/
       padding makes it GLIDE + resize from one step to the next — welcome → spotlight included. */
    transition: top .34s cubic-bezier(.4,0,.2,1), transform .34s cubic-bezier(.4,0,.2,1), padding .34s ease, opacity .2s ease;
    will-change: top, transform;
  }
  /* Position is set inline (top% + translate); .centered only sets the bigger welcome/finish size. */
  .tour-card.centered { text-align: center; padding: 32px 24px 22px; }
  @media (prefers-reduced-motion: reduce) { .tour-card { transition: opacity .2s ease; } }
  /* Each step's glyph/title/body is remounted (key={i}) so this fade replays — the text
     no longer hard-cuts as you page through the tour. The foot (dots/buttons) stays put. */
  .tour-content { animation: tourFade .3s ease both; }
  @keyframes tourFade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
  @media (prefers-reduced-motion: reduce) { .tour-content { animation: none; } .tour-card:not(.centered) { transition: none; } }
  .tour-glyph { font-size: 40px; line-height: 1; display: flex; }
  .tour-card.centered .tour-glyph { font-size: 78px; justify-content: center; filter: drop-shadow(0 10px 28px rgba(0,0,0,0.55)); }
  .tour-title { font-size: 19px; font-weight: 800; letter-spacing: -0.02em; margin: 10px 0 0; }
  .tour-card.centered .tour-title { font-size: 24px; margin-top: 22px; }
  .tour-body { color: var(--text-muted); font-size: 14px; line-height: 1.55; margin: 7px 0 0; }
  .tour-card.centered .tour-body { font-size: 15px; margin-top: 12px; max-width: 320px; margin-left: auto; margin-right: auto; }
  /* Footer stacks: dots on their own row (they wrap — the tour has many steps), action
     buttons on the row below so Back/Next stay roomy and their labels never wrap. */
  .tour-foot { display: flex; flex-direction: column; gap: 12px; margin-top: 16px; }
  .tour-dots { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; }
  .tour-foot-btns { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
  .tour-back { background: none; border: 0; color: var(--text-muted); font: inherit; cursor: pointer; padding: 8px 10px; white-space: nowrap; }
  .tour-next { min-height: 44px; padding: 0 22px; border-radius: 11px; font-size: 15px; white-space: nowrap; }
  .tour-card.centered .tour-foot-btns { flex-direction: column-reverse; gap: 10px; }
  .tour-card.centered .tour-next { width: 100%; max-width: 320px; min-height: 50px; }
  .tour-card.centered .tour-back { width: 100%; text-align: center; }

  /* --- Plan & billing --- */
  .set-plan-row {
    display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%;
    background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
    padding: 13px 15px; color: var(--text); font: inherit; cursor: pointer; touch-action: manipulation; text-align: left;
  }
  .set-plan-row:active { background: var(--surface-2); }
  .set-plan-row.rank-pro, .set-plan-row.rank-proplus { border-color: rgba(var(--accent-rgb),0.4); background: rgba(var(--accent-rgb),0.05); }
  .set-plan-l { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .set-plan-name { font-size: 15px; font-weight: 800; }
  .set-plan-sub { font-size: 12px; color: var(--text-muted); }
  .set-plan-cta { flex-shrink: 0; font-size: 13px; font-weight: 800; color: var(--accent); }

  /* Pro-lock teaser */
  .pro-lock {
    display: flex; flex-direction: column; gap: 5px; width: 100%; text-align: left;
    background: var(--surface); border: 1px dashed var(--border-strong); border-radius: 14px;
    padding: 14px 15px; color: var(--text); font: inherit; cursor: pointer; touch-action: manipulation;
  }
  .pro-lock:active { background: var(--surface-2); }
  .pro-lock-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
  .pro-lock-title { font-size: 14px; font-weight: 800; }
  .pro-lock-badge { flex-shrink: 0; font-size: 11px; font-weight: 800; color: var(--accent-text); background: var(--accent); border-radius: 999px; padding: 3px 9px; }
  .pro-lock-desc { font-size: 12px; color: var(--text-muted); }
  .pro-lock-cta { font-size: 12px; font-weight: 800; color: var(--accent); margin-top: 2px; }
  /* Consolidated "everything Pro adds" pitch (Free only, top of Settings) — the positive,
     one-place sell so value doesn't rely only on scattered locks. */
  .set-pro-pitch { display: flex; flex-direction: column; gap: 6px; width: 100%; text-align: left; margin-top: 8px; padding: 14px 15px; border-radius: 14px; background: rgba(var(--accent-rgb),0.08); border: 1px solid rgba(var(--accent-rgb),0.4); color: var(--text); font: inherit; cursor: pointer; touch-action: manipulation; }
  .set-pro-pitch:active { background: rgba(var(--accent-rgb),0.14); }
  .set-pro-pitch-head { font-size: 14px; font-weight: 800; }
  .set-pro-pitch-body { font-size: 12.5px; color: var(--text-muted); line-height: 1.55; }
  .set-pro-pitch-cta { font-size: 13px; font-weight: 800; color: var(--accent); margin-top: 2px; }

  /* Billing overlay */
  .billing {
    position: fixed; inset: 0; z-index: 130; display: flex; flex-direction: column;
    width: 100%; max-width: var(--app-max); margin: 0 auto; background: var(--bg);
  }
  .billing-head {
    flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 8px;
    padding: calc(var(--safe-top) + 12px) 12px 12px; border-bottom: 1px solid var(--border);
  }
  .billing-head .btn-ghost { width: 72px; text-align: left; }
  .billing-head-sp { width: 72px; flex-shrink: 0; }
  .billing-title { font-size: 16px; font-weight: 800; }
  .billing-body { flex: 1; min-height: 0; overflow-y: auto; scrollbar-gutter: stable both-edges; padding: 16px 16px calc(var(--safe-bottom) + 28px); display: flex; flex-direction: column; gap: 14px; }
  .billing-current {
    display: flex; flex-direction: column; gap: 3px; background: var(--surface);
    border: 1px solid var(--border); border-radius: 16px; padding: 16px 16px;
  }
  .billing-current.rank-pro, .billing-current.rank-proplus { border-color: rgba(var(--accent-rgb),0.45); background: rgba(var(--accent-rgb),0.06); }
  .billing-current-lbl { font-size: 11px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-dim); }
  .billing-current-name { font-size: 24px; font-weight: 800; letter-spacing: -0.01em; }
  .billing-current-sub { font-size: 12px; color: var(--text-muted); }
  .billing-toggle { display: flex; gap: 4px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 4px; }
  .billing-toggle button {
    flex: 1; min-width: 0; border: none; background: none; color: var(--text-muted); font: inherit; font-weight: 800; font-size: 12px;
    padding: 8px 4px; border-radius: 999px; cursor: pointer; touch-action: manipulation; white-space: nowrap;
    display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  }
  .billing-toggle button.on { background: var(--accent); color: var(--accent-text); }
  .billing-save { font-size: 11px; font-weight: 800; background: rgba(0,0,0,0.16); border-radius: 999px; padding: 2px 7px; flex-shrink: 0; }
  .billing-toggle button:not(.on) .billing-save { background: var(--surface); color: var(--accent); }
  /* Launch "founders' price · first 100" hook (shown only while on Free). */
  .founders-banner { border: 1px solid var(--accent); background: rgba(var(--accent-rgb),0.08); border-radius: 16px; padding: 12px 14px; display: flex; flex-direction: column; gap: 3px; }
  .founders-title { font-size: 14px; font-weight: 800; letter-spacing: -0.01em; }
  .founders-sub { font-size: 12px; color: var(--text-muted); line-height: 1.45; }
  .plan-locked { font-size: 11px; font-weight: 700; color: var(--accent); line-height: 1.4; margin-top: 6px; }
  .plan-cards { display: flex; flex-direction: column; gap: 12px; }
  .plan-card { position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: 18px; padding: 16px; }
  .plan-card.popular { border-color: var(--accent); }
  .plan-card.current { box-shadow: 0 0 0 1px var(--accent) inset; }
  .plan-tag { position: absolute; top: -9px; left: 16px; font-size: 10px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: var(--accent-text); background: var(--accent); border-radius: 999px; padding: 3px 9px; }
  .plan-name { font-size: 17px; font-weight: 800; }
  .plan-price { display: flex; align-items: baseline; gap: 3px; margin-top: 6px; }
  .plan-was { font-size: 15px; font-weight: 700; color: var(--text-dim); text-decoration: line-through; margin-right: 6px; opacity: 0.75; }
  .plan-amt { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; }
  .plan-per { font-size: 13px; font-weight: 700; color: var(--text-muted); }
  .plan-permo { font-size: 11px; color: var(--text-dim); margin-top: 2px; }
  .plan-tagline { font-size: 12px; color: var(--text-muted); margin-top: 6px; }
  .plan-feats { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
  .plan-feats li { display: flex; gap: 8px; font-size: 13px; line-height: 1.35; }
  .plan-check { flex-shrink: 0; color: var(--accent); font-weight: 800; }
  /* "Not in Free" rows: dim the line and mark it with a muted ✗ so the gap to Pro is obvious. */
  .plan-feats li.feat-off { color: var(--text-dim); }
  .plan-feats li.feat-off .plan-check { color: var(--text-dim); }
  .plan-cta { width: 100%; margin-top: 14px; border: none; border-radius: 999px; padding: 11px; font: inherit; font-weight: 800; font-size: 14px; cursor: pointer; touch-action: manipulation; }
  .plan-cta.up { background: var(--accent); color: var(--accent-text); }
  .plan-cta.down { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); }
  .plan-cta.is-cur { background: transparent; color: var(--text-dim); border: 1px solid var(--border); cursor: default; }
  /* Free-trial offer on paid cards (shown only while the user is on Free). */
  /* Opaque fill (not translucent): the badge straddles the card's top edge, so a
     see-through bg let the card's green border line show straight through the pill.
     The inset shadow keeps the soft green tint over the solid surface base. */
  .plan-trial-badge { position: absolute; top: -9px; right: 16px; z-index: 1; font-size: 10px; font-weight: 800; letter-spacing: 0.03em; color: var(--accent); background: var(--surface); box-shadow: inset 0 0 0 99px rgba(var(--accent-rgb),0.16); border: 1px solid var(--accent); border-radius: 999px; padding: 3px 9px; }
  .plan-cta.trial { background: var(--accent); color: var(--accent-text); }
  .plan-trial-note { margin-top: 7px; text-align: center; font-size: 11px; color: var(--text-dim); line-height: 1.4; }
  .billing-note { font-size: 11px; color: var(--text-dim); text-align: center; line-height: 1.5; margin: 2px 4px; }

  .redeem-box { margin-top: 10px; border: 1px solid var(--border); border-radius: 14px; padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; }
  .redeem-title { font-size: 13px; font-weight: 600; color: var(--text); }
  .redeem-row { display: flex; gap: 8px; }
  .redeem-input { flex: 1; min-width: 0; background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 9px 11px; font-size: 14px; color: var(--text); letter-spacing: 0.06em; text-transform: uppercase; }
  .redeem-input:focus { outline: none; border-color: var(--accent); }
  .redeem-btn { flex: 0 0 auto; padding: 9px 16px; }
  .redeem-msg { font-size: 12px; line-height: 1.4; }
  .redeem-msg.ok { color: var(--accent); font-weight: 600; }
  .redeem-msg.err { color: #ef4444; }

  /* --- Main page: avatar hero --- */
  /* No position:relative here — it would become the containing block for the
     activity .sheet (position:absolute; bottom:0), pinning the sheet to the bottom
     of the tall scrollable dashboard instead of the phone frame (.app). */
  .main-screen { display: flex; flex-direction: column; gap: 16px; }
  .hero {
    width: 100%; display: flex; flex-direction: column; align-items: center;
    background: var(--surface); border: 1px solid var(--border); border-radius: 20px;
    padding: 22px 18px 16px; cursor: pointer; touch-action: manipulation; color: var(--text);
    font: inherit;
  }
  .hero.tone-go { border-color: rgba(var(--accent-rgb),0.4); background: rgba(var(--accent-rgb),0.05); }
  .hero.tone-behind { border-color: rgba(var(--you-rgb),0.4); background: rgba(var(--you-rgb),0.05); }

  /* Unified hero card: avatar zone + race + up-next + week, divided by hairlines. */
  .hero-card {
    /* `clip` + clip-margin keeps the rounded-corner clip (so child sections don't square the
       corners) but lets the avatar's aura glow bleed ~22px past the edge before it's cut. */
    width: 100%; display: flex; flex-direction: column; overflow: clip; overflow-clip-margin: 22px; position: relative;
    background: var(--surface); border: 1px solid var(--border); border-radius: 20px;
  }
  /* Tone tint lives on the WHOLE card (layered over --surface) so the avatar area and
     the coach-action area below share one background — no two-tone band between them. */
  .hero-card.tone-go { border-color: rgba(var(--accent-rgb),0.4); background: linear-gradient(rgba(var(--accent-rgb),0.05), rgba(var(--accent-rgb),0.05)), var(--surface); }
  .hero-card.tone-behind { border-color: rgba(var(--you-rgb),0.4); background: linear-gradient(rgba(var(--you-rgb),0.05), rgba(var(--you-rgb),0.05)), var(--surface); }
  .hero-tap {
    width: 100%; display: flex; flex-direction: column; align-items: center;
    background: none; border: none; color: inherit; font: inherit;
    padding: 22px 18px 10px; cursor: pointer; touch-action: manipulation;
  }
  /* Today / This-week stats tucked into the hero's top corners (left = today,
     right = this week) so the empty space flanking the avatar isn't wasted. */
  .hero-stat {
    position: absolute; top: 12px; z-index: 2;
    display: flex; flex-direction: column; gap: 1px;
    background: none; border: 0; color: inherit; font: inherit;
    padding: 5px 7px; border-radius: 12px; cursor: pointer; touch-action: manipulation;
    /* Kill the opaque native long-press highlight (WebKit text-selection / callout) that
       covered the whole card with a solid tint — leave only our own faint press state below. */
    -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
  }
  /* Press feedback: a FAINT translucent accent wash so the hero shows through, not the old
     opaque var(--surface-2) fill that read as a solid box on press. */
  .hero-stat:active { background: rgba(var(--accent-rgb),0.14); }
  /* Gentle themed hover wash (was nothing → felt dead on desktop). */
  .hero-stat:hover { background: rgba(var(--accent-rgb),0.08); }
  /* The global :focus-visible draws a hard 2px SOLID accent outline that read as a harsh bright
     box on this big rounded button. Swap it for a soft translucent ring (follows the radius,
     still theme-driven via --accent-rgb, still keyboard-visible). */
  .hero-stat:focus-visible { outline: none; box-shadow: 0 0 0 2px rgba(var(--accent-rgb),0.45); }
  .hero-stat-l { left: 10px; align-items: flex-start; text-align: left; }
  .hero-stat-r { right: 10px; align-items: flex-end; text-align: right; }
  /* Top-left "Coach" on/off switch — label + a slider toggle (off = Status). */
  .hero-mode { position: absolute; bottom: 10px; left: 12px; z-index: 5; display: inline-flex; align-items: center; gap: 7px; } /* moved 2026-06-10 (user pref A): Insights toggle from top-left → bottom-left footer zone, beside the "tap me" hint */
  .hero-mode-lbl { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
  .hero-switch { position: relative; width: 36px; height: 20px; flex-shrink: 0; border: 1px solid var(--text-dim); border-radius: 999px; background: var(--border-strong); cursor: pointer; padding: 0; touch-action: manipulation; transition: background 0.25s cubic-bezier(0.4,0,0.2,1), border-color 0.25s cubic-bezier(0.4,0,0.2,1); }
  .hero-switch.on { background: var(--accent); border-color: var(--accent); }
  /* Springy knob (slight overshoot) + GPU promotion so the slide stays smooth even while the
     hero re-renders/crossfades on toggle. translate3d keeps it on its own compositor layer. */
  .hero-switch-knob { position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; transform: translate3d(0,0,0); will-change: transform; transition: transform 0.28s cubic-bezier(0.34,1.4,0.5,1); box-shadow: 0 1px 2px rgba(0,0,0,0.4); }
  .hero-switch.on .hero-switch-knob { transform: translate3d(16px,0,0); }
  /* Free plan: NOT a fake toggle (that read as "flip me" but did nothing). A clear locked
     pill — lock + label + PRO tag — that taps through to billing. */
  .hero-lock-pill { gap: 6px; padding: 4px 9px 4px 8px; border: 1px solid var(--border-strong); border-radius: 999px; background: rgba(255,255,255,0.05); font: inherit; cursor: pointer; touch-action: manipulation; }
  .hero-lock-pill:active { background: rgba(255,255,255,0.1); }
  .hero-lock-ico { font-size: 11px; line-height: 1; }
  .hero-pro-tag { font-size: 9px; font-weight: 900; letter-spacing: 0.08em; color: var(--accent); border: 1px solid var(--accent); border-radius: 5px; padding: 1px 4px; line-height: 1.25; }
  .hero-stat-label { font-size: 9px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-dim); }
  .hero-stat-val { font-size: 19px; font-weight: 800; line-height: 1.1; font-variant-numeric: tabular-nums; }
  .hero-stat-sub { font-size: 10px; color: var(--text-muted); max-width: 92px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .hero-card.tone-go .hero-stat-val { color: var(--accent); }
  .hero-card.tone-behind .hero-stat-val { color: var(--you); }
  /* Today shown as a shrunk-down race: two stacked bars (avatar plan vs you). */
  .hero-race-mini { display: flex; flex-direction: column; gap: 4px; margin: 4px 0 3px; width: 182px; }
  .hrm-row { display: flex; align-items: center; gap: 5px; }
  .hrm-tag { width: 28px; flex-shrink: 0; font-size: 10px; font-weight: 800; letter-spacing: 0.02em; text-transform: uppercase; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .hrm-tag.jek { color: var(--accent); }
  .hrm-tag.me { color: var(--you); }
  /* Visible rail + outline so BOTH bars read as the same length even when one is near-empty
     (e.g. "0s" → no fill): you see the full equal-length track, not just the colored fill. */
  .hrm-track { flex: 1; max-width: 80px; height: 6px; border-radius: 999px; background: rgba(255,255,255,0.14); box-shadow: inset 0 0 0 1px var(--border-strong); overflow: hidden; }
  /* Fixed (not min-) width so both rows reserve the SAME value column — otherwise a wide
     value ("1h 15m") vs a narrow one ("0s") squeezes the flex tracks to different widths
     and the two gauges no longer line up. */
  /* Left-aligned so the time sits right next to the end of its bar (instead of pushed out
     to the far edge). Width is just enough for "12h 30m" so there's little trailing space —
     keeps the section tight against the avatar pill. Fixed so both gauges still line up. */
  .hrm-val { flex-shrink: 0; width: 42px; text-align: left; font-size: 10px; font-weight: 800; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .hrm-fill { display: block; height: 100%; border-radius: 999px; transition: width 0.3s ease; }
  .hrm-fill.jek { background: var(--accent); }
  .hrm-fill.me { background: var(--you); }
  .hero-face {
    font-size: 64px; line-height: 1; display: block; position: relative;
    filter: drop-shadow(0 4px 10px rgba(0,0,0,0.5)) var(--aura-glow, ); /* original aura: colored drop-shadow glow */
    /* Keep the avatar on its own GPU layer so the poke wiggle starts INSTANTLY from
       rest instead of dropping its first frames (the "lag then jump mid-anim" hitch). */
    will-change: transform; transform: translateZ(0);
  }
  /* Pro accessory badge — pinned to the avatar's top-right corner. */
  .av-acc { position: absolute; top: -3px; right: -9px; font-size: 25px; line-height: 1; pointer-events: none;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.55)); animation: accPop .5s cubic-bezier(.2,.9,.3,1.35) both; }
  .av-acc-lg { font-size: 30px; top: -4px; right: -10px; }
  .av-acc-sm { font-size: 16px; top: -5px; right: -6px; }   /* race faces (~38px) */
  .av-acc-xs { font-size: 12px; top: -5px; right: -5px; }   /* leaderboard faces (~20px) */
  /* Trophy (earned milestone) — pinned to the BOTTOM-right corner like a medal, so it reads as
     an award distinct from the free identity sticker. Overrides the default top-right corner. */
  /* Outline the trophy's OWN silhouette with an accent stroke so it's never mistaken for a plain
     sticker even when both are the same emoji (👑 worn as trophy AND picked as sticker). Four
     drop-shadows trace the emoji edge (NOT a coin/disc behind it); the last keeps the normal shadow. */
  .av-acc.rank { top: auto; bottom: -3px; right: -9px;
    filter:
      drop-shadow(1px 0 0 var(--accent)) drop-shadow(-1px 0 0 var(--accent))
      drop-shadow(0 1px 0 var(--accent)) drop-shadow(0 -1px 0 var(--accent))
      drop-shadow(0 2px 3px rgba(0,0,0,0.55));
    /* Cache the outlined result on its own compositor layer so a swaying ancestor just MOVES it
       instead of re-rasterising the 4-shadow stack each frame (that re-raster is the edge jitter). */
    will-change: transform; backface-visibility: hidden; }
  .av-acc-lg.rank { top: auto; bottom: -4px; right: -10px; }
  .av-acc-sm.rank { top: auto; bottom: -5px; right: -6px; }
  .av-acc-xs.rank { top: auto; bottom: -5px; right: -5px; }
  @keyframes accPop { 0% { opacity: 0; transform: scale(.3) rotate(-18deg); } 60% { transform: scale(1.18) rotate(6deg); } 100% { opacity: 1; transform: scale(1) rotate(0); } }
  @media (prefers-reduced-motion: reduce) { .av-acc { animation: none; } }
  /* Pro avatar AURA — a colored glow. Each `.aura-<id>` only SETS the glow as a custom
     property; each face context (.hero-face, .rh-face …) composes it with its own base
     drop-shadow via `var(--aura-glow, )`. This way one set of colors works at every size
     (CSS `filter` can't stack across rules, but a var inside one filter can). */
  /* The glow hugs the emoji's SHAPE (soft drop-shadow). TEXT-glyph faces (leaderboard) compose
     `--aura-glow` straight into their own filter. But filtering a live animated <img> makes
     Chromium shadow its bounding BOX → a square; so ActionEmoji stacks a STATIC png silhouette
     behind the webp and puts the glow on THAT (.ae-aura-glow) — shape-hugging glow, top still
     animates. `.aura-<id>` only ever lands on a face element (never the picker swatch .aura-opt). */
  /* --aura-glow = small drop-shadow for TEXT-glyph faces (leaderboard) — drop-shadow traces a
     glyph fine. --aura-tint = recolor+blur for the animated-webp glow copy (.ae-aura-glow):
     grayscale→sepia→saturate→hue-rotate pushes the emoji to the aura hue, blur makes it a soft
     shape-hugging halo that follows every animation frame (the hue is approximate by design). */
  .aura-sunset { --aura-glow: drop-shadow(0 0 5px rgba(245,158,11,0.5)) drop-shadow(0 0 2px rgba(239,68,68,0.45)); --aura-tint: grayscale(1) sepia(1) saturate(6) hue-rotate(0deg) brightness(1) blur(6px); --aura-color: rgba(245,158,11,0.55); }
  .aura-ocean  { --aura-glow: drop-shadow(0 0 5px rgba(56,189,248,0.5)) drop-shadow(0 0 2px rgba(99,102,241,0.45)); --aura-tint: grayscale(1) sepia(1) saturate(6) hue-rotate(165deg) brightness(1) blur(6px); --aura-color: rgba(56,189,248,0.55); }
  .aura-forest { --aura-glow: drop-shadow(0 0 5px rgba(52,211,153,0.5)) drop-shadow(0 0 2px rgba(16,185,129,0.45)); --aura-tint: grayscale(1) sepia(1) saturate(6) hue-rotate(110deg) brightness(1) blur(6px); --aura-color: rgba(52,211,153,0.55); }
  .aura-candy  { --aura-glow: drop-shadow(0 0 5px rgba(244,114,182,0.5)) drop-shadow(0 0 2px rgba(167,139,250,0.45)); --aura-tint: grayscale(1) sepia(1) saturate(6) hue-rotate(290deg) brightness(1) blur(6px); --aura-color: rgba(244,114,182,0.55); }
  .aura-gold   { --aura-glow: drop-shadow(0 0 5px rgba(253,230,138,0.55)) drop-shadow(0 0 2px rgba(245,158,11,0.5)); --aura-tint: grayscale(1) sepia(1) saturate(5) hue-rotate(15deg) brightness(1.1) blur(6px); --aura-color: rgba(253,230,138,0.6); }
  .aura-frost  { --aura-glow: drop-shadow(0 0 5px rgba(165,243,252,0.55)) drop-shadow(0 0 2px rgba(129,140,248,0.45)); --aura-tint: grayscale(1) sepia(1) saturate(5) hue-rotate(150deg) brightness(1.15) blur(6px); --aura-color: rgba(165,243,252,0.6); }
  /* Animated aura: a soft colored halo that BREATHES behind any aura'd face (in addition to
     the static shape-glow above). `aura-fx` is added by auraClass alongside `aura-<id>`, so it
     only ever lands on real faces (hero / leaderboard / friends / league / rest-header), never
     the picker swatch. The halo color is the per-aura `--aura-color`; it scales+fades in a slow
     2.6s loop so the avatar feels alive. */
  .aura-fx { position: relative; }
  .aura-fx::before {
    /* Reverted 2026-06-10 per user ("ทำไมออร่าเป็นอย่างนี้? revert เหมือนเดิม"): the breathing
       radial-gradient halo (added by a concurrent session) read as a big blue blob. Back to the
       subtle per-aura --aura-glow drop-shadow only (the v471 look). Re-enable by restoring this rule. */
    display: none;
  }
  @keyframes auraBreath {
    0%, 100% { transform: scale(0.82); opacity: 0.4; }
    50%      { transform: scale(1.14); opacity: 0.8; }
  }
  /* Accessory: keep the entrance pop, then a gentle endless twinkle so the badge sparkles. */
  .av-acc { animation: accPop .5s cubic-bezier(.2,.9,.3,1.35) both, accTwinkle 2.8s ease-in-out .5s infinite; }
  /* A user-dragged badge is positioned via inline left/top + translate(-50%) centering, so it
     can't also run the corner twinkle (that animates transform and would fight the centering). */
  .av-acc.placed { animation: none; }
  .av-acc.av-acc-drag { pointer-events: auto; cursor: grab; touch-action: none; }
  .av-acc.av-acc-drag:active { cursor: grabbing; }
  .acc-size-row { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
  .acc-size-label { font-size: 13px; color: var(--text-dim); flex: 0 0 auto; }
  .acc-size-slider { flex: 1 1 auto; min-width: 0; accent-color: var(--accent); }
  /* The ＋ "more emoji" swatch in the sticker quick-row. */
  .acc-opt.acc-more .acc-dot { font-size: 18px; color: var(--text-dim); }
  .aura-opt:disabled { opacity: 0.4; cursor: default; }
  /* A sticker slot: emoji · size slider · remove. */
  .sticker-slot { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
  .sticker-slot-em { flex: 0 0 auto; font-size: 22px; line-height: 1; width: 26px; text-align: center; }
  .sticker-slot .acc-size-slider { flex: 1 1 auto; }
  .sticker-slot .link-btn { flex: 0 0 auto; white-space: nowrap; }
  .sticker-reset { font-size: 16px; line-height: 1; padding: 2px 4px; }
  /* Front/back tag on each sticker row — the "front" layer is highlighted in the accent color. */
  .sticker-layer { flex: 0 0 auto; font-size: 10px; font-weight: 800; letter-spacing: .02em; text-transform: uppercase;
    color: var(--text-muted); background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 2px 7px; }
  .sticker-layer.front { color: var(--accent); border-color: var(--accent); background: rgba(var(--accent-rgb), 0.14); }
  /* Swap front/back button — centered pill under the two sticker rows. */
  .sticker-swap { display: block; margin: 8px auto 0; border: 1px solid var(--border); background: var(--surface-2);
    color: var(--text); font-size: 12.5px; font-weight: 700; border-radius: 999px; padding: 6px 16px; cursor: pointer;
    transition: border-color .14s ease, color .14s ease; }
  .sticker-swap:hover { border-color: var(--accent); color: var(--accent); }
  /* Full Custom (Pro) — flip button, rotate slider row, and the locked teaser. */
  /* Each placed sticker = one tidy card: header (emoji + layer + actions), then labelled Size / Rotate. */
  .sticker-block { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border-radius: 12px; border: 1px solid var(--border); background: var(--surface-2); transition: border-color .14s ease; }
  .sticker-block.sel { border-color: var(--accent); }
  .sticker-head { display: flex; align-items: center; gap: 8px; }
  .sticker-head-sp { flex: 1; }
  .sticker-rm { color: var(--danger); }
  .sticker-ctl { display: flex; align-items: center; gap: 10px; }
  .sticker-ctl-lbl { flex: 0 0 auto; width: 46px; font-size: 11px; font-weight: 700; color: var(--text-muted); }
  .sticker-ctl .acc-size-slider { flex: 1; min-width: 0; }
  .sticker-block .sticker-slot { margin-top: 0; }
  .fx-btn { flex: 0 0 auto; border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
    border-radius: 8px; padding: 5px 11px; font-size: 13px; font-weight: 700; cursor: pointer; line-height: 1;
    transition: border-color .14s ease, color .14s ease, background .14s ease; }
  .fx-btn:hover { border-color: var(--accent); color: var(--accent); }
  .fx-btn.on { border-color: var(--accent); color: var(--accent); background: rgba(var(--accent-rgb), 0.14); }
  .fx-btn-sm { padding: 3px 7px; font-size: 14px; }
  .facefx { margin-top: 8px; }
  .facefx-row { display: flex; align-items: center; gap: 10px; }
  .fx-ic { flex: 0 0 auto; color: var(--text-muted); font-size: 16px; line-height: 1; }
  .fx-val { flex: 0 0 auto; width: 42px; text-align: right; font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
  .sticker-rotate-row { display: flex; align-items: center; gap: 10px; margin-top: 6px; padding-left: 36px; }
  .fullcustom-lock { display: flex; align-items: center; gap: 10px; width: 100%; margin-top: 8px;
    border: 1px dashed var(--border); background: var(--surface-2); border-radius: 12px; padding: 10px 12px;
    cursor: pointer; text-align: left; transition: border-color .14s ease; }
  .fullcustom-lock:hover { border-color: var(--accent); }
  .fullcustom-lock-ic { flex: 0 0 auto; font-size: 18px; }
  .fullcustom-lock-txt { flex: 1 1 auto; font-size: 13px; color: var(--text-dim); line-height: 1.35; }
  .fullcustom-lock-cta { flex: 0 0 auto; font-size: 12px; font-weight: 800; color: var(--accent); white-space: nowrap; }
  /* Rank line: the auto badge + an explainer, separate from the free stickers. */
  .rank-line { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
  .rank-line-em { flex: 0 0 auto; font-size: 22px; line-height: 1; width: 26px; text-align: center; }
  .rank-line-txt { font-size: 13px; color: var(--text-dim); line-height: 1.4; }
  /* Trophy picker — the earned-milestone ladder. Locked tiers render greyed (a visible goal). */
  .trophy-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
  .trophy-opt { display: flex; flex-direction: column; align-items: center; gap: 2px; width: 48px; padding: 6px 0 4px;
    border-radius: 12px; border: 2px solid var(--border-strong); background: var(--surface); cursor: pointer;
    transition: transform .12s ease, border-color .15s ease; }
  .trophy-opt:active { transform: scale(0.94); }
  .trophy-opt.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, var(--surface)); }
  .trophy-opt.locked { opacity: 0.5; cursor: default; border-style: dashed; }
  /* Reusable accent outline that traces an emoji's own silhouette (4 drop-shadows). Same trophy
     stroke used on the avatar (.av-acc.rank), the Trophy orbit slot, and every picker-grid cell —
     so a trophy reads the same everywhere. Flat contexts, so no depth shadow here. */
  .trophy-outline { display: inline-flex; line-height: 0;
    filter:
      drop-shadow(1px 0 0 var(--accent)) drop-shadow(-1px 0 0 var(--accent))
      drop-shadow(0 1px 0 var(--accent)) drop-shadow(0 -1px 0 var(--accent)); }
  /* Locked slots show the REAL trophy in COLOUR but dimmed (the .locked opacity above does the
     dimming), with a small 🔒 corner badge so "not yet earned" still reads at a glance. */
  .trophy-opt-em { position: relative; }
  .trophy-opt-lock { position: absolute; right: -7px; bottom: -5px; font-size: 11px; line-height: 1;
    filter: drop-shadow(0 1px 1px rgba(0,0,0,0.6)); }
  .trophy-opt-em { font-size: 22px; line-height: 1; display: flex; align-items: center; justify-content: center; min-height: 24px; }
  .trophy-opt-days { font-size: 10px; font-weight: 700; color: var(--text-dim); }
  .trophy-opt.on .trophy-opt-days { color: var(--accent); }
  /* The auto rank badge sits at the classic top-right corner (like the old single accessory). */
  .av-acc.rank { animation: accPop .5s cubic-bezier(.2,.9,.3,1.35) both; }
  /* Saved looks: a Save button + a row of re-applicable avatar snapshots. */
  /* Saved looks — a small "wardrobe" panel: snapshot the avatar and re-apply. */
  .looks-card { background: linear-gradient(180deg, var(--surface-2), var(--surface)); border: 1px solid var(--border); border-radius: 18px; padding: 14px; margin-top: 8px; }
  .looks-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
  .looks-head .looks-head-txt { flex: 1 1 auto; }
  .looks-head-ic { font-size: 17px; width: 34px; height: 34px; display: flex; align-items: center; justify-content: center; background: rgba(var(--accent-rgb),0.12); border-radius: 11px; flex: 0 0 auto; }
  .looks-head-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .looks-head-title { font-size: 13px; font-weight: 700; color: var(--text); letter-spacing: 0.01em; }
  .looks-head-sub { font-size: 11px; color: var(--text-muted); }
  .looks-grid { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
  /* Quiet ghost "add" affordance — a dashed accent outline, not a loud filled button. Lives in
     the header row (right of the title) so the card stays compact instead of the pill eating a
     whole row of its own. */
  .looks-save { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 600; color: var(--accent); background: rgba(var(--accent-rgb),0.07); border: 1px dashed rgba(var(--accent-rgb),0.45); border-radius: 10px; padding: 6px 10px; cursor: pointer; transition: background .12s ease, border-color .12s ease; }
  .looks-save:hover:not(:disabled) { background: rgba(var(--accent-rgb),0.13); border-color: var(--accent); }
  .looks-save:active:not(:disabled) { background: rgba(var(--accent-rgb),0.2); }
  .looks-save:disabled { opacity: 0.4; cursor: default; }
  .look-chip { position: relative; flex: 0 0 auto; }
  .look-face { position: relative; width: 50px; height: 50px; display: flex; align-items: center; justify-content: center; background: var(--surface); border: 1px solid var(--border); border-radius: 14px; cursor: pointer; transition: transform .12s ease, border-color .12s ease, box-shadow .12s ease; }
  .look-face:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: 0 5px 12px rgba(0,0,0,0.18); }
  /* Tight glyph-sized box so placed stickers reference the FACE, not the padded chip (matches editor). */
  .look-face-glyph { position: relative; display: inline-flex; width: 30px; height: 30px; align-items: center; justify-content: center; }
  .look-del { position: absolute; top: -6px; right: -6px; width: 18px; height: 18px; border-radius: 50%; background: var(--surface); border: 1px solid var(--border-strong); color: var(--text-dim); font-size: 10px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; }
  .look-del:hover { color: #f87171; border-color: #f87171; }
  .looks-empty { font-size: 12px; color: var(--text-muted); margin-top: 11px; line-height: 1.55; padding-top: 11px; border-top: 1px dashed var(--border); }
  @keyframes accTwinkle { 0%, 100% { transform: scale(1) rotate(0); } 50% { transform: scale(1.12) rotate(5deg); } }
  @media (prefers-reduced-motion: reduce) { .aura-fx::before { animation: none; } .av-acc { animation: accPop .5s both; } }
  /* Aura'd animated face (ActionEmoji): a blurred, hue-tinted copy of the SAME webp sits behind
     the crisp face (both animate in sync). The glow copy is CLIPPED to a circle (.ae-aura-clip)
     so it can never spill outside the frame as a square — only a contained circular halo shows. */
  .ae-aura { position: relative; display: inline-block; line-height: 0; vertical-align: top; isolation: isolate; }
  /* The glow copy hugs the emoji shape, but is clipped to the FRAME (the face box) so the part
     that would spill OUTSIDE — the square halo — is cut and never shows. Tiny radius just softens
     the corners; no big circle disc. */
  .ae-aura > .ae-aura-clip { position: absolute; inset: 0; z-index: -1; overflow: hidden; border-radius: 16%; pointer-events: none; }
  .ae-aura-clip > .ae-aura-glow { width: 100%; height: 100%; transform: scale(1.08); filter: var(--aura-tint, ); }
  /* Aura picker (Avatar tab) */
  .aura-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 4px; }
  .aura-opt { width: 42px; height: 42px; border-radius: 50%; border: 2px solid var(--border-strong); background: var(--surface);
    display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; touch-action: manipulation; transition: border-color .15s, transform .06s; }
  .aura-opt:active { transform: scale(0.94); }
  .aura-opt.on { border-color: var(--accent); }
  .aura-dot { width: 27px; height: 27px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
    font-size: 12px; color: #fff; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.18); }
  .acc-dot { display: flex; align-items: center; justify-content: center; font-size: 20px; line-height: 1; color: var(--text-muted); }
  /* Accent-theme picker (Settings) */
  .theme-row { display: flex; flex-wrap: wrap; gap: 10px; }
  .theme-opt { width: 42px; height: 42px; border-radius: 50%; border: 2px solid var(--border-strong); background: var(--surface);
    display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; touch-action: manipulation; transition: border-color .15s, transform .06s; }
  .theme-opt:active { transform: scale(0.94); }
  .theme-opt.on { border-color: var(--text); }
  .theme-dot { width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
    font-size: 14px; font-weight: 900; color: #0b1220; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.18); }
  /* Avatar face + its live action emoji, side by side */
  .hero-stage { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 80px; }
  .action-emoji { display: block; }
  /* Noto emoji + photo avatars render as real <img>, so iPadOS/iOS long-press offers the
     native "Save to Photos / Share / Copy" callout. Kill it everywhere so the app behaves
     like desktop — these images aren't user content to save/drag. */
  .action-emoji, .face-img, .ae-aura-glow, .av-acc img, .action-fallback {
    -webkit-touch-callout: none;
    -webkit-user-select: none; user-select: none;
    -webkit-user-drag: none;
  }
  /* Emoji with no Noto animation gently sway side-to-side so they still feel alive */
  /* Start/END at REST (0deg) — NOT at -8deg — so the sway eases out from center instead
     of snapping straight to a tilt on the very first frame (that snap is the "skip/jump"
     you saw on no-gif avatars). The hold at 0–16% is a deliberate STOP before each wiggle,
     and 0%==100%==rest makes the infinite loop seamless. */
  @keyframes emojiSway {
    /* Continuous pendulum L<->R — NO 0deg hold at the centre (that read as a pause after each
       left-right). Slowing at the extremes is natural pendulum ease, not a stop. */
    0% { transform: rotate(-8deg); }
    50% { transform: rotate(8deg); }
    100% { transform: rotate(-8deg); }
  }
  .emoji-sway { animation: emojiSway 1.5s ease-in-out infinite; transform-origin: 50% 75%; will-change: transform; backface-visibility: hidden; }
  @media (prefers-reduced-motion: reduce) { .emoji-sway { animation: none; } }
  /* User toggle: kill the fake sway on no-gif emojis app-wide (genuinely-animated webp faces still play). */
  body.no-sway .emoji-sway { animation: none; }
  .hero-action { filter: drop-shadow(0 3px 8px rgba(0,0,0,0.45)); position: relative; top: 0; will-change: transform; transform: translateZ(0); }
  /* Crossfade: the action/status emoji swaps (⚡ working ↔ 😏 status) overlap —
     outgoing fades+scales out while the incoming fades in over it. */
  .xfade { position: relative; display: inline-block; }
  .xfade-layer { position: absolute; left: 0; top: 0; }
  .xfade-layer.xin { animation: xfadeIn 0.4s ease forwards; }
  .xfade-layer.xout { animation: xfadeOut 0.4s ease forwards; }
  @keyframes xfadeIn { from { opacity: 0; transform: scale(0.82); } to { opacity: 1; transform: scale(1); } }
  @keyframes xfadeOut { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(1.12); } }
  /* A no-gif crossfade face (e.g. the hero "action" bike) must wiggle too. But `.xfade-layer.xin`
     (0,2,0) sets its own `animation`, which REPLACES `.emoji-sway` (0,1,0) entirely — so the sway
     was silently dropped and the face sat frozen on its settled frame. Run BOTH: xfadeIn does the
     one-shot opacity intro, emojiSway the perpetual wiggle (emojiSway is last, so it owns transform
     after the 0.4s intro). no-sway / reduced-motion still win via their own rules. */
  .xfade-layer.xin.emoji-sway { animation: xfadeIn 0.4s ease forwards, emojiSway 1.5s ease-in-out infinite; }
  body.no-sway .xfade-layer.xin.emoji-sway { animation: xfadeIn 0.4s ease forwards; }
  .hero-face.anim-run { animation: avatarRun 0.8s ease-in-out infinite; }
  .hero-face.anim-dash { animation: avatarDash 1.1s ease-in-out infinite; }
  /* Quick bounce/wiggle when you tap (poke) the avatar — overrides the idle anim. */
  .hero-face.poking { animation: heroPoke 0.5s ease !important; }
  .hero-action.poking { animation: heroPoke 0.5s ease !important; }
  @keyframes heroPoke {
    /* Hold dead-still for the first ~14% (~70ms) so the avatar visibly STOPS, then snaps
       into the wiggle — reads as a deliberate "freeze → react" beat, not a mid-anim jump. */
    0%, 14% { transform: scale(1) rotate(0); }
    34% { transform: scale(1.18) rotate(-7deg); }
    60% { transform: scale(0.94) rotate(6deg); }
    82% { transform: scale(1.06) rotate(-3deg); }
    100% { transform: scale(1) rotate(0); }
  }
  .hero-name { font-size: 22px; font-weight: 800; margin-top: 10px; letter-spacing: 0.01em; }
  /* While a block is live the avatar's name slot shows the ticking countdown instead. */
  .hero-name.timing { color: var(--accent); font-variant-numeric: tabular-nums; letter-spacing: 0; }
  .hero-head { font-size: 14px; font-weight: 700; margin-top: 8px; text-align: center; }
  .hero-sub { font-size: 12px; color: var(--text-muted); margin-top: 3px; text-align: center; }
  /* Fade + slight rise when the quote/sub/actions swap on a Status ↔ Insights toggle.
     The keyed spans remount on mode change, replaying this; the emoji crossfades on its own. */
  @keyframes heroSwap { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
  .hero-swap { animation: heroSwap 0.26s ease both; }
  @media (prefers-reduced-motion: reduce) { .hero-swap, .hero-coach-lock { animation: none; } }
  .hero-edit { font-size: 11px; color: var(--text-dim); font-weight: 700; margin-top: 12px; }
  /* Coach lives in the hero: its insight is JEK's quote (.hero-head.coachy); below the
     avatar, this strip holds just the action buttons, centered under the quote. */
  /* Insight quote: same 14px head as every other state, just constrained to a comfortable
     width so it wraps like a headline. No fixed height — it flows naturally (1–2 lines) exactly
     as the off-mode head does, keeping the two modes visually identical. */
  .hero-head.coachy { line-height: 1.4; max-width: 290px; margin-left: auto; margin-right: auto; }
  /* Only rendered when the foot has an actionable CoachCard suggestion (Reschedule/Drop it) —
     the ONE case where the Insights toggle needs to share the footer band with real content.
     `.hero-mode` is rendered INLINE here (train.html passes the same node, but as a flex child
     instead of its usual absolute bottom-left) so flex-wrap can drop it above the action
     button(s) on narrow phones — robust at any width, no breakpoint number to guess. At
     widths wide enough for both, `justify-content: space-between` keeps the row: toggle left,
     action(s) right, same look as before. */
  .hero-foot-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 14px; padding: 2px 16px 18px; animation: heroSwap 0.26s ease both; }
  .hero-foot-row .hero-mode { position: static; }
  .hero-coach { display: flex; }
  .hero-coach .coach-applied { margin-top: 0; }
  .hero-coach .coach-act, .hero-coach .coach-acts { margin-top: 0; }
  /* Tiny poke-hint footer under the coach actions (replaces the old in-button "tap me"). */
  /* Reserve a constant bottom-slot height so flipping to Insights (which may have no
     action buttons) never makes the hero card shorter than the avatar/poke state. */
  .hero-foot { min-height: 34px; display: flex; flex-direction: column; justify-content: center; }
  .hero-tapme { display: block; width: 100%; border: none; background: none; font: inherit;
    color: var(--text-dim); font-size: 11px; font-weight: 700; text-align: center;
    padding: 6px 0 14px; cursor: pointer; touch-action: manipulation; }
  .hero-tapme:active { color: var(--text-muted); }
  /* Free state: a slim full-width unlock teaser occupying the same hero slot. */
  /* Single compact ROW (no extra card height): a short, truly-CENTRED green CTA (symmetric padding).
     It fades/rises in with the same heroSwap motion as the head/sub so it doesn't hard-pop when it
     appears (e.g. after the Pro/Free entitlement reconciles or when Insights is toggled on). */
  /* No entrance "pop" — the lock can appear/re-appear several times while the Free/Pro
     entitlement reconciles on load; a scale-in each time reads as flicker. Plain appear. */
  .hero-coach-lock { width: 100%; border: none; background: none; font: inherit; font-weight: 800; font-size: 12px; color: var(--accent); cursor: pointer; touch-action: manipulation; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 7px 16px 14px; white-space: nowrap; }
  .hero-coach-lock:active { background: rgba(var(--accent-rgb),0.1); }
  @media (prefers-reduced-motion: reduce) { .hero-face, .hero-action, .xfade-layer { animation: none !important; } }

  /* --- Avatar customize + Settings --- */
  .av-screen, .set-screen { display: flex; flex-direction: column; gap: 4px; }
  /* Progress-tab mode switch: Mine (your progress) ↔ Friends (leaderboard). */
  /* Progress toggles share ONE row: Mine|Friends on the left, Day|Week on the right
     (in Friends mode the view-toggle is hidden, so mode-toggle spans the full width). */
  /* No margin-bottom: .hist-screen is a flex column with gap:12px, so a margin-bottom here STACKED
     on top of that gap (12+8=20px), leaving the toggle row floating too far above the first card.
     The flex-column gap alone spaces it (≈ the Schedule row's 14px). */
  .hist-toggles { display: flex; gap: 8px; }
  .hist-toggles .mode-toggle, .hist-toggles .view-toggle { flex: 1; margin-bottom: 0; }
  .hist-toggles .view-toggle { border-radius: 999px; padding: 4px; }
  .hist-toggles .view-toggle .view-toggle-btn { border-radius: 999px; padding: 8px 0; }
  .mode-toggle { display: flex; gap: 6px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 4px; margin-bottom: 8px; }
  .mode-toggle button { flex: 1; background: none; border: 0; color: var(--text-muted); font: inherit; font-weight: 800; font-size: 13px; padding: 8px; border-radius: 999px; cursor: pointer; touch-action: manipulation; transition: background .15s ease, color .15s ease; }
  .mode-toggle button.on { background: var(--accent); color: var(--accent-text); box-shadow: 0 1px 5px rgba(var(--accent-rgb),0.4); }
  .mode-toggle button:not(.on):hover { color: var(--text); background: rgba(255,255,255,0.04); }
  .mode-toggle button.on:hover { background: var(--accent); color: var(--accent-text); }
  /* ONE preview box, IDENTICAL on every tab (Face / Decorate / Personality) — the user wants them to
     look the same so it's easy to understand while adjusting. Centered face so it's still big enough
     to drag stickers / resize on the Decorate tab, but trimmed shorter than before (tighter padding +
     persona chip moved to the top-right corner) so the controls below stay reachable without
     scrolling. Scrolls with the form — not pinned/sticky. (2026-06-11) */
  .av-preview {
    position: relative;
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 13px 14px;
    box-shadow: 0 8px 18px -12px rgba(0,0,0,0.7);
  }
  .av-preview .hero-face { margin: 0; }
  .av-preview .hero-name { font-size: 18px; margin-top: 5px; }
  /* Name is edited by tapping it under the avatar (no separate NAME field). Button = the name + a faint
     pencil; tapping swaps in an inline input styled to match so nothing jumps. */
  .hero-name-btn { display: inline-flex; align-items: center; gap: 6px; background: transparent; border: 0; padding: 0; color: inherit; font-family: inherit; cursor: pointer; }
  .hero-name-pen { width: 13px; height: 13px; opacity: 0.5; flex-shrink: 0; }
  .hero-name-btn:hover .hero-name-pen { opacity: 0.9; }
  .hero-name-edit { font-size: 18px; font-weight: 800; margin-top: 5px; text-align: center; color: var(--text); background: transparent; border: 0; border-bottom: 2px solid var(--accent); padding: 2px 4px; max-width: 200px; outline: none; }
  /* Composed avatar hero: avatar center, personality (left) / saved-looks (top) / accessories (right) orbit it. */
  .av-hero { display: grid; grid-template-columns: auto 1fr auto; grid-template-rows: auto auto; grid-template-areas: "looks looks looks" "persona center acc"; align-items: center; gap: 14px 8px; padding: 16px 16px 20px; border-radius: 20px; border: 1px solid var(--border); background: linear-gradient(180deg, var(--surface-2), var(--surface)); box-shadow: inset 0 1px 0 rgba(255,255,255,0.03); margin-top: 6px; }
  .av-hero > .av-hero-persona { justify-self: start; }
  .av-hero-looks { grid-area: looks; justify-self: center; display: inline-flex; align-items: center; gap: 5px; padding: 5px 13px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface); color: var(--text); font-size: 12px; font-weight: 700; cursor: pointer; transition: border-color .14s ease, background .14s ease; }
  .av-hero-looks:hover { border-color: var(--border-strong); }
  .av-hero-looks-ic { font-size: 13px; }
  .av-hero-looks-n { color: var(--text-muted); font-weight: 700; }
  /* Personality (left) + accessories (right) share ONE circular visual language so the hero reads as
     one system: a round chip holds each attribute, a small caption names it. */
  .av-hero-persona { grid-area: persona; justify-self: center; display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 0; border: 0; background: transparent; cursor: pointer; }
  .av-hero-persona-em { width: 46px; height: 46px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 24px; line-height: 1; background: var(--surface); border: 1px solid var(--border); transition: border-color .14s ease, box-shadow .14s ease; }
  .av-hero-persona:hover .av-hero-persona-em { border-color: var(--border-strong); }
  .av-hero-persona.on .av-hero-persona-em { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(var(--accent-rgb),0.25); }
  .av-hero-persona-lbl { max-width: 74px; font-size: 10.5px; font-weight: 700; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .av-hero-center { grid-area: center; position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px; }
  /* Rotate handle for the MAIN face — same look as a sticker's, floating just above the avatar. */
  .av-face-rotor { position: absolute; top: -14px; left: 50%; transform: translateX(-50%); z-index: 6; width: 24px; height: 24px; border-radius: 50%; background: var(--accent); color: #06120a; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; box-shadow: 0 2px 7px rgba(0,0,0,0.5); }
  .av-face-rotor:active { cursor: grabbing; }
  .av-hero-center .hero-name, .av-hero-center .hero-name-edit { font-size: 18px; margin-top: 8px; }
  .av-hero-acc { grid-area: acc; justify-self: center; display: flex; flex-direction: column; gap: 10px; }
  /* Left orbit column (persona + trophy) mirrors .av-hero-acc so both flanks balance around the face. */
  .av-hero-side { justify-self: center; display: flex; flex-direction: column; align-items: center; gap: 10px; }
  .av-hero-side.left { grid-area: persona; }
  .av-acc-item { display: flex; flex-direction: column; align-items: center; gap: 4px; }
  /* overflow:visible + no fixed clip — a fixed max-width chopped the PRO badge's right border
     ("Sticker 2 PRO" / TH "สติกเกอร์ 2 PRO" is wider than 74px). Label sizes to its content. */
  .av-acc-lbl { display: inline-flex; align-items: center; gap: 4px; max-width: 110px; font-size: 10.5px; font-weight: 700; color: var(--text-muted); overflow: visible; white-space: nowrap; }
  .av-acc-pro { flex: 0 0 auto; font-size: 8px; font-weight: 800; letter-spacing: 0.3px; color: var(--accent); border: 1px solid rgba(var(--accent-rgb),0.4); border-radius: 4px; padding: 0 3px; line-height: 1.5; }
  .av-acc-slot { width: 46px; height: 46px; border-radius: 50%; border: 1px dashed var(--border-strong); background: var(--surface); display: flex; align-items: center; justify-content: center; font-size: 18px; color: var(--text-muted); cursor: pointer; transition: border-color .14s ease, background .14s ease, box-shadow .14s ease, transform .08s ease; }
  .av-acc-slot:hover { border-color: var(--border-strong); color: var(--text); }
  .av-acc-slot.filled { border-style: solid; border-color: var(--border); background: var(--surface-2); color: var(--text); }
  .av-acc-slot:active { transform: scale(0.92); }
  .av-hero-looks.on, .av-acc-slot.on { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(var(--accent-rgb),0.25); }
  .av-hero-looks.on { background: var(--surface-2); }
  /* A selected sticker on the face gets a dashed ring + a rotate handle floating above it (drag = spin,
     Photoshop free-transform style). Both only show while the Sticker editor panel is open. */
  .av-acc-drag.sel { outline: 2px dashed var(--accent); outline-offset: 3px; border-radius: 6px; }
  .av-acc-rotor { position: absolute; z-index: 6; transform: translate(-50%, -50%); width: 24px; height: 24px; border-radius: 50%; background: var(--accent); color: #06120a; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; box-shadow: 0 2px 7px rgba(0,0,0,0.5); }
  .av-acc-rotor:active { cursor: grabbing; }
  .av-preview-meta { display: flex; flex-direction: column; align-items: center; gap: 1px; }
  /* Segmented tab bar that splits the long Avatar form into Face / Decorate / Personality so the
     user edits one group at a time instead of scrolling a giant column. */
  .av-tabs { display: flex; gap: 4px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 13px; padding: 4px; margin-top: 12px; }
  .av-tab { flex: 1 1 0; min-width: 0; border: none; background: transparent; color: var(--text-muted); font-size: 13px; font-weight: 700; padding: 9px 6px; border-radius: 9px; cursor: pointer; transition: background .14s ease, color .14s ease; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .av-tab:hover:not(.on) { color: var(--text); }
  .av-tab.on { background: var(--surface); color: var(--text); box-shadow: 0 1px 4px rgba(0,0,0,0.18); }
  .av-tab-panel { margin-top: 4px; display: flex; flex-direction: column; }
  /* The FACE picker + main-emoji CUSTOM sit AFTER whichever tap-panel is open (order:5), so an opened
     editor appears right under the hero — not far below the picker. */
  .av-below { order: 5; }
  .av-face-tap { cursor: pointer; border-radius: 12px; }
  .av-face-tap.on { outline: 2px dashed var(--accent); outline-offset: 3px; }
  .av-hint { order: 6; text-align: center; font-size: 11.5px; color: var(--text-muted); margin-top: 12px; }
  .av-preview-tag { font-size: 11.5px; line-height: 1.35; color: var(--text-muted); text-align: center; max-width: 260px; margin-top: 1px; }
  /* Persona chip parked in the box's top-right corner (same place on every tab). */
  .av-preview-chips { position: absolute; top: 9px; right: 10px; display: flex; gap: 6px; }
  .av-preview-chips .av-chip { max-width: 120px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .av-chip {
    font-size: 12px; font-weight: 700; color: var(--text-muted);
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 5px 11px;
  }
  .av-chip.on { color: var(--accent); border-color: var(--accent); background: rgba(var(--accent-rgb), 0.14); }
  /* Grid so 5+ personality presets (+ Custom) wrap to rows instead of squashing. */
  .behavior-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 4px; }
  .behavior-chip {
    position: relative;
    min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 5px;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    border-radius: 12px; padding: 12px 6px; font: inherit; cursor: pointer; touch-action: manipulation;
    transition: transform 0.14s ease, background 0.14s ease, border-color 0.14s ease;
  }
  .behavior-chip:hover { transform: translateY(-2px); border-color: var(--border-strong); }
  .behavior-chip:active { transform: scale(0.96); }
  .behavior-chip.on { border-color: var(--accent); background: rgba(var(--accent-rgb),0.14); }
  /* Locked personas still show THEIR OWN emoji (dimmed) + name so every chip is distinct — only a small
     corner 🔒 marks them Pro (was: a blank 🔒 that made every locked chip look identical). */
  .behavior-chip.locked { border-style: dashed; }
  .behavior-emoji.locked { opacity: 0.4; }
  .behavior-lock { position: absolute; top: 6px; right: 6px; font-size: 11px; line-height: 1; opacity: 0.85; }
  /* Every personality's emoji gently sways so the row feels alive; the selected one swings livelier.
     Staggered delays across ALL chips (not just the first row) so no two bob in lock-step. */
  .behavior-emoji { font-size: 22px; line-height: 1; display: inline-block; transform-origin: 50% 80%; animation: behaviorBob 2.2s ease-in-out infinite; }
  .behavior-chip:nth-child(2) .behavior-emoji { animation-delay: -0.55s; }
  .behavior-chip:nth-child(3) .behavior-emoji { animation-delay: -1.1s; }
  .behavior-chip:nth-child(4) .behavior-emoji { animation-delay: -1.65s; }
  .behavior-chip:nth-child(5) .behavior-emoji { animation-delay: -0.3s; }
  .behavior-chip:nth-child(6) .behavior-emoji { animation-delay: -0.85s; }
  .behavior-chip:nth-child(7) .behavior-emoji { animation-delay: -1.4s; }
  .behavior-chip:nth-child(8) .behavior-emoji { animation-delay: -1.95s; }
  .behavior-chip:nth-child(9) .behavior-emoji { animation-delay: -0.15s; }
  .behavior-chip:nth-child(10) .behavior-emoji { animation-delay: -0.7s; }
  .behavior-chip:nth-child(11) .behavior-emoji { animation-delay: -1.25s; }
  .behavior-chip:nth-child(12) .behavior-emoji { animation-delay: -1.8s; }
  .behavior-chip.on .behavior-emoji { animation-duration: 1.4s; }
  @keyframes behaviorBob {
    0%, 100% { transform: translateY(0) rotate(-9deg); }
    50% { transform: translateY(-2px) rotate(9deg); }
  }
  @media (prefers-reduced-motion: reduce) { .behavior-emoji { animation: none; } }
  .behavior-name { font-size: 12px; font-weight: 700; text-align: center; }
  .behavior-chip.on .behavior-name { color: var(--accent); }
  .behavior-18 { display: inline-block; margin-left: 4px; font-size: 8px; font-weight: 800; letter-spacing: 0.02em; color: #fff; background: #ef4444; border-radius: 999px; padding: 1px 4px; vertical-align: middle; }
  /* Custom personality "design" panel — two trait sliders + a live mix + sample line. */
  .trait-panel { margin-top: 12px; padding: 14px; border: 1px solid var(--border); border-radius: 14px; background: var(--surface-2); display: flex; flex-direction: column; gap: 14px; }
  .trait-row { display: flex; flex-direction: column; gap: 5px; }
  .trait-ends { display: flex; justify-content: space-between; align-items: baseline; font-size: 11px; color: var(--text-dim); font-weight: 600; }
  .trait-name { font-size: 12px; font-weight: 800; color: var(--text); text-transform: uppercase; letter-spacing: 0.04em; }
  .trait-slider { -webkit-appearance: none; appearance: none; width: 100%; height: 6px; border-radius: 999px; background: var(--border-strong); outline: none; cursor: pointer; }
  .trait-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 20px; height: 20px; border-radius: 50%; background: var(--accent); border: 2px solid var(--surface); box-shadow: 0 1px 3px rgba(0,0,0,0.4); cursor: pointer; }
  .trait-slider::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: var(--accent); border: 2px solid var(--surface); cursor: pointer; }
  .trait-mix { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 12px; }
  .trait-mix-item { display: flex; flex-direction: column; gap: 3px; }
  .trait-mix-lbl { font-size: 11px; font-weight: 700; color: var(--text-muted); }
  .trait-mix-bar { height: 5px; border-radius: 999px; background: var(--border); overflow: hidden; }
  .trait-mix-fill { display: block; height: 100%; background: var(--accent); border-radius: 999px; transition: width 0.15s ease; }
  .trait-preview { font-size: 13px; color: var(--text); line-height: 1.4; }
  .trait-preview-lbl { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: var(--accent); margin-right: 5px; }
  /* Custom-personality editor (replaces the trait sliders) */
  .custom-panel { margin-top: 12px; padding: 14px; border: 1px solid var(--border); border-radius: 14px; background: var(--surface-2); display: flex; flex-direction: column; gap: 10px; }
  .custom-row { display: flex; align-items: center; gap: 10px; }
  .custom-row > label { font-size: 12px; font-weight: 700; color: var(--text-muted); flex: 0 0 auto; }
  .custom-field-label { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: var(--accent); margin-top: 4px; }
  .custom-emoji-input { width: 52px; flex: 0 0 auto; text-align: center; font-size: 22px; padding: 7px 4px; border: 1px solid var(--border-strong); border-radius: 10px; background: var(--surface); color: var(--text); }
  .custom-text-input { flex: 1 1 auto; min-width: 0; font-size: 14px; padding: 9px 11px; border: 1px solid var(--border-strong); border-radius: 10px; background: var(--surface); color: var(--text); }
  .custom-text-input::placeholder { color: var(--text-muted); opacity: 0.7; }
  .custom-text-input:focus, .custom-emoji-input:focus { outline: none; border-color: var(--accent); }
  .custom-line-row { display: flex; align-items: center; gap: 8px; }
  .custom-line-del { flex: 0 0 auto; width: 40px; height: 40px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); font-size: 13px; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
  .custom-line-del:hover { color: var(--danger); border-color: var(--danger); }
  .custom-line-add { align-self: flex-start; font-size: 12px; font-weight: 700; color: var(--accent); background: none; border: 1px dashed var(--border-strong); border-radius: 9px; padding: 7px 12px; cursor: pointer; }
  .custom-base-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
  .custom-base-chip { font-size: 11px; font-weight: 700; padding: 8px 4px; border-radius: 9px; border: 1px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 3px; }
  .custom-base-chip.on { border-color: var(--accent); background: rgba(var(--accent-rgb),0.14); color: var(--accent); }
  /* Lively free-time toggle (Avatar tab) */
  .lively-row {
    width: 100%; display: flex; align-items: center; gap: 12px; text-align: left;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    padding: 14px; cursor: pointer; margin-top: 4px; touch-action: manipulation; font: inherit; color: var(--text);
  }
  .lively-row.on { border-color: rgba(56,189,248,0.5); background: rgba(56,189,248,0.08); }
  .lively-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
  .lively-row-title { font-weight: 800; font-size: 14px; }
  .lively-row-sub { color: var(--text-muted); font-size: 12px; line-height: 1.45; }
  .lively-switch {
    flex: 0 0 auto; width: 44px; height: 26px; border-radius: 999px;
    background: var(--surface-2); border: 1px solid var(--border-strong); position: relative; transition: background .18s, border-color .18s;
  }
  .lively-row.on .lively-switch { background: #38bdf8; border-color: #38bdf8; }
  .lively-knob {
    position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%;
    background: #fff; transition: transform .18s; box-shadow: 0 1px 3px rgba(0,0,0,0.4);
  }
  .lively-row.on .lively-knob { transform: translateX(18px); }
  /* Slim sway toggle on the face tab — a compact pill (smaller padding/type than lively-row),
     reusing the lively switch visuals. */
  .sway-pill {
    width: 100%; display: flex; align-items: center; gap: 10px; text-align: left;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    padding: 10px 12px; margin-top: 12px; cursor: pointer; touch-action: manipulation; font: inherit; color: var(--text);
  }
  .sway-pill.on { border-color: rgba(56,189,248,0.5); background: rgba(56,189,248,0.08); }
  .sway-pill-ic { flex: 0 0 auto; font-size: 20px; line-height: 1; display: flex; align-items: center; justify-content: center; }
  .sway-pill-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .sway-pill-title { font-weight: 800; font-size: 13px; }
  .sway-pill-sub { color: var(--text-muted); font-size: 11px; line-height: 1.4; }
  .sway-pill.on .lively-switch { background: #38bdf8; border-color: #38bdf8; }
  .sway-pill.on .lively-knob { transform: translateX(18px); }
  /* Pro-gating affordances (locked controls + inline upgrade links) */
  .self-avatar-opt.locked { opacity: 0.7; border-style: dashed; }
  .label-pro { font-size: 9px; font-weight: 800; letter-spacing: 0.04em; color: var(--accent-text); background: var(--accent); border-radius: 999px; padding: 2px 6px; vertical-align: middle; margin-left: 6px; }
  .link-btn { background: none; border: 0; padding: 0; font: inherit; font-weight: 800; color: var(--accent); cursor: pointer; text-decoration: underline; }
  .set-card { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 4px 14px; }
  /* Language picker: two segmented buttons inside a set-card. */
  .set-lang-row { display: flex; gap: 8px; padding: 10px 0; }
  .set-lang-btn { flex: 1 1 0; font-size: 13px; font-weight: 700; color: var(--text-muted); background: var(--surface-2);
    border: 1px solid var(--border); border-radius: 10px; padding: 9px 0; cursor: pointer; touch-action: manipulation; transition: background .15s, color .15s, border-color .15s; }
  .set-lang-btn.on { color: var(--accent-text); background: var(--accent); border-color: var(--accent); }
  .set-row { display: flex; justify-content: space-between; gap: 10px; padding: 11px 0; font-size: 14px; border-bottom: 1px solid var(--border); }
  .set-row:last-child { border-bottom: 0; }
  .set-v { color: var(--text-muted); display: inline-flex; align-items: center; gap: 5px; }
  /* Tappable action rows (Help): icon tile + title/sub + chevron, inside a set-card. */
  .set-action { display: flex; align-items: center; gap: 12px; width: 100%; padding: 11px 0; background: none; border: 0; border-bottom: 1px solid var(--border); font: inherit; color: var(--text); text-align: left; cursor: pointer; touch-action: manipulation; }
  .set-action:last-child { border-bottom: 0; }
  .set-action:active { opacity: 0.6; }
  .set-action-ico { flex-shrink: 0; width: 34px; height: 34px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; font-size: 15px; }
  .set-action-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .set-action-title { font-size: 14px; font-weight: 700; }
  .set-action-sub { font-size: 12px; color: var(--text-muted); line-height: 1.35; }
  .set-action-chev { flex-shrink: 0; color: var(--text-dim); font-size: 18px; font-weight: 700; }
  /* Editable account name (Account → Signed in as). */
  .set-name-btn { display: inline-flex; align-items: center; gap: 6px; background: none; border: 0; color: var(--accent); font: inherit; font-weight: 700; cursor: pointer; padding: 0; }
  .set-name-pencil { font-size: 11px; opacity: 0.7; }
  .set-name-edit { display: inline-flex; align-items: center; gap: 4px; }
  .set-name-input { width: 130px; max-width: 46vw; background: var(--surface-2); border: 1px solid var(--accent); border-radius: 8px; color: var(--text); font: inherit; padding: 4px 8px; outline: none; }
  .set-name-ok, .set-name-cancel { background: none; border: 0; font: inherit; font-size: 15px; line-height: 1; cursor: pointer; padding: 3px 4px; }
  .set-name-ok { color: var(--accent); }
  .set-name-cancel { color: var(--text-dim); }
  .set-msg { font-size: 12px; font-weight: 600; margin: 8px 2px 0; }
  .set-msg.ok { color: var(--accent); }
  .set-msg.err { color: var(--danger); }
  .reset-confirm { border: 1px solid rgba(248,113,113,0.5); background: rgba(248,113,113,0.06); border-radius: 14px; padding: 14px; }
  .reset-confirm-title { font-weight: 800; font-size: 15px; color: var(--danger); }
  .reset-confirm-sub { font-size: 12px; color: var(--text-muted); line-height: 1.5; margin: 6px 0 10px; }
  .reset-confirm-sub b { color: var(--text); letter-spacing: 0.06em; }
  .reset-confirm-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 12px; }
  /* Final "are you sure" bar — armed only after typing RESET + hitting erase. Stronger red. */
  .reset-final { margin-top: 14px; padding: 12px; border-radius: 12px;
    border: 1px solid var(--danger); background: rgba(248,113,113,0.12); animation: fadeIn .15s ease; }
  .reset-final-warn { font-size: 12.5px; font-weight: 700; color: var(--danger); line-height: 1.5; margin: 0; }

  /* --- Schedule: compact race header --- */
  .rh {
    display: flex; align-items: center; gap: 12px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 12px 14px;
  }
  .rh.behind { border-color: rgba(var(--you-rgb),0.4); background: rgba(var(--you-rgb),0.05); }
  .rh-face { font-size: 34px; line-height: 1; flex-shrink: 0; position: relative; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.5)) var(--aura-glow, ); }
  /* Race-header face reuses the hero face's soft drop-shadow (so an animated emoji's aura doesn't
     trace a hard square box like .rh-face's tight shadow did); just keep it from shrinking in the flex row. */
  /* hero-face is sized for the 64px main avatar (font-size:64). At the race header's 38px the tall
     64px line-box made placed stickers float around empty space instead of hugging the small face,
     so pin the box to the real avatar size and shrink-wrap it. */
  /* position:relative so placed stickers (av-acc.placed, absolute) anchor to THIS tight 38px face
     box — not a bigger ancestor (the whole .rh row), which drifted them off toward the bottom on the
     Progress/Schedule race header. Mirrors .hero-face / .rh-face, which both set it. */
  .rh-hero-face { flex-shrink: 0; font-size: 38px; display: inline-flex; align-items: center; justify-content: center; position: relative; }
  .rh-face-poke { background: none; border: 0; padding: 0; cursor: pointer; touch-action: manipulation; display: inline-flex; }
  .rh-face-poke:active { transform: scale(0.9); }
  .rh-face-poke.poking { animation: heroPoke 0.5s ease; }
  .rh-poke-again { color: var(--text-dim); font-size: 11px; font-weight: 700; margin-left: 4px; }
  .rh-rest-emo { display: inline-block; vertical-align: -2px; margin-right: 2px; }
  .rh-bars { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
  /* Period label so the race reads as one DAY's progress (or "This week"), not an
     ambiguous total — sits above the JEK/ME bars. */
  .rh-period { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 10px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 1px; }
  /* Day-percent pill, moved off the crowded day toolbar onto the TODAY card's header row. */
  .rh-pill { flex-shrink: 0; font-size: 11px; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: normal; text-transform: none; border-radius: 999px; padding: 2px 9px; background: var(--surface-2); color: var(--text); }
  .rh-pill.good { background: rgba(var(--accent-rgb),0.16); color: var(--accent); }
  .rh-pill.mid { background: rgba(var(--you-rgb),0.14); color: var(--you); }
  .rh-pill.bad { background: rgba(248,113,113,0.14); color: var(--danger); }
  .rh-row { display: flex; align-items: center; gap: 8px; }
  .rh-tag { width: 46px; flex-shrink: 0; font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .rh-tag.av { color: var(--accent); }
  .rh-tag.me { color: var(--text-dim); }
  .rh-track { position: relative; flex: 1; height: 8px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
  .rh-fill { height: 100%; border-radius: 999px; transition: width 0.5s ease; }
  .rh-fill.av { background: var(--accent); }
  .rh-fill.me { background: var(--you); }
  /* "Overcharge" — the part of your bar that has banked PAST the avatar. Sits on top of
     the orange ME fill (left = avatar's position, width = your surplus) and reads like a
     shield/overcharge in a game health bar. Vivid magenta — a SATURATED "filled" colour
     (white read as empty track; cyan blended with the green JEK bar; pink didn't suit).
     Fully rounded + a white left border, so the seam where your effort crosses the
     avatar's gets a soft rounded white "cap" (the shape the user preferred). */
  .rh-over { position: absolute; top: 0; height: 100%; border-radius: 999px;
    transform-origin: right center;
    background: linear-gradient(90deg, #a855f7, #8b5cf6);
    border-left: 2px solid rgba(255,255,255,0.95);
    box-shadow: inset 0 0 4px rgba(255,255,255,0.3);
    /* Reveal AFTER the orange has settled (0.4s delay), then grow from the RIGHT edge
       leftward — so the mint reads as the gauge's overflowing tip, not a separate bar.
       Anchored via `right` in JSX so live updates also extend right→left. */
    animation: rhOverIn 0.55s cubic-bezier(0.22,1,0.36,1) 0.4s both;
    transition: right 0.5s ease, width 0.5s ease; }
  @keyframes rhOverIn { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  .rh-val { width: 50px; flex-shrink: 0; text-align: right; font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums; }
  .rh-status { font-size: 11px; font-weight: 700; margin-top: 1px; }
  .rh.behind .rh-status { color: var(--you); }
  .rh:not(.behind) .rh-status { color: var(--accent); }
  .rh.ahead .rh-status { color: #a855f7; }

  /* --- Collapsible race header (Day view) --- */
  .race-wrap { position: relative; }
  /* Reserve room on the right so the control tab never overlaps the time values. */
  .race-wrap .rh { padding-right: 44px; }
  /* Progress-jump + collapse stacked as ONE matched tab hugging the right edge, vertically
     centred — reads as a single control group instead of two chips crowding the bar values. */
  .race-tools {
    position: absolute; top: 50%; right: 8px; transform: translateY(-50%); z-index: 2;
    display: flex; flex-direction: column; gap: 4px;
  }
  .race-hide, .race-prog {
    width: 26px; height: 22px; padding: 0; line-height: 1;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 7px;
    color: var(--text-dim); font-size: 11px; cursor: pointer; touch-action: manipulation;
  }
  .race-hide:hover, .race-prog:hover { color: var(--text); background: var(--surface); }
  .race-hide:active, .race-prog:active { transform: scale(0.92); }
  .race-reveal {
    display: flex; align-items: center; gap: 8px; width: 100%;
    background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
    padding: 7px 12px; color: var(--text-dim); font-size: 12px; font-weight: 700;
    cursor: pointer; touch-action: manipulation;
  }
  .race-reveal:active { transform: scale(0.99); }
  .race-reveal-face { font-size: 18px; line-height: 1; flex-shrink: 0; }
  .race-reveal-gap { margin-left: auto; color: var(--you); font-weight: 800; }
  .race-reveal-caret { margin-left: auto; color: var(--text-dim); font-size: 10px; }
  .race-reveal-gap + .race-reveal-caret { margin-left: 8px; }

  /* --- Two-lane timeline (left = you, right = avatar plan) --- */
  .tl2-caps {
    position: sticky; top: 0; z-index: 9; display: flex;
    background: var(--surface); border-bottom: 1px solid var(--border);
    padding: 6px 0 6px 46px; font-size: 10px; font-weight: 800;
    text-transform: uppercase; letter-spacing: 0.06em;
  }
  .tl2-cap { flex: 1; min-width: 0; text-align: center; display: flex; align-items: center; justify-content: center; gap: 8px; }
  .tl2-cap.me { color: var(--you); }
  /* Keep a long user name from shoving the ＋ button off-screen — the name ellipsis-truncates, the button stays. */
  .tl2-cap-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tl2-cap-add { flex-shrink: 0; }
  /* Legend: solid border = the committed PLAN (repeats), dashed = a one-off logged session. */
  .tl2-legend { display: flex; gap: 13px; align-items: center; padding: 4px 0 6px 46px; font-size: 10px; font-weight: 600; letter-spacing: .03em; color: var(--text-dim); }
  .tl2-legend-item { display: inline-flex; align-items: center; gap: 5px; }
  .tl2-legend-block { display: inline-block; width: 14px; height: 9px; border-radius: 3px; border-width: 1.5px; border-style: solid; }
  .tl2-legend-block.solid { border-color: rgba(var(--accent-rgb),0.7); background: rgba(var(--accent-rgb),0.10); }
  .tl2-legend-block.dashed { border-style: dashed; border-color: rgba(var(--you-rgb),0.7); background: rgba(var(--you-rgb),0.10); }
  .tl2-cap.av { color: var(--accent); }
  .tl2-cap-add {
    width: 19px; height: 19px; border-radius: 6px; flex-shrink: 0;
    background: rgba(var(--you-rgb),0.2); border: 1px solid rgba(var(--you-rgb),0.55); color: var(--you);
    font-size: 13px; font-weight: 800; line-height: 1; cursor: pointer; padding: 0; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center;
  }
  .tl2-cap-add:active { background: rgba(var(--you-rgb),0.35); }
  /* Lively on/off right where its fillers live — on the avatar lane cap, mirroring the ME ＋. */
  .tl2-cap-lively {
    width: 19px; height: 19px; border-radius: 6px; flex-shrink: 0;
    background: transparent; border: 1px solid var(--border); color: var(--text-dim);
    font-size: 12px; line-height: 1; cursor: pointer; padding: 0; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center; opacity: 0.55;
  }
  .tl2-cap-lively.on { background: rgba(var(--accent-rgb),0.2); border-color: rgba(var(--accent-rgb),0.55); color: var(--accent); opacity: 1; }
  .tl2-cap-lively:active { background: rgba(var(--accent-rgb),0.35); }
  /* Expand-to-full-page button, pinned to the right edge of the sticky ฉัน/JEK caps row. */
  .tl2-cap-expand {
    position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
    width: 22px; height: 22px; border-radius: 7px; flex-shrink: 0;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text-dim);
    cursor: pointer; padding: 0; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center;
  }
  .tl2-cap-expand:active { background: var(--surface); color: var(--text); }
  .tl2.me.free { border-style: dashed; }
  /* While dragging or selected, switch to a SOLID yellow outline so the highlight reads
     as a clean active state — the dashed "free session" look is for the idle pill only. */
  /* A logged session of a "for me" activity wears the blue for-me colour (not the amber
     ME colour) so for-me time reads consistently with its for-me blocks. */
  .tl2.me.hobby { border-color: rgba(56,189,248,0.55); background: rgba(56,189,248,0.12); }
  .tl2.me.hobby.sel { border-color: #38bdf8; background: rgba(56,189,248,0.20); }
  .tl2.me.hobby.dragging { border-color: #38bdf8; }
  .tl2.me.hobby .meseg-resize { background: linear-gradient(to top, rgba(56,189,248,0.5), transparent); }
  .tl2.me.hobby .meseg-resize::after { background: rgba(56,189,248,0.85); }
  /* Merged session pill: its grab area is a real <button>, so reset the chrome and
     swap the grab cursor for a pointer (it selects rather than drags). */
  .tl2.me.merged .meseg-grab { cursor: pointer; width: 100%; background: none; border: 0; color: inherit; font: inherit; text-align: left; }
  .meseg-count { font-size: 10px; font-weight: 700; color: var(--text-muted); margin-left: 5px; vertical-align: 1px; }
  .tl2-divider { position: absolute; left: 50%; top: 0; bottom: 0; width: 1px; background: var(--border); }
  .tl2 {
    position: absolute; border-radius: 10px; overflow: hidden; z-index: 2;
    display: flex; align-items: stretch; border: 1px solid;
  }
  .tl2.me {
    left: 46px; right: 52%; /* 2% gap before the avatar lane so the pop-out ⋯ button (overhangs ~8px right) doesn't spill onto the avatar block */
    background: rgba(var(--you-rgb),0.16); border-color: rgba(var(--you-rgb),0.55);
    display: block; min-height: 26px;
  }
  .tl2.me.dragging { box-shadow: 0 6px 18px rgba(0,0,0,0.45); border-color: var(--you); z-index: 8; opacity: 0.96; }
  /* Selected session: lifts above its neighbours + brightens so its controls read. */
  .tl2.me.sel { z-index: 10; overflow: visible; border-color: var(--you); background: rgba(var(--you-rgb),0.26); box-shadow: 0 4px 14px rgba(0,0,0,0.5); } /* overflow:visible so the pop-out ⋯ button can overhang the corner; z-10 > sticky caps (z-9) so its controls aren't hidden behind the header on top-row blocks */
  /* While commenting, let the editor pop out past the pill's clipped bounds. */
  .tl2.me.noting, .tl2.av.noting { overflow: visible; z-index: 13; }
  /* Unselected sessions are compact pills (name + time, no reserved control space). */
  .tl2.me:not(.sel) { min-height: 30px; }
  .tl2.me:not(.sel) .meseg-grab { padding-right: 8px; }
  /* Pills keep a SUBTLE resize grip (just the handle bar, no heavy gradient). */
  .tl2.me:not(.sel) .meseg-resize { height: 9px; background: none; }
  .meseg-grab {
    height: 100%; display: flex; align-items: center; gap: 7px; padding: 5px 8px 3px 8px;
    cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none;
  }
  /* Reserve the control-button clearance on the NAME line only (the buttons sit at
     the top-right), so the time line below keeps full width and shows the clock
     range in full instead of being clipped to "6:20–7:40…". */
  .tl2.me.sel .tl2-name { padding-right: 36px; } /* reserve room for the single ⋯ button */
  .meseg-grab:active { cursor: grabbing; }
  .meseg-info { min-width: 0; display: flex; flex-direction: column; }
  /* "has a comment" flag — a small accent chip so it clearly reads as tappable: click it to READ the
     comment directly (no need to select the whole block first). */
  .tl2-name .meseg-note-flag { display: inline-flex; align-items: center; margin-left: 5px; vertical-align: -2px;
    background: rgba(var(--accent-rgb),0.18); border: 0; padding: 2px 4px; border-radius: 6px; cursor: pointer; color: var(--accent); }
  .tl2-name .meseg-note-flag:hover, .tl2-name .meseg-note-flag:active { background: rgba(var(--accent-rgb),0.32); }
  .meseg-time { font-size: 10px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .meseg-btn {
    position: absolute; right: 4px; width: 18px; height: 18px; border-radius: 6px;
    background: rgba(11,18,32,0.4); border: 0; color: var(--text-muted);
    font-size: 12px; line-height: 1; cursor: pointer; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center; padding: 0;
  }
  .meseg-btn.note { top: 3px; right: 44px; font-size: 10px; }
  .meseg-btn.edit { top: 3px; right: 64px; font-size: 11px; }
  .tl2.me.free.sel .meseg-grab .tl2-name { padding-right: 36px; } /* single ⋯ menu button */
  .meseg-btn.note.has { background: rgba(var(--you-rgb),0.32); color: var(--you); }
  .meseg-btn.split { top: 3px; right: 24px; }
  .meseg-btn.del { top: 3px; right: 4px; }
  .meseg-btn:active { background: rgba(11,18,32,0.7); color: var(--text); }
  /* Single "⋯" trigger that REPLACES the cramped 18px corner cluster: one easy-to-tap
     button on a selected block that opens a roomy action menu (Edit / Comment / Split /
     Delete) as 40px rows — works regardless of how short the block is. */
  /* "Pop-out" corner trigger (user pref 2026-06-10, chose "เด้งมุมขวาบน"): the ⋯ floats OVER the
     block's top-right corner, overhanging OUTWARD so it never covers the title even on tiny blocks.
     Bigger + circular + drop-shadow so it reads as a floating button and is easy to tap. Requires the
     selected block to be overflow:visible (see .tl2.me.sel / .tl2.av.hobby.sel) so it isn't clipped. */
  .blk-more { position: absolute; top: -10px; right: -8px; z-index: 12; width: 28px; height: 28px;
    border-radius: 50%; background: var(--surface-2); border: 1px solid var(--border-strong);
    color: var(--text-muted); font-size: 15px; font-weight: 900; line-height: 1; cursor: pointer;
    box-shadow: 0 2px 8px rgba(0,0,0,0.45); touch-action: manipulation;
    display: inline-flex; align-items: center; justify-content: center; padding: 0;
    transition: background .14s ease, color .14s ease, border-color .14s ease, transform .1s ease; }
  .blk-more:hover { color: var(--text); border-color: var(--accent); }
  .blk-more:active { background: var(--surface); transform: scale(0.9); }
  /* Quick comment button on a selected block — sits just left of the ⋯, opens the note editor
     directly (no menu dive). '.has' tints it when a note already exists. */
  .blk-quick-note { position: absolute; top: -10px; right: 24px; z-index: 12; width: 28px; height: 28px;
    border-radius: 50%; background: var(--surface-2); border: 1px solid rgba(var(--accent-rgb),0.55);
    color: var(--accent); cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.45);
    display: inline-flex; align-items: center; justify-content: center; padding: 0; touch-action: manipulation;
    transition: color .14s ease, border-color .14s ease, transform .1s ease; }
  .blk-quick-note:hover { color: var(--accent); border-color: var(--accent); }
  .blk-quick-note:active { transform: scale(0.9); }
  .blk-quick-note.has { color: var(--accent); border-color: rgba(var(--accent-rgb),0.6); }
  /* Avatar (green) task block comment button. It's ALWAYS visible (avatar blocks have no select
     state), and the block is overflow:hidden except while editing — so it sits INSIDE the top-right
     corner (not a floating overhang, which got clipped). The goal badge drops to the bottom. */
  .tl2-av-note { position: absolute; top: 4px; right: 4px; z-index: 6; width: 22px; height: 19px;
    display: grid; place-items: center; padding: 0; border-radius: 7px; cursor: pointer; touch-action: manipulation;
    background: rgba(11,18,32,0.5); border: 1px solid rgba(var(--accent-rgb),0.4); color: var(--accent);
    transition: background .14s ease, border-color .14s ease, transform .1s ease; }
  .tl2-av-note:hover { border-color: var(--accent); }
  .tl2-av-note:active { transform: scale(0.9); }
  .tl2-av-note.has { background: rgba(var(--accent-rgb),0.22); border-color: rgba(var(--accent-rgb),0.7); }
  /* Keep the task name clear of the top-right comment button. */
  .tl2.av:not(.hobby) .tl2-name { padding-right: 26px; }
  /* For-me toolbar: ✎ edit / ⤲ split / × remove — Split & Remove replace the old 💬 and ⋯ slots. */
  .blk-quick-split { position: absolute; top: -10px; right: 56px; z-index: 12; width: 28px; height: 28px;
    border-radius: 50%; background: var(--surface-2); border: 1px solid var(--border-strong);
    color: var(--text-muted); font-size: 15px; line-height: 1; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.45);
    display: inline-flex; align-items: center; justify-content: center; padding: 0; touch-action: manipulation;
    transition: color .14s ease, border-color .14s ease, transform .1s ease; }
  .blk-quick-split:hover { color: var(--text); border-color: var(--accent); }
  .blk-quick-split:active { transform: scale(0.9); }
  .blk-quick-remove { position: absolute; top: -10px; right: -8px; z-index: 12; width: 28px; height: 28px;
    border-radius: 50%; background: var(--surface-2); border: 1px solid rgba(239,68,68,0.5);
    color: var(--danger,#ef4444); font-size: 17px; line-height: 1; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.45);
    display: inline-flex; align-items: center; justify-content: center; padding: 0; touch-action: manipulation;
    transition: color .14s ease, border-color .14s ease, transform .1s ease; }
  .blk-quick-remove:hover { color: #fff; background: var(--danger,#ef4444); border-color: var(--danger,#ef4444); }
  .blk-quick-remove:active { transform: scale(0.9); }
  /* Edit sits at right:24 (next to remove@-8) so a block with just ✎+× has them adjacent; split (for-me
     only) goes further out at right:56. */
  .blk-quick-edit { position: absolute; top: -10px; right: 24px; z-index: 12; width: 28px; height: 28px;
    border-radius: 50%; background: var(--surface-2); border: 1px solid var(--border-strong);
    color: var(--text-muted); font-size: 14px; line-height: 1; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.45);
    display: inline-flex; align-items: center; justify-content: center; padding: 0; touch-action: manipulation;
    transition: color .14s ease, border-color .14s ease, transform .1s ease; }
  .blk-quick-edit:hover { color: var(--text); border-color: var(--accent); }
  .blk-quick-edit:active { transform: scale(0.9); }
  /* Selected-block action bar: round buttons in one flex row above the block (edit · comment · split ·
     remove), auto-packed so there are never gaps. Replaces the old per-button absolute offsets + the
     square in-corner comment button — the comment is now a circle in this row, on BOTH task types. */
  .blk-quick-bar { position: absolute; top: -12px; right: 4px; z-index: 12; display: flex; gap: 5px; }
  .blk-quick { width: 28px; height: 28px; border-radius: 50%; background: var(--surface-2); border: 1px solid var(--border-strong);
    color: var(--text-muted); font-size: 14px; line-height: 1; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.45);
    display: inline-flex; align-items: center; justify-content: center; padding: 0; touch-action: manipulation;
    transition: color .14s ease, border-color .14s ease, transform .1s ease; }
  .blk-quick:hover { color: var(--text); border-color: var(--accent); }
  .blk-quick:active { transform: scale(0.9); }
  .blk-q-note.has { color: var(--accent); border-color: rgba(var(--accent-rgb),0.6); }
  .blk-q-rested { background: rgba(var(--accent-rgb),0.85); border-color: var(--accent); } /* task is currently rested */
  .blk-q-remove { color: var(--danger,#ef4444); border-color: rgba(239,68,68,0.5); font-size: 17px; }
  .blk-q-remove:hover { color: #fff; background: var(--danger,#ef4444); border-color: var(--danger,#ef4444); }
  /* right:-8px matches .blk-more's offset so the caret below lines up under the ⋯ trigger. */
  .blk-menu { position: absolute; top: 32px; right: -8px; z-index: 30; min-width: 170px;
    background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: 12px;
    box-shadow: 0 14px 34px rgba(0,0,0,0.55); padding: 6px; display: flex; flex-direction: column; gap: 2px;
    transform-origin: top right; animation: blkMenuIn .14s ease-out; }
  /* Caret ties the menu to the ⋯ trigger so it reads as "from this button", not a floating card.
     right:9px puts its center under the 28px ⋯ button (which sits at right:-8px). */
  .blk-menu::before { content: ''; position: absolute; top: -6px; right: 9px; width: 11px; height: 11px;
    background: var(--surface-2); border-left: 1px solid var(--border-strong); border-top: 1px solid var(--border-strong);
    transform: rotate(45deg); border-top-left-radius: 3px; }
  /* Flipped up: the ⋯ trigger sits at the block's TOP (top:-10px), so anchor the menu just
     ABOVE that top edge (not the block's bottom) — else on a tall block it floats far from the
     button. calc(100% + 24px) keeps a 14px gap above the trigger for the down-pointing caret. */
  .blk-menu.up { top: auto; bottom: calc(100% + 24px); transform-origin: bottom right; }
  .blk-menu.up::before { top: auto; bottom: -6px; border-left: 0; border-top: 0;
    border-right: 1px solid var(--border-strong); border-bottom: 1px solid var(--border-strong);
    border-top-left-radius: 0; border-bottom-right-radius: 3px; }
  @keyframes blkMenuIn { from { opacity: 0; transform: scale(0.94) translateY(-4px); } to { opacity: 1; transform: scale(1) translateY(0); } }
  .blk-menu-item { display: flex; align-items: center; gap: 11px; width: 100%; min-height: 40px; padding: 0 10px;
    background: none; border: 0; border-radius: 9px; color: var(--text); font: inherit; font-size: 13px;
    font-weight: 600; text-align: left; cursor: pointer; touch-action: manipulation;
    transition: background .12s ease, color .12s ease; }
  .blk-menu-item:hover { background: rgba(var(--accent-rgb), 0.14); color: var(--accent); }
  .blk-menu-item:active { background: rgba(var(--accent-rgb), 0.22); }
  .blk-menu-item.danger { color: var(--danger); }
  .blk-menu-item.danger:hover, .blk-menu-item.danger:active { background: rgba(248,113,113,0.15); color: var(--danger); }
  .blk-menu-ico { width: 26px; height: 26px; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
    font-size: 14px; border-radius: 7px; background: rgba(255,255,255,0.05); color: inherit; }
  /* Inline comment editor — pops below the session pill. */
  .meseg-note-pop {
    position: absolute; top: 100%; left: 0; right: 0; margin-top: 5px; z-index: 14;
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: 12px;
    padding: 8px; box-shadow: 0 8px 22px rgba(0,0,0,0.55); cursor: default; overflow: visible;
    /* Stay comfortably wide even when opened from a narrow/overlap block (block is thin, comment shouldn't be). */
    min-width: 210px; max-width: calc(100vw - 24px);
  }
  /* Flipped: open ABOVE the block (block sits near the bottom of the timeline). */
  .meseg-note-pop.up { top: auto; bottom: 100%; margin-top: 0; margin-bottom: 5px; }
  /* Speech-bubble tail pointing at the task the comment belongs to (flips with the popup). Two triangles:
     the ::before is the border edge, the ::after is the card fill on top of it. */
  .meseg-note-pop::before, .meseg-note-pop::after { content: ''; position: absolute; left: 22px; width: 0; height: 0; }
  .meseg-note-pop::before { margin-left: -8px; border: 8px solid transparent; }
  .meseg-note-pop::after { margin-left: -7px; border: 7px solid transparent; }
  .meseg-note-pop:not(.up)::before { top: -16px; border-bottom-color: var(--border-strong); }
  .meseg-note-pop:not(.up)::after { top: -14px; border-bottom-color: var(--surface); }
  .meseg-note-pop.up::before { bottom: -16px; border-top-color: var(--border-strong); }
  .meseg-note-pop.up::after { bottom: -14px; border-top-color: var(--surface); }
  /* Read mode: just the comment text + a small ✎ to edit (tap the 💬 flag to open). */
  .meseg-note-pop.read { display: flex; align-items: flex-start; gap: 8px; }
  .meseg-note-text { flex: 1; min-width: 0; font-size: 12.5px; line-height: 1.45; color: var(--text); white-space: pre-wrap; word-break: break-word; padding: 3px 1px; }
  .meseg-note-edit { flex: 0 0 auto; width: 26px; height: 26px; border-radius: 8px; background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted); font-size: 13px; cursor: pointer; display: flex; align-items: center; justify-content: center; }
  .meseg-note-edit:hover { color: var(--accent); border-color: var(--accent); }
  /* Comment bar: the text sits left as an editable field (borderless — reads like the comment itself),
     with a ✎ button on the right to commit. One popup = show + edit inline, no separate step. */
  .meseg-note-pop.edit { display: flex; align-items: center; gap: 7px; }
  .meseg-note-area {
    width: 100%; box-sizing: border-box; resize: none; border-radius: 8px;
    background: transparent; border: 1px solid transparent; color: var(--text);
    font: inherit; font-size: 13px; line-height: 1.45; padding: 6px 8px;
  }
  .meseg-note-pop.edit .meseg-note-area { flex: 1; min-width: 0; background: var(--surface-2); border-color: var(--border); }
  .meseg-note-area:focus { outline: none; border-color: rgba(var(--accent-rgb),0.5); }
  /* The ✎ commit button (image-47 style: rounded square, subtle until hover). */
  .meseg-note-done {
    flex: 0 0 auto; width: 40px; align-self: stretch; min-height: 36px; border-radius: 9px;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted);
    font-size: 16px; cursor: pointer; touch-action: manipulation;
    display: flex; align-items: center; justify-content: center;
  }
  .meseg-note-done:hover { color: var(--accent); border-color: var(--accent); background: rgba(var(--accent-rgb),0.1); }
  .meseg-resize {
    position: absolute; left: 0; right: 0; bottom: 0; height: 11px;
    cursor: ns-resize; touch-action: none;
    background: linear-gradient(to top, rgba(var(--you-rgb),0.5), transparent);
  }
  .meseg-resize::after {
    content: ''; position: absolute; left: 50%; bottom: 3px; width: 22px; height: 3px;
    border-radius: 999px; background: rgba(var(--you-rgb),0.85); transform: translateX(-50%);
  }
  .tl2.av {
    left: 50%; right: 6px;
    background: rgba(var(--accent-rgb),0.06); border-color: rgba(var(--accent-rgb),0.35);
  }
  .tl2.av.active { background: rgba(var(--accent-rgb),0.16); }
  .tl2.av.upcoming { opacity: 0.6; }
  /* "It's happening now" — a clear bright ring PLUS an outer glow so it's obviously the active task. */
  .tl2.av.live { box-shadow: 0 0 0 2px var(--accent), 0 0 14px rgba(var(--accent-rgb),0.45); }
  /* Rested block whose time is happening now — same time-is-now glow, in the lime accent. */
  .tl2.av.rested.rest-now { box-shadow: 0 0 0 2px rgba(var(--accent-rgb),0.9); }
  /* Rest-ticket: the avatar takes the break too — no race/log on this block. Kept in the
     lime accent (not a separate green) so it reads as one ticket colour; the 🎟️ box, 💤
     glyph, resting note + dimmed opacity still mark it as a rest. */
  /* Rested = calmer, but DON'T fade the whole block (that washed out the 💤 sticker).
     Mute just the text/time instead; the emoji + 🎟️ box keep full opacity. */
  .tl2.av.rested { background: rgba(var(--accent-rgb),0.12); border-color: rgba(var(--accent-rgb),0.45); }
  .tl2.av.rested .tl2-info { opacity: 0.78; }
  .tl2.av.rested .tl2-name { color: #bef264; }
  .tl2.av.rested .tl2-resize { background: linear-gradient(to top, rgba(var(--accent-rgb),0.5), transparent); }
  .tl2.av.rested .tl2-resize::after { background: rgba(var(--accent-rgb),0.9); }
  .tl2-rest-badge { font-size: 11px; line-height: 1; margin-left: -2px; }
  .tl2-rest-note { color: #bef264 !important; font-weight: 600; }
  /* "Just for me" block (type=hobby): yours to do, never raced. It lives in the ME
     lane (LEFT half), not the avatar's — so override the avatar lane's left/right. */
  /* "For me" blocks wear the same QUIET teal treatment as the free-time fillers
     (muted bg/border, italic light-blue name, dim time, soft glow) instead of the
     old loud bright-bordered card — mirror .tl2.av.lively below. */
  /* z-index 3 keeps a for-me block painting ABOVE ME sessions (z-index 2), which are
     rendered later in the DOM — so when they overlap (mid-drag, or a packing edge case)
     the for-me box can never be hidden behind them and vanish. */
  .tl2.av.hobby { left: 46px; right: 51%; z-index: 3; border-color: rgba(56,189,248,0.55); background: rgba(56,189,248,0.16); }
  .tl2.av.hobby.active { background: rgba(56,189,248,0.22); }
  .tl2.av.hobby.live { box-shadow: 0 0 0 2px #38bdf8, 0 0 14px rgba(56,189,248,0.45); }
  .tl2.av.hobby.dragging { border-color: #38bdf8; }
  /* Tapped/selected for-me block: brighten + lift so it reads as active and its
     control buttons stand out (mirrors a selected ME session). */
  /* Selected = clearly the active task: a bright border + a glow ring so it's instantly recognizable. */
  .tl2.av.hobby.sel { border-color: #38bdf8; background: rgba(56,189,248,0.22); box-shadow: 0 0 0 3px rgba(56,189,248,0.32), 0 6px 16px rgba(0,0,0,0.45); z-index: 10; overflow: visible; } /* overflow:visible so the pop-out buttons overhang the corner; z-10 > sticky caps (z-9) */
  /* Avatar (green) block selected — same lift/reveal as the for-me select, in the accent colour, so the
     floating ✎/× buttons can overhang and the block reads as active. */
  .tl2.av:not(.hobby).sel { border-color: var(--accent); background: rgba(var(--accent-rgb),0.22); box-shadow: 0 0 0 3px rgba(var(--accent-rgb),0.32), 0 6px 16px rgba(0,0,0,0.45); z-index: 10; overflow: visible; }
  /* The name is a tap-to-edit target (full blocks) — hint it. */
  .tl2-name-edit { cursor: pointer; }
  .tl2.av.hobby .tl2-name { color: var(--text); font-style: normal; font-weight: 700; white-space: nowrap; display: block; -webkit-line-clamp: none; }
  .tl2.av.hobby .tl2-time { color: var(--text-muted); white-space: nowrap; }
  .tl2.av.hobby .tl2-dot:not(.rested) { display: none; }
  .tl2.av.hobby .tl2-resize { background: linear-gradient(to top, rgba(56,189,248,0.4), transparent); }
  .tl2.av.hobby .tl2-resize::after { background: rgba(56,189,248,0.8); }
  /* Unselected for-me block: drop the wide blue gradient fill, but KEEP the small
     centered grip handle (like the task box) so it still reads as resizable. */
  .tl2.av.hobby:not(.sel) .tl2-resize { background: none; }
  /* Checkbox column + goal pill: recolor the green accents to the hobby teal too. */
  .tl2.av.hobby .tl2-box { color: #38bdf8; border-right-color: rgba(56,189,248,0.3); }
  .tl2.av.hobby.done .tl2-box { background: #38bdf8; color: #0b1220; }
  /* Rest-ticket on a hobby: give the 🎟️ a blue chip to match the hobby teal. */
  .tl2.av.hobby.rested .tl2-box { background: rgba(56,189,248,0.85); color: #0b1220; }
  .tl2.av.hobby .tl2-goal-btn { color: #38bdf8; border-color: rgba(56,189,248,0.45); }
  .tl2.av.hobby .tl2-goal-btn.hit { background: #38bdf8; border-color: #38bdf8; color: #0b1220; }
  .tl2-hobby-tag { color: #7dd3fc; }
  /* Overlapping "for me" block squished into a side-by-side column: the 66px button
     clearance + side-by-side emoji ate the whole narrow width, leaving just the emoji.
     Reclaim the width and stack emoji-over-name so you can still read what it is. */
  /* Packed/narrow blocks (2+ overlapping in a thin column) are too skinny to read a name — show JUST the
     emoji, centred. Tap the block → it expands to full width and reveals the name/time/buttons. Same for
     avatar + for-me. */
  /* Packed/narrow block = emoji + start-time only, CENTERED vertically in the block (so it reads as one
     tidy label in the middle, not floating at a corner). Tap the block → it expands to full info. */
  .tl2.av.narrow .tl2-info, .tl2.av.hobby.narrow .tl2-info, .tl2.me.narrow .meseg-info { display: none; }
  .tl2.av.narrow .tl2-goal-btn, .tl2.av.hobby.narrow .tl2-goal-btn { display: none; }
  /* Keep the ✓ done toggle on collapsed blocks (checking is the main action) — as a small round
     checkbox in the top-left corner instead of the full left rail. */
  .tl2.av.narrow .tl2-box { position: absolute; top: 4px; left: 4px; width: 17px; height: 17px; min-width: 0; padding: 0;
    align-self: auto; border: 1.5px solid rgba(var(--accent-rgb),0.55); border-radius: 50%; background: var(--surface);
    display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; z-index: 6; }
  .tl2.av.narrow .tl2-box .tl2-box-mark { display: none; } /* empty circle = unchecked */
  .tl2.av.narrow.done .tl2-box { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
  .tl2.av.narrow .tl2-box:disabled { opacity: 0.4; }
  .tl2.av.hobby.narrow .tl2-dot { display: none; }
  /* ME free/logged session (dashed) collapses the same way — its dashed border stays as the identity. */
  /* Row-wrap so the emoji + 💬 marker sit together on the top line and the time wraps to the line below. */
  .tl2.av.narrow .tl2-main, .tl2.av.hobby.narrow .tl2-main, .tl2.me.narrow .meseg-grab {
    flex-flow: row wrap; align-items: center; justify-content: center; align-content: center; padding: 2px; gap: 1px 4px; }
  .tl2.av.narrow .tl2-face, .tl2.av.hobby.narrow .tl2-face { font-size: 19px; }
  .tl2-minitime { display: none; }
  .tl2.narrow .tl2-minitime { display: block; flex-basis: 100%; font-size: 9px; font-weight: 700; line-height: 1.2; color: var(--text-muted); font-variant-numeric: tabular-nums; text-align: center; white-space: normal; }
  /* "has a comment" marker, shown only on collapsed/narrow blocks (the full 💬 flag rides with the name,
     which narrow hides) — inline right next to the emoji, same size as the full flag. */
  .tl2-narrow-note { display: none; background: none; border: 0; padding: 1px 2px; cursor: pointer; color: var(--accent); }
  .tl2.narrow .tl2-narrow-note { display: inline-flex; align-items: center; z-index: 6; }
  .tl2.narrow .tl2-narrow-note:active { opacity: 0.6; }
  /* Lively free-time fillers: decorative, muted, and click-through (pointer-events
     none) so you can still drag-create a real block over them. */
  .tl2.av.lively {
    pointer-events: none; z-index: 1;
    background: rgba(56,189,248,0.06); border-color: rgba(56,189,248,0.28);
  }
  .tl2.av.lively.live { box-shadow: 0 0 0 1.5px #38bdf8; }
  .tl2.av.lively .tl2-name { color: #9ad8f5; font-style: italic; font-weight: 600; }
  .tl2.av.lively .tl2-time { color: var(--text-dim); }
  .lively-main { cursor: default; }
  /* Little leading dot before a free-time filler (matches the hobby teal). */
  .tl2-fill-dot { flex: 0 0 auto; width: 4px; height: 4px; border-radius: 50%; background: #38bdf8; }
  /* Avatar task block's leading dot — looks like the lively fill-dot but doubles as the
     done toggle. Small visual dot via ::before, padded transparent hit area for the tap. */
  .tl2-dot { flex: 0 0 auto; width: 16px; height: 16px; margin: -4px -3px -4px -2px; border: 0;
    background: transparent; border-radius: 50%; cursor: pointer; touch-action: manipulation;
    display: inline-flex; align-items: center; justify-content: center; font-size: 11px; line-height: 1; padding: 0; }
  .tl2-dot::before { content: ''; width: 7px; height: 7px; border-radius: 50%; box-sizing: border-box;
    border: 1.5px solid var(--accent); background: transparent; }
  .tl2-dot.done::before { background: var(--accent); }
  .tl2.av.upcoming .tl2-dot::before { opacity: 0.5; }
  .tl2-dot.rested::before { display: none; } /* show the 🎟️ glyph instead */
  /* Decorative for-me dot: a FULL (filled) teal circle, not a hollow ring. */
  .tl2.av.hobby .tl2-dot::before { border-color: #38bdf8; background: #38bdf8; }
  .tl2.av.hobby .tl2-dot.done::before { background: #38bdf8; }
  /* "Just for me" hobby blocks: the dot is decorative only (not a done toggle), so
     it's smaller and shows no clickable affordance. */
  .tl2.av.hobby .tl2-dot { cursor: default; }
  .tl2.av.hobby .tl2-dot::before { width: 5px; height: 5px; }
  .tl2.av.dragging { box-shadow: 0 6px 18px rgba(0,0,0,0.45); border-color: var(--accent); z-index: 8; opacity: 0.96; }
  /* Invisible top grip: drag the block's top edge to move its start. No fill/handle (kept clean). */
  .tl2-resize-top { position: absolute; left: 0; right: 0; top: 0; height: 11px; z-index: 4; cursor: ns-resize; touch-action: none; }
  .tl2-resize {
    position: absolute; left: 0; right: 0; bottom: 0; height: 11px; z-index: 4;
    cursor: ns-resize; touch-action: none;
    /* Round the bottom corners to match the block's 10px radius — otherwise, when a selected/placed
       block turns overflow:visible, the handle's square bottom corners poke past the rounded frame. */
    border-radius: 0 0 9px 9px;
    background: linear-gradient(to top, rgba(var(--accent-rgb),0.5), transparent);
  }
  .tl2-resize::after {
    content: ''; position: absolute; left: 50%; bottom: 3px; width: 22px; height: 3px;
    border-radius: 999px; background: rgba(var(--accent-rgb),0.85); transform: translateX(-50%);
  }
  .tl2-box {
    flex-shrink: 0; width: 30px; align-self: stretch; background: transparent; border: 0;
    border-right: 1px solid rgba(var(--accent-rgb),0.25); color: var(--accent);
    display: flex; align-items: center; justify-content: center;
    font-size: 15px; font-weight: 800; cursor: pointer; touch-action: manipulation;
    /* Round the left corners to match the block, so the done-fill rail doesn't poke a square corner past
       the block's rounded corner when a selected block turns overflow:visible. */
    border-radius: 9px 0 0 9px;
  }
  .tl2-box:disabled { cursor: default; }
  /* Unchecked indicator — a small outline circle (the old leading dot), no rail fill, so a
     not-yet-done task reads as an empty checkbox just like before you mark it. */
  .tl2-box-mark { width: 7px; height: 7px; border-radius: 50%; box-sizing: border-box;
    border: 1.5px solid var(--accent); }
  .tl2.av.upcoming .tl2-box-mark { opacity: 0.5; }
  .tl2-box:disabled .tl2-box-mark { border-color: var(--text-dim); }
  /* JEK finished it, you haven't checked it — show your committed-self's FACE on a
     transparent rail (no ✓, no lime fill — both are reserved for YOUR check-off), so
     "my committed self did it" can never be mistaken for "I did it". */
  .tl2-box.jekdone { background: transparent; }
  .tl2-box-jek { display: flex; align-items: center; justify-content: center; opacity: 0.7; filter: grayscale(0.25); }
  /* Checked: the rail fills solid lime with a ✓ (+ a divider line vs the body). */
  .tl2.av.done .tl2-box { background: var(--accent); color: #0b1220; border-right: 1px solid rgba(var(--accent-rgb),0.25); }
  /* A rested (ticketed) block is excused — never show the green "done" fill on its
     ticket box, even if it had a logged session. Keep every rested block identical
     (neutral box on the blue rest theme), not green-vs-transparent. */
  /* Rested block: fill the 🎟️ column with the solid lime accent so the ticket sits on a lime chip. */
  .tl2.av.rested .tl2-box { background: rgba(var(--accent-rgb),0.9); color: #0b1220; border-right: 1px solid rgba(var(--accent-rgb),0.5); }
  /* A per-task ticket can be cancelled by tapping its 🎟️ box — show it's clickable. */
  .tl2-box.unrestable { cursor: pointer; }
  .tl2-box.unrestable:hover { background: rgba(var(--accent-rgb),1); }
  .tl2-box.unrestable:active { background: rgba(132,204,22,1); }
  .tl2-body { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; }
  /* flex:1 so the button fills the WHOLE block height — the entire box is draggable to move, not just
     the text line. Top/bottom resize grips (z-4, absolute) still sit above it and win at the edges. */
  .tl2-main {
    flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 7px;
    background: transparent; border: 0; color: var(--text); text-align: left;
    font: inherit; cursor: grab; padding: 4px 7px; touch-action: none;
    user-select: none; -webkit-user-select: none;
  }
  .tl2-main:active { cursor: grabbing; }
  /* Goal-logger: a corner pill on the avatar box showing live % done; tap to open
     the −/value/＋ logger in a popover (keeps the box itself compact). */
  .tl2-goal-btn {
    position: absolute; top: 3px; right: 3px; z-index: 5; height: 18px; padding: 0 7px;
    border-radius: 999px; background: rgba(11,18,32,0.5); border: 1px solid rgba(var(--accent-rgb),0.4);
    color: var(--accent); font-size: 10px; font-weight: 800; line-height: 1; cursor: pointer;
    font-variant-numeric: tabular-nums; touch-action: manipulation;
    display: flex; align-items: center;
  }
  /* Goal-hit pill sits on the lime-tinted avatar block, so a solid lime fill blended in.
     A dark outline + soft shadow lifts it off the green card while keeping the win colour. */
  .tl2-goal-btn.hit { background: var(--accent); border-color: #0b1220; color: #0b1220; box-shadow: 0 1px 5px rgba(0,0,0,0.5); }
  /* Quick controls on a "Just for me" block (mirror the ME-session buttons). */
  .tl2-hbtns { position: absolute; top: 3px; right: 3px; z-index: 6; display: flex; gap: 3px; }
  /* Reserve the button clearance on the NAME line only (the 4 controls sit top-right and
     only appear when selected), so the time line keeps full width — like the yellow box. */
  .tl2.av.hobby.sel .tl2-name { padding-right: 36px; } /* single ⋯ menu button */
  .tl2-hbtn { width: 18px; height: 18px; border-radius: 6px; background: rgba(11,18,32,0.55);
    border: 0; color: var(--text-muted); font-size: 12px; line-height: 1; cursor: pointer;
    touch-action: manipulation; display: flex; align-items: center; justify-content: center; padding: 0; }
  .tl2-hbtn:hover { color: var(--text); background: rgba(11,18,32,0.82); }
  .tl2-hbtn.has { background: rgba(56,189,248,0.32); color: #7dd3fc; }
  /* On for-me blocks the goal pill drops to the bottom so it clears the buttons. */
  .tl2.av.hobby .tl2-goal-btn { top: auto; bottom: 13px; }
  /* Same on the avatar task block: the top-right corner now holds the 💬 comment button,
     so the goal pill moves to the bottom-right (clearing both the button and the resize grip). */
  .tl2.av:not(.hobby) .tl2-goal-btn { top: auto; bottom: 13px; }
  .tl2.av.logopen { overflow: visible; z-index: 10; }
  /* Keep the task name clear of the corner % pill. */
  .tl2-goal-btn + .tl2-body .tl2-main { padding-right: 46px; }
  .tl2-goal-pop {
    position: absolute; top: 100%; right: 0; margin-top: 5px; z-index: 16;
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: 10px;
    padding: 8px 9px; box-shadow: 0 8px 22px rgba(0,0,0,0.55); cursor: default; white-space: nowrap;
  }
  /* speech-bubble tail pointing up at the avatar block */
  .tl2-goal-pop::before,
  .tl2-goal-pop::after {
    content: ''; position: absolute; bottom: 100%;
    width: 0; height: 0; border: 7px solid transparent; pointer-events: none;
  }
  .tl2-goal-pop::before { right: 17px; border-width: 8px; border-bottom-color: var(--border-strong); }
  .tl2-goal-pop::after  { right: 18px; border-bottom-color: var(--surface); }
  /* Flipped: open ABOVE the block (block sits near the bottom of the timeline). */
  .tl2-goal-pop.up { top: auto; bottom: 100%; margin-top: 0; margin-bottom: 5px; }
  .tl2-goal-pop.up::before, .tl2-goal-pop.up::after { bottom: auto; top: 100%; }
  .tl2-goal-pop.up::before { border-bottom-color: transparent; border-top-color: var(--border-strong); }
  .tl2-goal-pop.up::after  { border-bottom-color: transparent; border-top-color: var(--surface); }
  .tl2-goal-pop-head { font-size: 11px; font-weight: 700; color: var(--text-muted); margin-bottom: 6px; }
  .tl2-goal-pop .tl2-amount { padding: 0; flex-wrap: nowrap; }
  /* Cancel / Save footer — mirrors the comment box, in the avatar lane's lime. */
  .tl2-goal-actions { display: flex; justify-content: flex-end; gap: 6px; margin-top: 8px; }
  .tl2-goal-cancel, .tl2-goal-save {
    font-size: 11px; font-weight: 700; padding: 5px 12px; border-radius: 999px;
    cursor: pointer; touch-action: manipulation; border: 1px solid var(--border);
  }
  .tl2-goal-cancel { background: var(--surface-2); color: var(--text-muted); }
  .tl2-goal-save { background: var(--accent); border-color: var(--accent); color: #0b1220; }
  .tl2-goal-save:disabled { opacity: 0.5; cursor: default; }
  .tl2-amount {
    display: flex; align-items: center; gap: 5px; padding: 0 7px 5px;
    flex-wrap: wrap;
  }
  .tl2-amt-btn {
    flex-shrink: 0; width: 22px; height: 22px; border-radius: 7px;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--accent);
    font-size: 15px; font-weight: 800; line-height: 1; cursor: pointer; padding: 0;
    touch-action: manipulation;
  }
  .tl2-amt-btn:disabled { color: var(--text-dim); opacity: 0.5; cursor: default; }
  .tl2-amt-input {
    width: 42px; flex-shrink: 0; text-align: center; background: var(--bg);
    border: 1px solid var(--border); border-radius: 7px; color: var(--text);
    font: inherit; font-weight: 800; font-size: 12px; padding: 3px 2px;
    font-variant-numeric: tabular-nums; -moz-appearance: textfield;
  }
  .tl2-amt-input::-webkit-outer-spin-button, .tl2-amt-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .tl2-amt-input:disabled { opacity: 0.6; }
  .tl2-amt-meta { font-size: 10px; font-weight: 700; color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
  .tl2-amt-meta.hit { color: var(--accent); }
  .tl2-face { font-size: 15px; line-height: 1; flex-shrink: 0; display: flex; align-items: center; gap: 4px; }
  .tl2-action { display: block; }
  /* Poke the avatar while it's working a live job → it wiggles + reacts in-character. */
  .tl2-face.pokeable { cursor: pointer; touch-action: manipulation; border-radius: 8px; }
  .tl2-face.pokeable:active { transform: scale(0.92); }
  .tl2-face.poking { animation: tl2Poke 0.5s ease; }
  @keyframes tl2Poke {
    0% { transform: scale(1) rotate(0); }
    25% { transform: scale(1.22) rotate(-9deg); }
    55% { transform: scale(0.92) rotate(7deg); }
    80% { transform: scale(1.08) rotate(-4deg); }
    100% { transform: scale(1) rotate(0); }
  }
  /* The block clips its contents; while poking, let the reaction bubble pop out. */
  .tl2.av.poking { overflow: visible; z-index: 12; }
  .tl2-poke-bubble {
    position: absolute; left: 32px; bottom: calc(100% - 4px); z-index: 13;
    display: inline-flex; align-items: flex-start; gap: 5px; max-width: 220px;
    background: var(--surface); border: 1px solid var(--accent); border-radius: 12px;
    padding: 5px 9px; box-shadow: 0 8px 22px rgba(0,0,0,0.5);
    font-size: 12px; font-weight: 700; color: var(--text); white-space: normal;
    animation: tl2PokeBubble 0.22s ease both;
  }
  .tl2-poke-bubble::after {
    content: ''; position: absolute; left: 16px; top: 100%; width: 9px; height: 9px;
    background: var(--surface); border-right: 1px solid var(--accent); border-bottom: 1px solid var(--accent);
    transform: translateY(-5px) rotate(45deg);
  }
  .tl2-poke-emoji { display: block; flex-shrink: 0; }
  /* Wrap the line up to 2 lines (ellipsis on the 2nd) instead of cutting at one. */
  .tl2-poke-msg { min-width: 0; line-height: 1.3; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
  @keyframes tl2PokeBubble { from { opacity: 0; transform: translateY(5px) scale(0.9); } to { opacity: 1; transform: translateY(0) scale(1); } }
  @media (prefers-reduced-motion: reduce) { .tl2-face.poking { animation: none; } .tl2-poke-bubble { animation: none; } }
  .tl2-info { min-width: 0; display: flex; flex-direction: column; }
  .tl2-name { font-weight: 700; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tl2-sub { font-weight: 600; color: var(--accent); }
  .tl2.av.done .tl2-name, .tl2.me .tl2-name { text-decoration: none; }
  .tl2-time { font-size: 10px; color: var(--text-muted); font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Avatar-lane blocks (tasks / for-me / lively) are only half-width, so a long name or
     time used to truncate to "talking…" / "21:25–23:…". Let them WRAP into the block's
     vertical space instead (name clamped to 2 lines; time flows onto a 2nd line). */
  .tl2.av .tl2-name { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  .tl2.av .tl2-time { white-space: normal; }
  .tl2-check { flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%; background: var(--you); color: #0b1220; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center; }
  .meseg-emoji { flex-shrink: 0; width: 20px; height: 20px; display: block; }
  /* Now-line sits BEHIND the blocks (z-index 1, blocks are 2) so it never cuts across a
     block's title/time text. The gutter time-pill (z-index 9) stays the readable "now"
     marker; the line still shows in the gutter + empty time gaps. */
  .tl2-now { position: absolute; left: 44px; right: 6px; height: 2px; z-index: 1; pointer-events: none; background: var(--danger); transform: translateY(-50%); }
  .tl2-now-dot { position: absolute; left: 0; top: 50%; width: 9px; height: 9px; border-radius: 50%; background: var(--danger); transform: translate(-50%, -50%); }
  /* Drag-to-create preview box */
  .tl-dragsel {
    position: absolute; z-index: 6; border-radius: 10px; pointer-events: none; overflow: hidden;
    border: 2px dashed var(--accent); background: rgba(var(--accent-rgb),0.16);
    display: flex; align-items: flex-start; justify-content: center;
  }
  .tl-dragsel.me { left: 46px; right: 51%; border-color: var(--you); background: rgba(var(--you-rgb),0.16); }
  .tl-dragsel.av { left: 50%; right: 6px; }
  .tl-dragsel-time { font-size: 10px; font-weight: 800; color: var(--accent); padding: 2px 6px; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .tl-dragsel.me .tl-dragsel-time { color: var(--you); }

  /* --- Schedule editor --- */
  .editor-screen { display: flex; flex-direction: column; gap: 12px; }
  .editor-head { display: flex; align-items: center; justify-content: space-between; }
  .editor-title { font-weight: 800; font-size: 16px; }
  .day-tabs { display: flex; gap: 5px; }
  .day-tab {
    flex: 1; aspect-ratio: 1 / 1; min-width: 0;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text-dim);
    border-radius: 10px; font: inherit; font-weight: 700; font-size: 13px;
    cursor: pointer; touch-action: manipulation;
  }
  .day-tab.on { background: rgba(var(--accent-rgb),0.16); border-color: var(--accent); color: var(--accent); }
  .editor-dayname { font-size: 13px; font-weight: 800; color: var(--text); }
  .editor-empty { text-align: center; padding: 18px 8px; }
  .blockrow-list { display: flex; flex-direction: column; gap: 8px; }
  .blockrow {
    display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 12px; padding: 10px 14px; cursor: pointer; touch-action: manipulation;
    font: inherit; color: var(--text);
  }
  .blockrow-time {
    font-size: 12px; font-weight: 700; color: var(--text-muted);
    font-variant-numeric: tabular-nums; line-height: 1.25; flex-shrink: 0; width: 42px;
  }
  .blockrow-bar { width: 4px; align-self: stretch; border-radius: 999px; flex-shrink: 0; }
  .blockrow-name { flex: 1; font-weight: 600; font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .blockrow-days { font-size: 11px; color: var(--text-dim); font-weight: 700; }

  /* --- Block sheet (activity chips + time inputs) --- */
  .act-chip-row { display: flex; gap: 8px; flex-wrap: wrap; }
  .act-chip {
    display: inline-flex; align-items: center; gap: 7px;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    border-radius: 999px; padding: 8px 14px; font: inherit; font-weight: 600; font-size: 13px;
    cursor: pointer; touch-action: manipulation;
  }
  .act-chip.on { border-color: var(--accent); background: rgba(var(--accent-rgb),0.14); }
  .act-chip.add { color: var(--text-muted); }
  .act-chip-dot { width: 10px; height: 10px; border-radius: 50%; }
  .act-create { margin-top: 10px; display: flex; flex-direction: column; gap: 4px; }
  .time-row { display: flex; align-items: center; gap: 12px; }
  .time-input {
    flex: 1; background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    border-radius: 10px; padding: 12px; font: inherit; font-weight: 700; font-size: 18px;
    text-align: center; font-variant-numeric: tabular-nums; touch-action: manipulation;
  }
  .time-sep { color: var(--text-muted); font-weight: 700; }
  /* Custom themed time picker — wheel style (replaces native type=time dropdown). */
  .tp { position: relative; flex: 1; min-width: 0; }
  .tp-display {
    width: 100%; background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    border-radius: 10px; padding: 12px 8px; font: inherit; font-weight: 700; font-size: 18px;
    text-align: center; font-variant-numeric: tabular-nums; cursor: pointer; touch-action: manipulation;
  }
  .tp-display:active { background: var(--border); }
  .tp-display.open { border-color: var(--accent); position: relative; z-index: 92; }
  /* Dim the rest of the sheet so the wheel reads as a floating panel instead of
     overlapping the rows beneath it; the open field stays bright above the dim. */
  .tp-backdrop { position: fixed; inset: 0; z-index: 90; background: rgba(2,6,23,0.5); }
  .tp-pop {
    position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 91;
    padding: 10px; background: var(--surface); border: 1px solid var(--border-strong);
    border-radius: 14px; box-shadow: 0 18px 45px rgba(0,0,0,0.6);
  }
  /* Flip above the field when there isn't room below (avoids scrolling the sheet). */
  .tp-pop.up { top: auto; bottom: calc(100% + 6px); }
  .tp-wheels { position: relative; display: flex; align-items: stretch; gap: 2px; }
  /* The centered selection band that the chosen value snaps into. */
  .tp-band {
    position: absolute; left: 4px; right: 4px; top: 80px; height: 40px; z-index: 0; pointer-events: none;
    border-radius: 10px; background: rgba(var(--accent-rgb),0.13); border: 1px solid rgba(var(--accent-rgb),0.4);
  }
  .tp-colon { position: relative; z-index: 1; align-self: center; font-weight: 800; font-size: 18px; color: var(--text-muted); padding: 0 1px; }
  .tp-col {
    position: relative; z-index: 1; flex: 1; min-width: 0; height: 200px; overflow-y: auto;
    scroll-snap-type: y mandatory; scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 32%, #000 68%, transparent);
            mask-image: linear-gradient(to bottom, transparent, #000 32%, #000 68%, transparent);
  }
  .tp-col::-webkit-scrollbar { display: none; }
  .tp-col.tp-ap { flex: 0 0 52px; }
  .tp-pad { height: 80px; flex-shrink: 0; }
  .tp-opt {
    display: flex; align-items: center; justify-content: center; height: 40px; width: 100%;
    border: 0; background: transparent; color: var(--text-muted); scroll-snap-align: center;
    font: inherit; font-weight: 700; font-size: 17px; cursor: pointer; touch-action: manipulation;
    font-variant-numeric: tabular-nums;
  }
  .tp-opt.on { color: var(--text); font-weight: 800; }
  .tp-done {
    width: 100%; margin-top: 10px; border: 0; border-radius: 10px; background: var(--accent); color: var(--accent-text);
    font: inherit; font-weight: 800; font-size: 14px; padding: 10px; cursor: pointer; touch-action: manipulation;
  }
  .amount-row { display: flex; align-items: center; gap: 12px; }
  .amount-input {
    flex: 1; min-width: 0; background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    border-radius: 10px; padding: 12px; font: inherit; font-weight: 700; font-size: 18px;
    text-align: center; font-variant-numeric: tabular-nums; touch-action: manipulation; -moz-appearance: textfield;
  }
  .amount-input::-webkit-outer-spin-button, .amount-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .amount-unit { flex-shrink: 0; font-weight: 700; color: var(--text-muted); min-width: 48px; }

  /* Activity-list cards render as tappable buttons (reusing .act-card visuals). */
  .act-card { width: 100%; text-align: left; font: inherit; color: var(--text); cursor: pointer; touch-action: manipulation; }
  .act-card-edit { font-size: 12px; font-weight: 700; color: var(--text-dim); flex-shrink: 0; }
  /* The whole card already opens the editor, so the old "Edit ›" label was redundant chrome — now
     just a quiet chevron marking the row as tappable, freeing space + shortening the row. */
  .act-card-chevron { flex-shrink: 0; color: var(--text-muted); font-size: 22px; line-height: 1; font-weight: 300; padding-right: 2px; }
  /* Main-page manage mode: header toggle + per-card delete. */
  .act-list-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
  .act-head-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
  .act-edit-toggle { padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border); background: transparent; color: var(--text-dim); font-size: 12px; font-weight: 700; cursor: pointer; flex-shrink: 0; }
  .act-edit-toggle.on { background: rgba(var(--accent-rgb),0.16); border-color: var(--accent); color: var(--accent); }
  .act-delall { border-color: rgba(239,68,68,0.5); color: var(--danger,#ef4444); }
  .act-delall:active { background: rgba(239,68,68,0.14); }
  .act-card.editing { border-color: rgba(var(--danger-rgb,239,68,68),0.35); }
  .act-card-actions { flex-shrink: 0; display: inline-flex; align-items: center; gap: 6px; }
  .act-card-arch { flex-shrink: 0; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 15px; line-height: 1; background: var(--surface-2); border: 1px solid var(--border); cursor: pointer; }
  .act-card-arch:active { transform: scale(0.92); }
  .act-card-del { flex-shrink: 0; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800; line-height: 1; color: var(--danger,#ef4444); background: rgba(var(--danger-rgb,239,68,68),0.14); cursor: pointer; }
  .act-card-del:active { transform: scale(0.92); }
  /* Archived (diary) list under the active activities. */
  .act-archived { margin-top: 18px; display: flex; flex-direction: column; gap: 8px; }
  .act-archived-head { font-size: 11px; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-dim); padding: 0 2px; }
  .act-arch-row { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); opacity: 0.85; }
  .act-arch-emoji { flex-shrink: 0; display: inline-flex; width: 20px; height: 20px; align-items: center; justify-content: center; }
  .act-arch-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; font-weight: 600; color: var(--text-muted); }
  .act-arch-restore { flex-shrink: 0; padding: 5px 12px; border-radius: 999px; border: 1px solid var(--accent); background: transparent; color: var(--accent); font-size: 12px; font-weight: 800; cursor: pointer; }
  .act-arch-restore:active { transform: scale(0.94); }
  .act-arch-del { flex-shrink: 0; width: 28px; height: 28px; border-radius: 50%; border: 0; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; color: var(--danger,#ef4444); background: rgba(var(--danger-rgb,239,68,68),0.12); cursor: pointer; }

  /* --- History: daily accountability log --- */
  .hist-screen { display: flex; flex-direction: column; gap: 12px; }
  .friends-screen { display: flex; flex-direction: column; gap: 10px; }
  .lb-list { display: flex; flex-direction: column; gap: 7px; }
  .lb-row { display: flex; flex-direction: column; gap: 8px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 10px 13px; }
  .lb-row.me { border-color: rgba(var(--accent-rgb),0.5); background: rgba(var(--accent-rgb),0.06); }
  .lb-main { display: flex; align-items: center; gap: 10px; }
  .lb-bar { display: block; height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
  .lb-fill { display: block; height: 100%; border-radius: 999px; background: var(--accent); transition: width 0.5s ease; }
  .lb-fill.me { background: var(--you); }
  .lb-rank { width: 22px; text-align: center; font-weight: 800; color: var(--text-dim); font-variant-numeric: tabular-nums; flex: 0 0 auto; font-size: 14px; }
  .lb-emoji { font-size: 20px; line-height: 1; flex: 0 0 auto; position: relative; filter: var(--aura-glow, ); }
  .lb-name { flex: 1; min-width: 0; font-weight: 700; font-size: 14.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .lb-self-tag { margin-left: 6px; font-size: 10px; font-weight: 700; padding: 1px 6px; border-radius: 999px; background: rgba(132, 204, 22, 0.16); color: var(--accent); vertical-align: middle; }
  .lb-streak { font-size: 12px; font-weight: 700; color: var(--you); flex: 0 0 auto; font-variant-numeric: tabular-nums; }
  .lb-pct { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.05; color: var(--accent); flex: 0 0 auto; font-variant-numeric: tabular-nums; min-width: 46px; text-align: right; }
  .lb-pct b { font-size: 15px; font-weight: 800; }
  .lb-pct small { font-size: 9.5px; font-weight: 700; color: var(--text-muted); }
  .lb-fav { flex: 0 0 auto; background: none; border: 0; cursor: pointer; font-size: 16px; line-height: 1; padding: 2px 3px; margin: -2px -2px -2px 0; color: var(--text-muted); opacity: 0.5; transition: opacity .12s ease, transform .1s ease; }
  .lb-fav:hover { opacity: 0.85; }
  .lb-fav:active { transform: scale(0.85); }
  .lb-fav.on { color: #fbbf24; opacity: 1; }
  .lb-fav.capped { opacity: 0.2; cursor: default; }
  .lb-row.tap { cursor: pointer; touch-action: manipulation; }
  .lb-row.tap:active { border-color: var(--border-strong); }
  /* Friend League: Today / Week segmented toggle + week header */
  .lb-tabs { display: flex; gap: 6px; background: var(--surface-2); border-radius: 11px; padding: 4px; margin-bottom: 10px; }
  .lb-tab { flex: 1; border: none; background: transparent; color: var(--text-dim); font-weight: 700; font-size: 13.5px; padding: 8px 6px; border-radius: 8px; cursor: pointer; transition: background 0.15s, color 0.15s; }
  .lb-tab.on { background: var(--surface); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,0.18); }
  .lg-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }
  .lg-week { font-weight: 800; font-size: 14px; }
  .lg-left { font-size: 12px; font-weight: 700; color: var(--text-dim); }
  .lg-champ { display: flex; align-items: center; gap: 11px; margin-bottom: 12px; padding: 11px 14px; border-radius: 13px;
    background: linear-gradient(120deg, rgba(var(--you-rgb),0.16), rgba(var(--you-rgb),0.05)); border: 1px solid rgba(var(--you-rgb),0.45); }
  .lg-champ.me { background: linear-gradient(120deg, rgba(var(--you-rgb),0.26), rgba(var(--accent-rgb),0.10)); border-color: rgba(var(--you-rgb),0.7); }
  .lg-champ-em { font-size: 26px; line-height: 1; flex: 0 0 auto; position: relative; filter: var(--aura-glow, ); }
  .lg-champ-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .lg-champ-ttl { font-weight: 800; font-size: 14px; color: var(--you); }
  .lg-champ-sub { font-size: 12.5px; font-weight: 700; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Head-to-head race card */
  .fr-card { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
  .fr-back { align-self: flex-start; background: none; border: 0; color: var(--accent); font-weight: 700; font-size: 13px; cursor: pointer; padding: 0; touch-action: manipulation; }
  .fr-title { font-size: 18px; font-weight: 900; letter-spacing: -0.01em; }
  .fr-row { display: flex; align-items: center; gap: 9px; }
  .fr-em { font-size: 20px; line-height: 1; flex: 0 0 auto; position: relative; filter: var(--aura-glow, ); }
  .fr-nm { width: 54px; font-weight: 700; font-size: 13px; flex: 0 0 auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .fr-tr { flex: 1; height: 13px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
  .fr-fl { display: block; height: 100%; border-radius: 999px; transition: width 0.5s ease; }
  .fr-fl.me { background: var(--you); }
  .fr-fl.them { background: var(--accent); }
  .fr-st { font-size: 11px; font-weight: 700; color: var(--you); flex: 0 0 auto; font-variant-numeric: tabular-nums; }
  .fr-pc { font-size: 14px; font-weight: 800; flex: 0 0 auto; font-variant-numeric: tabular-nums; min-width: 40px; text-align: right; }
  .fr-verdict { text-align: center; font-weight: 800; font-size: 14px; color: var(--text-muted); padding-top: 4px; border-top: 1px solid var(--border); }
  .fr-verdict.good { color: var(--accent); }
  /* My profile hero on the Friends screen — big avatar + my live status. */
  .me-hero { display: flex; align-items: center; gap: 14px; background: var(--surface); border: 1px solid var(--border); border-radius: 18px; padding: 14px 16px; }
  /* Bare emoji exactly like the Main-page hero (.hero-face): no disc/ring, so the badge pins
     to the emoji's own corner and the aura is the same colored drop-shadow. */
  /* translateZ(0)+will-change put this on its own GPU layer like .hero-face, so the drop-shadow
     hugs the emoji's alpha SHAPE instead of shadowing the animated-webp's bounding BOX (the square). */
  .me-hero-face { flex: 0 0 auto; font-size: 46px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; position: relative; filter: drop-shadow(0 4px 10px rgba(0,0,0,0.5)) var(--aura-glow, ); will-change: transform; transform: translateZ(0); }
  .me-hero-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
  .me-hero-name { font-size: 17px; font-weight: 900; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .me-hero-stats { display: flex; gap: 16px; }
  .me-stat { display: flex; flex-direction: column; line-height: 1.15; font-size: 9.5px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: .04em; }
  .me-stat b { font-size: 15px; font-weight: 900; color: var(--text); letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
  .me-stat.you b { color: var(--you); }
  .me-code { align-self: flex-start; background: rgba(var(--accent-rgb), 0.10); border: 1px solid rgba(var(--accent-rgb), 0.30); color: var(--accent); font-size: 11px; font-weight: 800; padding: 4px 11px; border-radius: 999px; cursor: pointer; letter-spacing: .03em; touch-action: manipulation; }
  /* "How points work" explainer chip + collapsible note under the leaderboard tabs. */
  .fmla-chip { align-self: flex-start; margin-top: 8px; background: none; border: 0; padding: 2px 0; color: var(--text-muted); font-size: 11.5px; font-weight: 700; cursor: pointer; touch-action: manipulation; }
  .fmla-i { display: inline-block; color: var(--accent); font-weight: 900; }
  .fmla-note { margin: 6px 0 2px; padding: 10px 12px; background: rgba(var(--accent-rgb), 0.07); border: 1px solid rgba(var(--accent-rgb), 0.20); border-radius: 12px; font-size: 12px; line-height: 1.5; color: var(--text-muted); text-align: left; }
  /* Head-to-head "arena": two avatars facing off with a tug-of-war rope below. */
  .vs-arena { background: var(--surface); border: 1px solid var(--border); border-radius: 18px; padding: 16px 14px; display: flex; flex-direction: column; gap: 14px; }
  .vs-teamttl { text-align: center; font-size: 14px; font-weight: 900; letter-spacing: -0.01em; margin-top: -2px; }
  .vs-teamttl i { font-style: normal; font-weight: 700; color: var(--text-dim); margin: 0 4px; }
  .vs-stage { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 4px; }
  .vs-side { display: flex; flex-direction: column; align-items: center; gap: 5px; position: relative; padding: 12px 4px 8px; border-radius: 16px; transition: background .3s ease; }
  .vs-side.lead.me { background: rgba(var(--you-rgb), 0.10); }
  .vs-side.lead.them { background: rgba(var(--accent-rgb), 0.10); }
  .vs-crown { position: absolute; top: -9px; font-size: 17px; line-height: 1; filter: drop-shadow(0 1px 2px rgba(0,0,0,.35)); z-index: 2; }
  .vs-face { width: 74px; height: 74px; border-radius: 50%; background: var(--surface-2); display: inline-flex; align-items: center; justify-content: center; position: relative; line-height: 1; }
  /* Tight wrapper around the 50px face so badges/stickers anchor to the FACE, not the 74px circle.
     The Pro aura is the SAME shape-hugging var(--aura-glow) drop-shadow as .me-hero-face / the
     Avatar page — it lives HERE (no background on this wrapper, so it traces the avatar glyph and
     hugs the character, not the disc/ring). --aura-glow is set by the .aura-<id> class auraClass
     puts on .vs-face and inherits down to here. The ring (box-shadow on .vs-face) is a separate
     layer and is NOT touched by this filter, so it stays crisp with no glow.
     will-change/translateZ(0) is REQUIRED (same as .hero-face / .me-hero-face): it forces this
     wrapper onto its own raster layer so drop-shadow traces the avatar's real ALPHA (shape-hugging)
     instead of the <img>'s square box — without it the glow renders as a square behind the avatar. */
  .vs-face-in { position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; line-height: 1; filter: var(--aura-glow, ); will-change: transform; transform: translateZ(0); }
  /* Identity rings (user likes these): amber for YOU, accent-green for the avatar/JEK. Plain crisp
     rings, NO glow on the ring itself (2026-06-15 — glow lives behind the avatar, not on the ring). */
  .vs-side.me .vs-face { box-shadow: 0 0 0 3px var(--you); }
  .vs-side.them .vs-face { box-shadow: 0 0 0 3px var(--accent); }
  .vs-name { font-size: 13px; font-weight: 800; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: center; }
  .vs-team { font-size: 9px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); margin-top: -2px; }
  .vs-pct { font-size: 26px; font-weight: 900; line-height: 1; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
  .vs-pct i { font-size: 13px; font-weight: 800; font-style: normal; opacity: .55; margin-left: 1px; }
  .vs-side.me .vs-pct { color: var(--you); }
  .vs-side.them .vs-pct { color: var(--accent); }
  .vs-sub { font-size: 10.5px; font-weight: 700; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .vs-streak { font-size: 11px; font-weight: 700; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .vs-badge { width: 34px; height: 34px; border-radius: 50%; border: 1.5px solid var(--border); background: var(--surface-2); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 900; color: var(--text-dim); letter-spacing: .02em; }
  .vs-tug { position: relative; height: 16px; border-radius: 999px; background: var(--surface-2); overflow: hidden; display: flex; }
  .vs-tug-me { height: 100%; background: var(--you); transition: width .5s ease; }
  .vs-tug-them { height: 100%; background: var(--accent); transition: width .5s ease; }
  .vs-knot { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 8px; height: 8px; border-radius: 50%; background: var(--surface); box-shadow: 0 0 0 2px rgba(0,0,0,.18); transition: left .5s ease; }
  /* Friend's day — a read-only calendar that mirrors the Schedule day view's look
     (vertical hour axis + positioned blocks), but renders the FRIEND's synced blocks. */
  .frd-cal { position: relative; border: 1px solid var(--border); border-radius: 12px; background: var(--bg); overflow: hidden; }
  .frd-scroll { position: relative; max-height: 320px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
  .frd-canvas { position: relative; }
  .frd-hour { position: absolute; left: 0; right: 0; border-top: 1px solid var(--border); pointer-events: none; }
  .frd-hour-lbl { position: absolute; left: 6px; top: -7px; font-size: 9px; font-weight: 700; color: var(--text-dim); background: var(--bg); padding: 0 3px; font-variant-numeric: tabular-nums; }
  .frd-block { position: absolute; left: 46px; right: 8px; border-radius: 8px; padding: 3px 8px; overflow: hidden; display: flex; align-items: center; gap: 6px;
    background: rgba(var(--accent-rgb),0.12); border: 1px solid rgba(var(--accent-rgb),0.4); }
  .frd-block.done { background: rgba(var(--accent-rgb),0.26); }
  .frd-block-em { font-size: 14px; line-height: 1; flex: 0 0 auto; }
  .frd-block-nm { font-size: 11.5px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .frd-block-tm { margin-left: auto; font-size: 9.5px; font-weight: 700; color: var(--text-muted); flex: 0 0 auto; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .frd-check { font-size: 11px; color: var(--accent); flex: 0 0 auto; }

  /* This-week rollup card */
  .week-card {
    background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
    padding: 16px; display: flex; flex-direction: column; gap: 12px;
  }
  .week-card-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
  .week-card-label { text-transform: uppercase; letter-spacing: 0.1em; font-size: 11px; font-weight: 700; color: var(--text-dim); }
  .week-streak {
    font-size: 12px; font-weight: 800; color: var(--you);
    background: rgba(var(--you-rgb),0.12); border-radius: 999px; padding: 3px 10px; white-space: nowrap;
  }
  /* Weekly Recap (PRO) — the recurring "your week in review" hook at the top of Progress.
     A richer, accented version of WeekCard: headline + 3 stat cells (kept / time / best
     day) with a vs-last-week delta, and the top coach insight. */
  /* Neutral surface (no green accent) — the green highlight now belongs to the JEK review
     card above; doubling it up read as the two cards being the same thing. */
  .wrec-card { background: var(--surface);
    border: 1px solid var(--border); border-radius: 16px; padding: 16px; display: flex; flex-direction: column; gap: 13px; overflow: visible; }
  .wrec-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; position: relative; overflow: visible; }
  .wrec-label { text-transform: uppercase; letter-spacing: 0.1em; font-size: 11px; font-weight: 700; color: var(--text-dim); }
  .wrec-head { font-size: 19px; font-weight: 800; letter-spacing: -0.01em; line-height: 1.2; }
  .wrec-head b { color: var(--accent); }
  .wrec-stats { display: flex; gap: 8px; }
  .wrec-stat { flex: 1; min-width: 0; background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 8px; text-align: center; }
  .wrec-stat-num { font-size: 18px; font-weight: 800; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .wrec-stat-lbl { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); margin-top: 4px; }
  .wrec-delta { font-size: 11px; font-weight: 800; font-variant-numeric: tabular-nums; }
  .wrec-delta.up { color: var(--accent); }
  .wrec-delta.down { color: var(--you); }
  .wrec-insight { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; line-height: 1.45; color: var(--text); background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; animation: wrecInsightIn 0.45s cubic-bezier(0.22,1,0.36,1) both; }
  /* The icon is a real animated Noto emoji (via ActionEmoji), not a unicode glyph — it
     moves on its own like the animated emoji people use. Nudge it up a hair to sit on the
     text baseline. */
  .wrec-insight-ico { flex: 0 0 auto; margin-top: -1px; }
  @keyframes wrecInsightIn { from { opacity: 0; transform: translateY(6px) scale(0.98); } to { opacity: 1; transform: none; } }
  @media (prefers-reduced-motion: reduce) { .wrec-insight { animation: none; } }
  /* WeeklyRecapCard — coach pill (right of header) + popover bubble */
  .wrec-coach-pill { background: rgba(var(--accent-rgb),0.12); border: 1px solid rgba(var(--accent-rgb),0.5); border-radius: 999px; padding: 3px 10px; font-size: 12px; font-weight: 800; color: var(--accent); min-height: 28px; cursor: pointer; display: flex; align-items: center; gap: 5px; font-family: inherit; line-height: 1.2; white-space: nowrap; box-shadow: 0 0 0 0 rgba(var(--accent-rgb),0.5); }
  .wrec-coach-pill:active { opacity: 0.7; }
  .wrec-coach-pill-tail { font-size: 9px; opacity: 0.7; margin-left: 1px; }
  /* Pill anchor wrapper — makes the bubble position relative to the pill group */
  .wrec-coach-anchor { position: relative; z-index: 121; }
  /* Speech bubble popover — absolute, doesn't push layout */
  .wrec-coach-bubble { position: absolute; top: calc(100% + 8px); right: 0; z-index: 120;
    background: var(--surface-2); border: 1.5px solid rgba(var(--accent-rgb),0.55); border-radius: 13px;
    padding: 11px 13px; max-width: 250px; min-width: 200px; display: flex; flex-direction: column; gap: 8px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.34), 0 0 0 4px rgba(var(--accent-rgb),0.12); animation: coachBubblePop 0.32s cubic-bezier(0.34,1.56,0.64,1) both; }
  @keyframes coachBubblePop { 0% { opacity: 0; transform: translateY(-6px) scale(0.86); } 60% { transform: translateY(0) scale(1.03); } 100% { opacity: 1; transform: none; } }
  /* Triangle pointing up toward the pill */
  .wrec-coach-bubble::before { content: ''; position: absolute; top: -8px; right: 14px;
    border-left: 8px solid transparent; border-right: 8px solid transparent; border-bottom: 8px solid rgba(var(--accent-rgb),0.55); }
  .wrec-coach-bubble::after { content: ''; position: absolute; top: -6px; right: 15px;
    border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 7px solid var(--surface-2); }
  .wrec-coach-bubble-txt { font-size: 13.5px; font-weight: 600; line-height: 1.45; color: var(--text); display: flex; align-items: flex-start; gap: 8px; }
  .wrec-coach-bubble-ico { flex: 0 0 auto; }
  .wrec-coach-bubble-muted { font-size: 12px; color: var(--text-dim); font-style: italic; }
  .wrec-coach-bubble-cta { font-size: 11px; font-weight: 700; color: var(--text-dim); cursor: pointer; background: none; border: none; font-family: inherit; text-align: left; display: flex; align-items: center; gap: 5px; padding: 2px 0 0; width: 100%; }
  .wrec-coach-bubble-cta:active { opacity: 0.6; }
  /* Streak badge — now inline with the recap label on the left */
  .wrec-label-row { display: flex; align-items: center; gap: 8px; }
  .wrec-race-dashed { flex: 1; height: 6px; border: 1.5px dashed var(--you); border-radius: 3px; opacity: 0.5; }
  /* Achievements card — summary line + badge ladder (FREE). */
  .ach-card { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 16px; display: flex; flex-direction: column; gap: 14px; }
  .ach-summary { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .ach-stats { display: flex; gap: 8px; }
  .ach-stat { flex: 1; min-width: 0; background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 8px; text-align: center; }
  .ach-stat-num { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; line-height: 1.1; }
  .ach-stat.cur .ach-stat-num { color: var(--you); }
  .ach-stat-lbl { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); margin-top: 3px; }
  .ach-badges { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
  .ach-badge { display: flex; flex-direction: column; align-items: center; gap: 3px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 9px 4px; position: relative; }
  .ach-badge-emoji { font-size: 22px; line-height: 1; display: flex; align-items: center; justify-content: center; filter: grayscale(1) opacity(0.32); transition: filter 0.2s ease; }
  .ach-badge.on { border-color: rgba(var(--you-rgb),0.5); background: rgba(var(--you-rgb),0.08); }
  .ach-badge.on .ach-badge-emoji { filter: none; }
  .ach-badge-days { font-size: 10px; font-weight: 800; color: var(--text-dim); font-variant-numeric: tabular-nums; }
  .ach-badge.on .ach-badge-days { color: var(--you); }
  .ach-badge.next { border-color: var(--border-strong); border-style: dashed; }
  /* Earned badges are wearable: tappable buttons. The one you're wearing gets a check + ring. */
  button.ach-badge.equip { cursor: pointer; font: inherit; -webkit-appearance: none; appearance: none; }
  button.ach-badge.equip:active { transform: scale(0.95); }
  .ach-badge.worn { border-color: var(--you); background: rgba(var(--you-rgb),0.16); box-shadow: 0 0 0 1px var(--you) inset; }
  .ach-badge.worn::after { content: '✓'; position: absolute; top: 3px; right: 4px; font-size: 9px; font-weight: 900; color: var(--you); line-height: 1; }
  /* Milestone celebration modal + confetti */
  .cele-backdrop { position: fixed; inset: 0; z-index: 10300; display: flex; align-items: center; justify-content: center; padding: 24px; background: rgba(2,6,23,0.72); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); animation: cele-fade 0.2s ease both; overflow-y: auto; }
  .cele-card { position: relative; width: 100%; max-width: 320px; margin: auto; background: var(--surface); border: 1px solid var(--border-strong); border-radius: 22px; padding: 30px 24px 24px; text-align: center; box-shadow: 0 20px 60px rgba(0,0,0,0.55); overflow: hidden; animation: cele-rise 0.32s cubic-bezier(.2,1,.3,1) both; }
  .cele-emoji { font-size: 64px; line-height: 1; animation: cele-pop 0.5s cubic-bezier(.2,1.5,.4,1) 0.08s both; }
  .cele-title { font-size: 25px; font-weight: 900; letter-spacing: -0.02em; margin-top: 12px; color: var(--you); }
  .cele-sub { font-size: 14px; color: var(--text-muted); margin-top: 9px; line-height: 1.55; }
  /* Clean neutral chip — the old amber-on-dark tint (rgba(--you)) muddied into a dirty brown box.
     Neutral surface keeps it crisp and stops it fighting the amber title + lime CTA. */
  .cele-wear { font-size: 13px; font-weight: 700; color: var(--text); margin-top: 14px; padding: 9px 13px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); }
  .cele-btn { margin-top: 18px; width: 100%; }
  .cele-confetti { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
  .cele-piece { position: absolute; top: -14px; width: 8px; height: 13px; border-radius: 2px; opacity: 0.95; animation-name: cele-fall; animation-timing-function: linear; animation-iteration-count: 1; animation-fill-mode: forwards; }
  @keyframes cele-fade { from { opacity: 0; } to { opacity: 1; } }
  @keyframes cele-rise { from { opacity: 0; transform: translateY(16px) scale(0.96); } to { opacity: 1; transform: none; } }
  @keyframes cele-pop { from { transform: scale(0) rotate(-18deg); } to { transform: scale(1) rotate(0); } }
  @keyframes cele-fall { to { transform: translateY(440px) rotate(560deg); opacity: 0; } }
  /* ── Monday recap modal ── */
  .recap-backdrop { z-index: 10250; padding: 20px; overflow-y: auto; }
  .recap-card { position: relative; width: 100%; max-width: 340px; margin: auto; background: var(--surface); border: 1px solid var(--border-strong); border-radius: 22px; padding: 26px 20px 20px; text-align: center; box-shadow: 0 20px 60px rgba(0,0,0,0.55); animation: cele-rise 0.32s cubic-bezier(.2,1,.3,1) both; }
  .recap-close { position: absolute; top: 6px; right: 8px; width: 36px; height: 36px; background: none; border: 0; color: var(--text-dim); font-size: 18px; line-height: 1; cursor: pointer; padding: 0; display: inline-flex; align-items: center; justify-content: center; touch-action: manipulation; }
  .recap-glyph { line-height: 0; display: inline-block; animation: cele-pop 0.5s cubic-bezier(.2,1.5,.4,1) 0.08s both; }
  /* Tight wrapper so the placed stickers + rank badge anchor to the FACE (not the modal),
     and the Pro aura glow hugs the avatar's alpha — same recipe as .me-hero-face / .vs-face-in. */
  .recap-face { position: relative; display: inline-flex; align-items: center; justify-content: center; line-height: 1; filter: var(--aura-glow, ); will-change: transform; transform: translateZ(0); }
  .recap-title { font-size: 22px; font-weight: 900; letter-spacing: -0.02em; margin-top: 10px; }
  .recap-sub { font-size: 13px; color: var(--text-muted); margin-top: 6px; line-height: 1.5; }
  /* Weekly LETTER from JEK (Slice 4): a short note above the stats so the recap reads like a
     message from JEK, not a dashboard. */
  .recap-letter { margin: 12px 6px 4px; text-align: center; }
  .recap-letter-greet { font-weight: 800; font-size: 14px; margin: 0 0 4px; }
  .recap-letter-body { font-size: 13px; line-height: 1.55; color: var(--text-muted); margin: 0; }
  .recap-letter-sign { font-size: 12px; font-style: italic; color: var(--text-muted); opacity: 0.75; margin: 6px 0 0; }
  /* JEK's instant ✓-Done reaction chip (Slice 2): fixed above the bottom nav, non-interactive,
     pops in then fades. Lives in the Schedule day view. */
  .done-react { position: fixed; left: 50%; bottom: calc(var(--nav-h) + var(--safe-bottom) + 12px); transform: translateX(-50%); z-index: 9000;
    display: flex; align-items: center; gap: 8px; pointer-events: none;
    background: var(--surface); border: 1px solid var(--accent); border-radius: 999px;
    padding: 8px 14px; box-shadow: 0 8px 24px rgba(0,0,0,0.4); font-size: 13px; font-weight: 700; color: var(--text); }
  .done-react-msg { white-space: nowrap; }
  @keyframes doneReactPop {
    0% { opacity: 0; transform: translate(-50%, 10px) scale(0.9); }
    14% { opacity: 1; transform: translate(-50%, 0) scale(1); }
    80% { opacity: 1; transform: translate(-50%, 0) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -6px) scale(0.96); } }
  .done-react { animation: doneReactPop 1.6s ease both; }
  @media (prefers-reduced-motion: reduce) { .done-react { animation-timing-function: steps(1); } }
  .recap-card .week-card { margin-top: 14px; text-align: left; }
  /* Stat strip (kept% / days kept / streak) above the week card. */
  .recap-stats { display: flex; gap: 8px; margin-top: 16px; }
  .recap-stat { flex: 1; min-width: 0; background: var(--surface-2); border: 1px solid var(--border); border-radius: 14px; padding: 11px 6px; display: flex; flex-direction: column; gap: 3px; }
  .recap-stat-num { font-size: 21px; font-weight: 900; letter-spacing: -0.02em; line-height: 1.05; font-variant-numeric: tabular-nums; }
  .recap-stat.cur .recap-stat-num { color: var(--you); }
  .recap-stat-lbl { font-size: 9.5px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
  /* Meta line under the card: time invested / lost / goals. */
  .recap-meta { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 12px; margin-top: 12px; font-size: 12px; font-weight: 600; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  /* First-week note + day-score legend (shown when there's nothing graded yet). */
  .recap-legend { margin-top: 14px; padding: 12px 13px; border: 1px solid var(--border); border-radius: 14px; background: var(--surface-2); text-align: left; }
  .recap-legend-note { font-size: 12.5px; color: var(--text-muted); line-height: 1.5; }
  .recap-legend-row { display: flex; flex-wrap: wrap; gap: 7px 14px; margin-top: 10px; font-size: 12px; color: var(--text-muted); }
  .recap-legend-item b { color: var(--accent); font-weight: 800; margin-right: 4px; }
  .recap-insight { display: flex; gap: 10px; align-items: flex-start; text-align: left; margin-top: 14px; padding: 12px; border: 1px solid var(--border); border-radius: 14px; background: var(--surface-2); }
  .recap-insight-ico { font-size: 20px; line-height: 1.2; flex-shrink: 0; }
  .recap-insight-body { min-width: 0; flex: 1; }
  .recap-insight-quote { font-size: 13.5px; font-weight: 700; line-height: 1.45; }
  .recap-insight-cta { margin-top: 8px; background: none; border: 0; padding: 0; font: inherit; font-size: 12.5px; font-weight: 800; color: var(--accent); cursor: pointer; touch-action: manipulation; }
  .recap-insight-cta.lock { color: var(--text-muted); }
  .recap-plan { margin-top: 18px; width: 100%; }
  .week-headline { font-size: 20px; font-weight: 800; letter-spacing: -0.01em; }
  .week-sub { font-size: 12px; color: var(--text-muted); margin-top: 3px; font-variant-numeric: tabular-nums; }
  .week-bar { height: 8px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
  .week-goals { font-size: 12px; font-weight: 700; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .week-fill { height: 100%; border-radius: 999px; background: var(--text-muted); transition: width 0.5s ease; }
  .week-bar.good .week-fill { background: var(--accent); }
  .week-bar.mid .week-fill { background: var(--you); }
  .week-bar.bad .week-fill { background: var(--danger); }
  .week-strip { display: flex; gap: 5px; }
  .week-day {
    flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 4px;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px; padding: 7px 0;
  }
  .week-day-lbl { font-size: 10px; font-weight: 700; color: var(--text-dim); }
  .week-day-glyph { font-size: 14px; line-height: 1; height: 18px; display: flex; align-items: center; justify-content: center; }
  .week-day.kept { border-color: rgba(var(--accent-rgb),0.4); background: rgba(var(--accent-rgb),0.07); }
  .week-day.kept .week-day-lbl { color: var(--accent); }
  /* Progress ladder ◕/◑/◔: warm amber that brightens as you climb — encouraging, never alarming. */
  .week-day.almost { border-color: rgba(var(--accent-rgb),0.3); background: rgba(var(--accent-rgb),0.05); }
  .week-day.almost .week-day-lbl, .week-day.almost .week-day-glyph { color: var(--accent); }
  .week-day.half .week-day-glyph, .week-day.start .week-day-glyph { color: var(--you); }
  .week-day.half .week-day-lbl, .week-day.start .week-day-lbl { color: var(--you); }
  /* A planned day with nothing logged: a quiet hollow ring, dimmed — no red, no ✕. */
  .week-day.miss .week-day-glyph { color: var(--text-dim); }
  .week-day.miss { opacity: 0.7; }
  .week-day.today { box-shadow: 0 0 0 1px var(--accent); border-color: var(--accent); }
  .week-day.today .week-day-glyph { color: var(--accent); }
  .week-day.none, .week-day.future { opacity: 0.5; }
  .week-day.none .week-day-glyph, .week-day.future .week-day-glyph { color: var(--text-dim); }
  .week-day.rest { border-style: dashed; border-color: var(--border-strong); opacity: 0.75; }
  .week-day.rest .week-day-lbl { color: var(--text-muted); }

  /* Multi-week trend card */
  /* Coach card (Pro) — the avatar's weekly read on your data. Accent-tinted so it
     reads as the headline insight, not just another stat block. */
  .coach-card { background: linear-gradient(180deg, rgba(var(--accent-rgb),0.10), var(--surface) 60%); border: 1px solid var(--accent); border-radius: 18px; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
  .coach-head { display: flex; align-items: center; gap: 11px; }
  .coach-face { font-size: 30px; line-height: 1; }
  .coach-face-img { width: 38px; height: 38px; border-radius: 50%; object-fit: cover; }
  .coach-head-txt { display: flex; flex-direction: column; gap: 1px; }
  .coach-title { font-size: 15px; font-weight: 800; letter-spacing: -0.01em; }
  .coach-sub { font-size: 11px; color: var(--text-dim); font-weight: 600; }
  .coach-empty { font-size: 13px; color: var(--text-muted); line-height: 1.5; }
  .coach-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
  .coach-item { display: flex; gap: 8px; font-size: 13.5px; line-height: 1.45; color: var(--text); }
  .coach-dot { flex-shrink: 0; color: var(--accent); font-weight: 800; }
  .coach-pro { margin-left: auto; align-self: flex-start; font-size: 9px; font-weight: 900; letter-spacing: 0.08em; color: var(--accent); border: 1px solid var(--accent); border-radius: 5px; padding: 1px 5px; }
  /* Free "taste" CTA under the single previewed insight — the locked rest opens billing. */
  .coach-tease { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; text-align: left;
    background: var(--surface-2); border: 1px dashed var(--accent); border-radius: 12px; padding: 10px 12px;
    color: var(--text); font: inherit; cursor: pointer; touch-action: manipulation; }
  .coach-tease:active { opacity: 0.85; }
  .coach-tease-txt { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600; line-height: 1.35; min-width: 0; }
  .coach-tease-lock { font-size: 13px; flex: 0 0 auto; }
  .coach-tease-btn { flex: 0 0 auto; background: var(--accent); color: var(--accent-text); font-weight: 800; font-size: 12px; border-radius: 999px; padding: 6px 12px; }
  .coach-sugg { background: var(--surface-2); border-radius: 12px; padding: 11px 12px; font-size: 13px; line-height: 1.45; color: var(--text); display: flex; flex-direction: column; align-items: flex-start; }
  .coach-sugg-lbl { display: block; font-size: 10px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent); margin-bottom: 3px; }
  /* Coach action button — accept the suggestion (reschedule) right from the card. */
  .coach-act { display: inline-block; margin-top: 9px; border: 1px solid var(--accent); background: var(--accent); color: var(--accent-text); font: inherit; font-weight: 800; font-size: 12px; border-radius: 999px; padding: 7px 13px; cursor: pointer; touch-action: manipulation; }
  .coach-act:active { opacity: 0.85; }
  .coach-applied { display: inline-flex; align-items: center; gap: 8px; margin-top: 9px; font-size: 12px; font-weight: 800; color: var(--accent); }
  .coach-undo { border: 1px solid var(--border-strong); background: none; color: var(--text-muted); font: inherit; font-weight: 800; font-size: 11px; border-radius: 999px; padding: 4px 11px; cursor: pointer; touch-action: manipulation; }
  .coach-undo:active { color: var(--text); }
  /* dropOrMove: a "Reschedule" ghost + a two-tap "Drop it" (arms red on first tap). */
  .coach-acts { display: flex; gap: 8px; margin-top: 9px; flex-wrap: wrap; justify-content: center; }
  .coach-act-ghost { border: 1px solid var(--border-strong); background: none; color: var(--text); font: inherit; font-weight: 800; font-size: 12px; border-radius: 999px; padding: 7px 13px; cursor: pointer; touch-action: manipulation; }
  .coach-drop { border: 1px solid var(--border-strong); background: none; color: var(--text-muted); font: inherit; font-weight: 800; font-size: 12px; border-radius: 999px; padding: 7px 13px; cursor: pointer; touch-action: manipulation; }
  .coach-drop.arm { border-color: #f87171; background: rgba(248,113,113,0.14); color: #f87171; }
  /* Entrance animation: ONLY JEK's face pops in. The card / bullets / TRY-THIS box
     appear plainly (no card rise, ring, or stagger — user wanted just the emoji). */
  @keyframes coachPop { 0% { opacity: 0; transform: scale(0.4); } 60% { transform: scale(1.16); } 100% { opacity: 1; transform: scale(1); } }
  .coach-card .coach-face, .coach-card .coach-face-img { animation: coachPop 0.55s cubic-bezier(0.2,0.9,0.3,1.25) 0.06s both; transform-origin: center; }
  @media (prefers-reduced-motion: reduce) {
    .coach-card .coach-face, .coach-card .coach-face-img { animation: none !important; }
  }
  /* ── Stat Radar card ── */
  .radar-card { background: var(--surface); border: 1px solid var(--border); border-radius: 18px; padding: 16px; display: flex; flex-direction: column; gap: 10px; }
  .radar-card-head { display: flex; align-items: center; justify-content: space-between; }
  .radar-head-actions { display: flex; align-items: center; gap: 6px; }
  .radar-card-title { font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted); }
  .radar-subhead { font-size: 11px; color: var(--text-dim); margin: 2px 0 -4px; }
  .radar-match-msg { text-align: center; font-size: 13px; color: var(--text-muted); padding: 0 4px; }
  .radar-legend { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; padding: 2px 0; }
  .radar-leg { font-size: 11px; color: var(--text-muted); display: flex; align-items: center; gap: 5px; }
  .radar-leg::before { content: ''; display: inline-block; width: 20px; height: 2.5px; border-radius: 2px; }
  .radar-leg--avatar::before { height: 0; border-top: 2px dashed var(--accent); background: none; opacity: .8; }
  .radar-leg--you::before { background: var(--you); }
  .radar-leg--streak::before { background: var(--streak-leg, #fb7185); }
  .radar-pill { background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 3px 10px; font-size: 12px; font-weight: 700; color: var(--text-muted); min-height: 28px; cursor: pointer; display: flex; align-items: center; font-family: inherit; line-height: 1.2; }
  .radar-body { position: relative; min-height: 340px; overflow: hidden; }
  .radar-panel { position: absolute; inset: 0; transition: opacity 0.22s; }
  .radar-panel--hidden { opacity: 0; pointer-events: none; }
  .radar-panel--ach { display: flex; flex-direction: column; gap: 8px; padding: 4px 0; overflow-y: auto; }
  .trend-card { background: var(--surface); border: 1px solid var(--border); border-radius: 18px; padding: 16px; display: flex; flex-direction: column; gap: 14px; }
  .trend-card-top { display: flex; align-items: center; justify-content: space-between; }
  .trend-bars { display: flex; align-items: flex-end; gap: 8px; height: 104px; }
  .trend-col { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 5px; height: 100%; }
  .trend-col-pct { font-size: 10px; font-weight: 700; color: var(--text-dim); font-variant-numeric: tabular-nums; }
  .trend-track { flex: 1; width: 100%; max-width: 30px; border-radius: 6px; background: var(--surface-2); display: flex; align-items: flex-end; overflow: hidden; }
  .trend-fill { width: 100%; border-radius: 6px; background: var(--text-muted); transition: height 0.5s ease; }
  .trend-fill.good { background: var(--accent); }
  .trend-fill.mid { background: var(--you); }
  .trend-fill.bad { background: var(--danger); }
  .trend-fill.empty { background: var(--border-strong); }
  .trend-col-lbl { font-size: 10px; font-weight: 600; color: var(--text-dim); font-variant-numeric: tabular-nums; }
  .trend-col.cur .trend-col-pct { color: var(--accent); }
  .trend-col.cur .trend-col-lbl { color: var(--text); font-weight: 800; }
  .trend-heat { display: flex; flex-direction: column; gap: 4px; }
  .trend-heat-row { display: flex; align-items: center; gap: 4px; }
  .trend-heat-wk { width: 34px; flex-shrink: 0; font-size: 10px; font-weight: 600; color: var(--text-dim); text-align: right; font-variant-numeric: tabular-nums; }
  .trend-heat-dow { flex: 1; text-align: center; font-size: 10px; font-weight: 700; color: var(--text-dim); }
  .trend-cell { flex: 1; aspect-ratio: 1; max-height: 22px; border-radius: 5px; background: var(--surface-2); border: 1px solid transparent; }
  /* Progress heatmap: green when kept, fading through amber as you climb the ladder,
     a faint cell for a planned-but-empty day — no red, matching the History strip. */
  .trend-cell.kept { background: rgba(var(--accent-rgb),0.5); }
  .trend-cell.almost { background: rgba(var(--accent-rgb),0.3); }
  .trend-cell.half { background: rgba(var(--you-rgb),0.4); }
  .trend-cell.start { background: rgba(var(--you-rgb),0.22); }
  .trend-cell.miss { background: var(--surface-2); opacity: 0.7; }
  .trend-cell.today { background: rgba(var(--accent-rgb),0.18); border-color: var(--accent); }
  .trend-cell.future { background: transparent; border: 1px dashed var(--border); }
  .trend-cell.none { background: var(--surface-2); opacity: 0.55; }
  .trend-cell.rest { background: transparent; border: 1px dashed var(--border-strong); opacity: 0.6; }

  .hist-list { display: flex; flex-direction: column; gap: 8px; }
  .hist-row {
    background: var(--surface); border: 1px solid var(--border);
    border-left: 3px solid var(--border); border-radius: 12px; padding: 11px 14px;
  }
  .hist-row.good { border-left-color: var(--accent); }
  .hist-row.mid { border-left-color: var(--you); }
  .hist-row.bad { border-left-color: var(--danger); }
  .hist-row-top { display: flex; align-items: baseline; justify-content: space-between; }
  .hist-date { font-weight: 700; font-size: 14px; }
  .hist-pct { font-weight: 800; font-size: 16px; font-variant-numeric: tabular-nums; }
  .hist-row.good .hist-pct { color: var(--accent); }
  .hist-row.mid .hist-pct { color: var(--you); }
  .hist-row.bad .hist-pct { color: var(--danger); }
  .hist-bar { height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; margin: 7px 0; }
  .hist-fill { height: 100%; border-radius: 999px; }
  .hist-row.good .hist-fill { background: var(--accent); }
  .hist-row.mid .hist-fill { background: var(--you); }
  .hist-row.bad .hist-fill { background: var(--danger); }
  .hist-row-sub { display: flex; justify-content: space-between; gap: 10px; font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .hist-verdict { font-weight: 700; flex-shrink: 0; }
  .hist-note { font-size: 11px; color: var(--text-dim); text-align: center; margin: 2px 0 0; }

  /* Progress page: per-task weekly progress */
  /* Progress: per-day breakdown */
  .dayp-list { display: flex; flex-direction: column; gap: 8px; }
  /* Progress week stepper (‹ This week / range ›) — browse past weeks' day/task breakdown. */
  .hist-week-nav { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 6px 0 4px; }
  .hist-week-lbl { font-size: 14px; font-weight: 700; color: var(--text); min-width: 120px; text-align: center; }
  .dayp-row { display: flex; align-items: flex-start; gap: 11px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 11px 13px; }
  .dayp-row.excused { opacity: 0.55; }
  /* Promote the bright "today" card to its own compositor layer so its glowing border
     is rasterized ONCE and just translated while scrolling — without this the 1px
     border + inset ring re-paint at sub-pixel offsets every frame and shimmer/"tear". */
  .dayp-row.today { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; transform: translateZ(0); backface-visibility: hidden; }
  .dayp-glyph { font-size: 15px; line-height: 1; width: 18px; text-align: center; flex-shrink: 0; margin-top: 1px; }
  .dayp-main { flex: 1; min-width: 0; }
  .dayp-top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
  .dayp-date { font-size: 13px; font-weight: 800; }
  .dayp-verdict { font-size: 12px; font-weight: 800; flex-shrink: 0; }
  .dayp-verdict.good, .dayp-verdict.mid { color: var(--accent); }
  .dayp-verdict.bad { color: var(--danger); }
  .dayp-verdict.muted { color: var(--text-dim); }
  .dayp-bar { height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; margin-top: 8px; }
  .dayp-fill { height: 100%; border-radius: 999px; transition: width 0.4s ease; }
  .dayp-fill.good, .dayp-fill.mid { background: var(--accent); }
  .dayp-fill.bad { background: var(--danger); }
  .dayp-sub { font-size: 11px; color: var(--text-muted); margin-top: 6px; font-variant-numeric: tabular-nums; }
  /* Per-day race: committed self (avatar) vs you, mirroring the Day view's bars. */
  .dayp-race { margin-top: 8px; display: flex; flex-direction: column; gap: 5px; }
  .dayp-race-row { display: flex; align-items: center; gap: 8px; }
  .dayp-race-face { width: 18px; flex-shrink: 0; font-size: 14px; line-height: 1; display: flex; align-items: center; justify-content: center; }
  .dayp-race-tag { width: 20px; flex-shrink: 0; font-size: 11px; font-weight: 800; letter-spacing: .02em; color: var(--you); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dayp-race-track { position: relative; flex: 1; height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
  .dayp-race-fill { height: 100%; border-radius: 999px; transition: width 0.4s ease; }
  /* Purple "you're ahead of the committed self" overcharge tip on the ME bar — mirrors the
     day race's .rh-over. Anchored by `right` so it grows from the ME fill's leading edge. */
  .dayp-race-over { position: absolute; top: 0; height: 100%; border-radius: 999px; background: linear-gradient(90deg, #a855f7, #8b5cf6); border-left: 2px solid rgba(255,255,255,0.9); box-shadow: inset 0 0 4px rgba(255,255,255,0.3); transition: right 0.4s ease, width 0.4s ease; }
  .dayp-race-fill.av { background: var(--accent); }
  .dayp-race-fill.me { background: var(--you); }
  .dayp-race-val { width: 58px; flex-shrink: 0; text-align: right; font-size: 11px; font-weight: 700; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .dayp-race-note { font-size: 11px; color: var(--text-muted); margin-top: 1px; }

  .task-prog-list { display: flex; flex-direction: column; gap: 10px; }
  .task-prog { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 12px 14px; }
  .task-prog-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
  .task-prog-name { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 14px; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  .task-prog-emoji { width: 24px; height: 24px; border-radius: 50%; background: var(--bg); border: 2px solid; display: inline-flex; align-items: center; justify-content: center; font-size: 13px; line-height: 1; flex-shrink: 0; }
  .task-prog-pct { font-weight: 800; font-size: 15px; font-variant-numeric: tabular-nums; flex-shrink: 0; }
  .task-prog-pct.good { color: var(--accent); } .task-prog-pct.mid { color: var(--you); } .task-prog-pct.bad { color: var(--danger); }
  .task-prog-bar { height: 8px; border-radius: 999px; background: var(--surface-2); overflow: hidden; margin: 8px 0 6px; }
  .task-prog-fill { height: 100%; border-radius: 999px; transition: width 0.4s ease; }
  .task-prog-sub { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .tp-race { display: flex; flex-direction: column; gap: 5px; margin-top: 8px; }
  .tp-row { display: flex; align-items: center; gap: 8px; }
  .tp-tag { flex: 0 0 38px; max-width: 38px; font-size: 10px; font-weight: 800; letter-spacing: .02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tp-tag.jek { color: var(--accent); }
  .tp-tag.me { color: var(--text-muted); }
  .tp-track { flex: 1; height: 7px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
  .tp-fill { display: block; height: 100%; border-radius: 999px; }
  .tp-fill.jek { background: var(--accent); }
  .tp-val { flex: 0 0 auto; min-width: 48px; text-align: right; font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

  @keyframes micPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(220,70,70,0.5); } 50% { box-shadow: 0 0 0 5px rgba(220,70,70,0); } }

  /* "Plan with JEK" (AI) — entry button + modal */
  .btn-ai-plan { display: inline-flex; align-items: center; justify-content: center; gap: 6px; margin-top: 10px;
    padding: 11px 16px; border-radius: 12px; font-size: 14px; font-weight: 800; cursor: pointer;
    color: var(--accent); background: rgba(var(--accent-rgb), 0.10); border: 1px solid rgba(var(--accent-rgb), 0.45); }
  .btn-ai-plan.btn-block { display: flex; width: 100%; margin-top: 8px; }
  .btn-ai-plan:active { transform: scale(0.98); }
  .plan-sheet { max-width: 460px; }
  .plan-head { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 14px; }
  .plan-head-text { min-width: 0; }
  .plan-orb { flex: none; width: 42px; height: 42px; border-radius: 13px; display: flex; align-items: center; justify-content: center; font-size: 21px;
    background: linear-gradient(135deg, rgba(var(--accent-rgb),0.30), rgba(var(--accent-rgb),0.08));
    border: 1px solid rgba(var(--accent-rgb),0.40); box-shadow: 0 0 20px rgba(var(--accent-rgb),0.22); }
  .plan-orb.thinking { animation: micPulse 1.1s ease-in-out infinite; }
  .plan-title { font-size: 17px; font-weight: 800; margin: 2px 0 4px; }
  .plan-head .plan-sub { margin: 0; }
  .plan-sub { font-size: 13px; color: var(--text-dim); line-height: 1.5; margin: 0 0 12px; }
  .plan-field { position: relative; }
  .plan-input { width: 100%; box-sizing: border-box; resize: none; border: 1px solid rgba(var(--accent-rgb), 0.4);
    border-radius: 12px; background: rgba(0,0,0,0.18); color: var(--text); padding: 11px 13px; font-size: 15px;
    font-family: inherit; line-height: 1.5; }
  .plan-field .plan-input { padding-right: 50px; }
  .plan-input:focus { outline: none; border-color: var(--accent); }
  .plan-mic { position: absolute; right: 9px; bottom: 9px; width: 33px; height: 33px; display: flex; align-items: center; justify-content: center;
    border: 1px solid rgba(var(--accent-rgb),0.4); border-radius: 10px; background: rgba(0,0,0,0.25); color: var(--accent); cursor: pointer; font-size: 15px; }
  .plan-mic:active { transform: scale(0.92); }
  .plan-mic.on { background: rgba(220,70,70,0.85); border-color: rgba(220,70,70,0.9); color: #fff; animation: micPulse 1s ease-in-out infinite; }
  .plan-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin-top: 11px; }
  .plan-chips-label { font-size: 12px; color: var(--text-muted); margin-right: 1px; }
  .plan-chip { font-size: 12px; padding: 6px 11px; border-radius: 999px; border: 1px solid var(--border);
    background: rgba(var(--accent-rgb),0.06); color: var(--text-dim); cursor: pointer; line-height: 1.3; text-align: left; }
  .plan-chip:active { transform: scale(0.97); }
  .plan-chip:hover { border-color: rgba(var(--accent-rgb),0.5); color: var(--text); }
  .plan-err { color: var(--danger); font-size: 13px; margin-top: 8px; }
  .plan-lock { font-size: 12px; color: var(--text-dim); margin: 8px 2px 0; }
  .plan-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 14px; }
  .plan-preview { display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 14px;
    background: var(--surface-2); border: 1px solid var(--border); }
  .plan-prev-emoji { font-size: 34px; line-height: 1; flex: none; }
  .plan-prev-info { min-width: 0; }
  .plan-prev-name { font-size: 16px; font-weight: 800; }
  .plan-prev-meta { font-size: 13px; color: var(--text-dim); margin-top: 3px; }

  /* Schedule top bar: Day|Week toggle on the left, the compact "JEK plans your week"
     trigger on the right — sits inline so it no longer eats a full row of the table. */
  /* Grid (not flex) so the two columns are a TRUE 50/50 split. With flex, the JEK button's
     intrinsic min-content width skews the split a few px, so Day|Week ended up ~8px narrower
     than the Progress page's Day|Week (which is a clean 50%). Grid 1fr 1fr ignores content
     width → Day|Week matches the Progress toggle's width & x exactly, so the tab transition
     doesn't shift the pill. :only-child handles the AI-proposal state (JEK button hidden →
     toggle alone spans full width). */
  .sched-topbar { display: grid; grid-template-columns: 1fr 1fr; align-items: center; gap: 8px; }
  .sched-topbar > :only-child { grid-column: 1 / -1; }
  /* Match the Progress page's day/week pill exactly (radius/padding) so the toggle bar is the
     same height across tabs — otherwise switching pages shifts the layout and the transition jumps. */
  .sched-topbar .view-toggle { border-radius: 999px; padding: 4px; }
  .sched-topbar .view-toggle .view-toggle-btn { border-radius: 999px; padding: 8px 0; }
  /* "JEK plans your week" — entry button in the right grid column + its AI sheet */
  .sched-aiplan-btn { display: flex; align-items: center; justify-content: center; gap: 6px; margin: 0;
    padding: 8px 12px; border-radius: 999px; cursor: pointer; font-size: 13px; font-weight: 700; color: var(--accent);
    border: 1px solid rgba(var(--accent-rgb),0.40); background: linear-gradient(135deg, rgba(var(--accent-rgb),0.14), rgba(var(--accent-rgb),0.05)); }
  .sched-aiplan-btn:active { transform: scale(0.985); }
  .sched-aiplan-btn:hover { border-color: var(--accent); }
  .sched-aiplan-ic { font-size: 16px; line-height: 1; }
  .sched-aiplan-lock { font-size: 12px; opacity: 0.85; }
  /* (The old full-width "See progress" banner was replaced by a pie icon in the race card /
     week-nav header — see .race-prog and .wg-expand-ic.) */
  /* On narrow phones the label would wrap/crowd the toggle — collapse to icon-only and let the
     JEK column shrink to its icon width (1fr auto) so the Day|Week toggle takes the rest. */
  @media (max-width: 420px) { .sched-topbar { grid-template-columns: 1fr auto; } .sched-aiplan-lbl { display: none; } }
  .planweek-times { display: flex; gap: 10px; margin-bottom: 11px; }
  .planweek-time { flex: 1; display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--text-muted); }
  .planweek-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 11px; }
  .planweek-actchip { font-size: 12px; padding: 5px 10px; border-radius: 999px; border: 1px solid var(--border);
    background: rgba(var(--accent-rgb),0.06); color: var(--text-dim); line-height: 1.3; }
  .planweek-noacts { font-size: 12.5px; color: var(--text-dim); display: flex; align-items: center; flex-wrap: wrap; gap: 2px; }
  .planweek-noacts-cta { background: none; border: 0; color: var(--accent); font-weight: 700; font-size: 12.5px; cursor: pointer; padding: 0; margin-left: 4px; }
  .planweek-quota { font-size: 11.5px; color: var(--text-muted); text-align: right; margin: 8px 2px 0; }
  .planweek-preview { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; max-height: 46vh; overflow-y: auto; }
  .planweek-prev-row { display: flex; align-items: center; gap: 11px; padding: 10px 12px; border-radius: 12px;
    background: var(--surface-2); border: 1px solid var(--border); }
  .planweek-prev-emoji { font-size: 24px; line-height: 1; flex: none; }
  .planweek-prev-info { min-width: 0; }
  .planweek-prev-name { font-size: 14.5px; font-weight: 800; }
  .planweek-prev-meta { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
  .ai-undo-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 10px;
    padding: 9px 12px 9px 14px; border-radius: 12px; background: var(--surface-2); border: 1px solid rgba(var(--accent-rgb),0.4); }
  .ai-undo-msg { font-size: 13px; font-weight: 700; color: var(--text); }
  .ai-undo-btn { flex: none; font-size: 13px; font-weight: 800; color: var(--accent); background: none; border: none; cursor: pointer; padding: 4px 6px; }
  .ai-undo-btn:active { transform: scale(0.95); }
  /* Delete-undo toast: floats just above the bottom nav, centered on the app column. It's the
     confirmation for an instant delete (no blocking popup) — tap Undo to restore the snapshot. */
  .del-undo {
    position: fixed; left: 14px; right: 14px; bottom: calc(var(--safe-bottom) + 78px);
    max-width: calc(var(--app-max) - 28px); margin: 0 auto; z-index: 50;
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 11px 12px 11px 16px; border-radius: 14px;
    background: var(--surface-2); border: 1px solid rgba(var(--accent-rgb),0.4);
    box-shadow: 0 14px 34px rgba(0,0,0,0.5); animation: delUndoIn .22s ease;
  }
  @keyframes delUndoIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
  @media (prefers-reduced-motion: reduce) { .del-undo { animation: none; } }
  /* Ghost blocks = JEK's proposed week previewed on the real grid (dashed, faded, non-interactive) */
  .wg-block.wg-ghost { opacity: 0.7; }
  .wg-block.wg-ghost .wg-lane.plan { background: rgba(var(--accent-rgb),0.12) !important; border: 1.5px dashed rgba(var(--accent-rgb),0.85) !important; box-shadow: none !important; }
  .wg-block.wg-ghost .wg-box { display: none; }
  /* Accept/cancel bar shown in place of the 🪄 button while a proposed week is on the grid */
  .week-plan-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
    margin: 10px 0 2px; padding: 10px 14px; border-radius: 12px; border: 1px solid rgba(var(--accent-rgb),0.5);
    background: linear-gradient(135deg, rgba(var(--accent-rgb),0.16), rgba(var(--accent-rgb),0.06)); }
  .week-plan-msg { font-size: 13px; font-weight: 700; color: var(--text); }
  .week-plan-acts { display: flex; gap: 8px; }
  /* Starter presets on the empty Activities screen (one-tap to seed a set) */
  .preset-pick { margin: 24px auto 0; width: 100%; max-width: 360px; }
  .preset-pick-lbl { display: block; font-size: 12.5px; color: var(--text-muted); margin-bottom: 12px;
    text-align: center; letter-spacing: .01em; }
  .preset-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
  /* Each card carries its own tint via --preset-tint / --preset-tint-rgb (set inline). The
     animated emoji sits in a soft tinted squircle so the four cards read as a coherent set. */
  .preset-card { position: relative; display: flex; flex-direction: column; align-items: center;
    gap: 8px; padding: 16px 10px 13px; border-radius: 16px; cursor: pointer;
    border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
    transition: border-color .15s, transform .12s, box-shadow .15s; }
  .preset-card:hover { border-color: rgba(var(--preset-tint-rgb),0.55);
    box-shadow: 0 6px 18px rgba(var(--preset-tint-rgb),0.16); transform: translateY(-2px); }
  .preset-card:active { transform: scale(0.97); }
  .preset-card-emoji { display: grid; place-items: center; width: 52px; height: 52px;
    border-radius: 15px; font-size: 28px; line-height: 1;
    background: rgba(var(--preset-tint-rgb),0.14);
    box-shadow: inset 0 0 0 1px rgba(var(--preset-tint-rgb),0.22); }
  .preset-card-emoji img { width: 34px; height: 34px; object-fit: contain; display: block; }
  .preset-card-name { font-size: 14px; font-weight: 800; }
  .preset-card-sub { font-size: 11px; font-weight: 600; color: rgba(var(--preset-tint-rgb),0.72); }

  /* Template picker sheet: choose individual activities (any of the 16) instead of dumping a set. */
  .preset-sheet .sheet-body { padding-top: 12px; }
  .preset-pick-sub { font-size: 13px; color: var(--text-muted); margin: 0 0 14px; text-align: center; }
  .preset-tabs { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin-bottom: 14px; }
  .preset-tab { position: relative; display: flex; flex-direction: column; align-items: center; gap: 5px;
    padding: 10px 2px; border-radius: 13px; cursor: pointer; border: 1px solid var(--border);
    background: var(--surface-2); color: var(--text-muted); transition: border-color .15s, color .15s, background .15s; }
  .preset-tab.on { border-color: rgba(var(--preset-tint-rgb),0.7); color: var(--text);
    background: rgba(var(--preset-tint-rgb),0.12); }
  .preset-tab-emoji { display: grid; place-items: center; width: 30px; height: 30px; }
  .preset-tab-emoji img { width: 26px; height: 26px; object-fit: contain; }
  .preset-tab-name { font-size: 10.5px; font-weight: 700; line-height: 1; white-space: nowrap; letter-spacing: -.2px; }
  .preset-tab-badge { position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px; padding: 0 5px;
    display: grid; place-items: center; border-radius: 9px; font-size: 11px; font-weight: 800;
    background: rgba(var(--preset-tint-rgb),1); color: #06120a; }
  .preset-pick-tools { display: flex; justify-content: flex-end; margin-bottom: 8px; }
  .preset-selall { background: none; border: 0; cursor: pointer; font-size: 12.5px; font-weight: 700;
    color: var(--accent); padding: 4px 2px; }
  .preset-acts { display: flex; flex-direction: column; gap: 8px; }
  .preset-act { display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-radius: 13px;
    cursor: pointer; border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
    text-align: left; transition: border-color .12s, background .12s; }
  .preset-act.on { border-color: rgba(var(--preset-tint-rgb),0.7); background: rgba(var(--preset-tint-rgb),0.1); }
  .preset-act-emoji { display: grid; place-items: center; width: 38px; height: 38px; flex: 0 0 auto;
    border-radius: 11px; font-size: 22px; background: rgba(var(--preset-tint-rgb),0.14); }
  .preset-act-emoji img { width: 26px; height: 26px; object-fit: contain; }
  .preset-act-emoji-edit { cursor: pointer; position: relative; }
  .preset-act-emoji-edit::after { content: '✎'; position: absolute; right: -3px; bottom: -3px; font-size: 10px;
    width: 15px; height: 15px; display: grid; place-items: center; border-radius: 50%;
    background: rgba(var(--preset-tint-rgb),0.95); color: #06120a; font-weight: 900; }
  .preset-act-name { flex: 1; font-size: 14.5px; font-weight: 700; }
  .preset-act-check { flex: 0 0 auto; width: 22px; height: 22px; display: grid; place-items: center;
    border-radius: 50%; border: 1.5px solid var(--border-strong); font-size: 13px; font-weight: 900; color: #06120a; }
  .preset-act-check.on { background: rgba(var(--preset-tint-rgb),1); border-color: rgba(var(--preset-tint-rgb),1); }
  .preset-build { display: flex; align-items: center; gap: 8px; padding: 2px 2px 6px; }
  .preset-build-emoji { flex: 0 0 auto; width: 46px; height: 46px; display: grid; place-items: center;
    border-radius: 12px; border: 1px solid rgba(var(--preset-tint-rgb),0.7); background: var(--card2); cursor: pointer; }
  .preset-custom-hint { margin: 2px 4px 10px; font-size: 12.5px; color: var(--text-dim); text-align: center; }
  .preset-own-input { flex: 1; padding: 10px 12px; border-radius: 12px; border: 1px dashed var(--border-strong);
    background: transparent; color: var(--text); font-size: 14px; font-weight: 600; }
  .preset-own-input::placeholder { color: var(--text-dim); font-weight: 600; }
  .preset-own-input:focus { outline: none; border-style: solid; border-color: rgba(var(--preset-tint-rgb),0.7); }
  .preset-own-add { flex: 0 0 auto; width: 40px; height: 40px; border-radius: 12px; border: none; cursor: pointer;
    background: rgba(var(--preset-tint-rgb),0.9); color: #06120a; font-size: 22px; font-weight: 900; line-height: 1; }
  .sheet-foot { padding: 12px 16px calc(12px + var(--safe-bottom)); border-top: 1px solid var(--border); }
  .sheet-foot .btn-block { margin-top: 0; }

  /* Unscheduled activity's "🗓️ Schedule" affordance — a small NEUTRAL pill (not a raw underlined
     link, not a second lime CTA) so it reads as a button while staying quiet inside the card. */
  /* Blends with the plain "N block in schedule" status text on the other rows — same size/tone, no
     boxed pill. The 🗓️ icon + a subtle underline are the only hints it's tappable, so it stops
     clashing with the calm rows while still reading as an action. */
  .act-sub-sched { display: inline-flex; align-items: center; gap: 4px; padding: 0;
    font-size: 12px; font-weight: 600; cursor: pointer; line-height: 1.5;
    color: var(--text-muted); background: none; border: none;
    text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--border-strong);
    transition: color .12s; }
  .act-sub-sched:hover { color: var(--text); text-decoration-color: var(--text-dim); }
  .act-sub-sched:active { opacity: 0.6; }
  .act-sub-sched-ico { font-size: 11px; line-height: 1; }

  /* "JEK fixes your schedule" reschedule nudge — a HIGHLIGHTED card under the hero */
  .resched-nudge { margin: 12px 0 0; padding: 14px; border-radius: 16px;
    background: linear-gradient(180deg, rgba(var(--accent-rgb),0.12), rgba(var(--accent-rgb),0.05));
    border: 1px solid rgba(var(--accent-rgb),0.45); box-shadow: 0 6px 20px rgba(var(--accent-rgb),0.10);
    animation: pibUp .25s ease; }
  .resched-row { display: flex; align-items: center; gap: 11px; }
  .resched-face { font-size: 30px; line-height: 1; flex: none; filter: drop-shadow(0 2px 6px rgba(0,0,0,0.5)); }
  .resched-msg { min-width: 0; }
  .resched-title { font-size: 15px; font-weight: 800; color: var(--accent); }
  .resched-sub { font-size: 13px; color: var(--text); line-height: 1.45; margin-top: 2px; }
  .resched-ba { display: flex; align-items: center; justify-content: center; gap: 14px; margin: 12px 0; }
  .resched-ba-col { display: flex; flex-direction: column; align-items: center; gap: 2px; }
  .resched-ba-lbl { font-size: 10px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-dim); }
  .resched-ba-time { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; padding: 5px 12px; border-radius: 10px; }
  .resched-ba-time.old { color: var(--text-dim); background: var(--surface-2); text-decoration: line-through; }
  .resched-ba-time.fresh { color: var(--accent-text); background: var(--accent); }
  .resched-arrow { font-size: 18px; color: var(--accent); font-weight: 800; }
  .resched-actions { display: flex; justify-content: flex-end; gap: 10px; }
  /* PWA install banner — a vanilla (non-React) bar injected at the bottom of <body> so it's obvious
     Ijek INSTALLS as an app (not "just a website"). Hidden once installed (standalone) or dismissed. */
  #pwa-install-banner {
    position: fixed; left: 12px; right: 12px; top: calc(12px + env(safe-area-inset-top)); z-index: 12000;
    display: flex; align-items: center; gap: 10px; max-width: 460px; margin: 0 auto;
    background: var(--surface, #141925); border: 1px solid var(--accent, #a3e635); border-radius: 14px;
    padding: 11px 12px; box-shadow: 0 8px 28px rgba(0,0,0,0.55); animation: pibUp .22s ease;
    font-family: 'Segoe UI', system-ui, sans-serif;
  }
  @keyframes pibUp { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
  #pwa-install-banner .pib-ico { flex: none; width: 24px; height: 24px; display: block; }
  #pwa-install-banner .pib-txt { flex: 1; min-width: 0; font-size: 13.5px; color: var(--text, #e6e9ef); line-height: 1.35; }
  #pwa-install-banner .pib-btn { flex: none; background: var(--accent, #a3e635); color: var(--accent-text, #0f1115); border: none; border-radius: 999px; padding: 7px 16px; font-size: 13px; font-weight: 800; cursor: pointer; }
  #pwa-install-banner .pib-x { flex: none; background: none; border: none; color: var(--text-muted, #9aa4b6); font-size: 14px; cursor: pointer; padding: 4px 6px; line-height: 1; }

  /* ===== To-Do (floating button + bottom sheet) ===== */
  /* Hide the floating To-Do button while any bottom sheet/modal is open (it otherwise
     overlaps the sheet's own actions, e.g. the agenda's "+ Add a task"). */
  body:has(.sheet-backdrop) .todo-fab-tab { display: none; }
  /* A slim tab tucked against the right edge, above the bottom nav, out of the schedule's way. */
  .todo-fab-tab {
    position: absolute; right: 0; bottom: calc(var(--nav-h) + 40px); z-index: 70;
    width: 30px; height: 46px; border: none; border-radius: 13px 0 0 13px; cursor: pointer;
    background: var(--accent); color: var(--accent-text); display: grid; place-items: center;
    box-shadow: -5px 4px 16px rgba(0,0,0,0.38); opacity: 0.92; padding: 0 2px 0 0;
    -webkit-tap-highlight-color: transparent;
  }
  .todo-fab-tab:hover { opacity: 1; }
  .todo-fab-tab:active { transform: scale(0.94); }
  .todo-fab-tab svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2.2;
    stroke-linecap: round; stroke-linejoin: round; }
  .todo-fab-badge {
    position: absolute; top: -3px; right: -3px; min-width: 20px; height: 20px; padding: 0 5px;
    border-radius: 999px; background: var(--you, #fbbf24); color: #0b1220; font-size: 11px; font-weight: 800;
    display: grid; place-items: center; border: 2px solid var(--bg); box-sizing: border-box;
  }
  /* ── To-Do weekly stat card (Progress/History tab, read-only) ── */
  .todo-stat-card {
    display: flex; align-items: center; gap: 10px;
    background: var(--surface-2, #1a2235); border: 1px solid var(--border, #2a3450);
    border-radius: 12px; padding: 11px 14px; margin: 12px 0 4px;
  }
  .todo-stat-icon { flex: none; display: grid; place-items: center; width: 28px; height: 28px;
    background: var(--accent); border-radius: 8px; }
  .todo-stat-icon svg { width: 15px; height: 15px; fill: none; stroke: var(--accent-text, #fff);
    stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
  .todo-stat-body { flex: 1; display: flex; flex-direction: column; gap: 1px; }
  .todo-stat-label { font-size: 11px; color: var(--text-muted, #9aa4b6); font-weight: 500; }
  .todo-stat-value { font-size: 17px; font-weight: 700; color: var(--text, #e8eaf0); }
  .todo-stat-value.all-done { color: var(--you, #fbbf24); }
  .todo-stat-cheer { flex: none; font-size: 12px; font-weight: 600; color: var(--you, #fbbf24); }

  /* Inline To-Do card on the Progress tab (under the Weekly Recap). Matches the recap/card look:
     a header row with icon + week count, an add bar, then the live checkable list. */
  .twk-card {
    background: var(--surface); border: 1px solid var(--border, #2a3450);
    border-radius: 16px; padding: 14px 14px 10px; margin: 0 0 14px;
  }
  .twk-head { display: flex; align-items: center; gap: 9px; margin-bottom: 12px; }
  .twk-icon { flex: none; display: grid; place-items: center; width: 28px; height: 28px;
    background: var(--accent); border-radius: 8px; }
  .twk-icon svg { width: 15px; height: 15px; fill: none; stroke: var(--accent-text, #fff);
    stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
  .twk-label { flex: 1; font-size: 13px; font-weight: 700; color: var(--text, #e8eaf0); letter-spacing: -0.01em; }
  .twk-count { flex: none; font-size: 13px; font-weight: 700; color: var(--text-muted, #9aa4b6); }
  .twk-count.all-done { color: var(--you, #fbbf24); }
  .twk-addbar { display: flex; gap: 8px; margin-bottom: 10px; }
  .twk-input {
    flex: 1; min-width: 0; background: var(--surface-2, #1a2235); border: 1px solid var(--border);
    border-radius: 11px; padding: 10px 13px; color: var(--text); font-size: 14px; outline: none;
    transition: border-color .15s, box-shadow .15s;
  }
  .twk-input::placeholder { color: var(--text-dim); }
  .twk-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16); }
  .twk-add {
    flex: none; width: 42px; border: none; border-radius: 11px; background: var(--accent);
    color: var(--accent-text); font-size: 22px; font-weight: 700; line-height: 1; cursor: pointer;
    transition: background .15s, opacity .15s;
  }
  .twk-add:hover:not(:disabled) { background: var(--accent-hover); }
  .twk-add:disabled { opacity: 0.4; cursor: default; }
  .twk-list { display: flex; flex-direction: column; }
  .twk-hint { font-size: 13px; color: var(--text-dim); text-align: center; padding: 6px 4px 8px; }
  /* All-clear celebration line (mirrors the To-Do sheet's cheer). */
  .twk-cheer { font-size: 13px; font-weight: 600; color: var(--you, #fbbf24); text-align: center; padding: 2px 4px 10px; }
  /* WEEK roll-up rows: one per to-do, with a weekly progress bar (recurring) or done/open (one-off). */
  .twk-wrow { display: flex; align-items: center; gap: 10px; padding: 9px 2px; border-bottom: 1px solid var(--border); }
  .twk-wrow:last-child { border-bottom: none; }
  .twk-wrow-name { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--text); }
  .twk-wrow-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .twk-wrow.is-done .twk-wrow-text { color: var(--text-muted); }
  .twk-wrow-prog { flex: none; display: flex; align-items: center; gap: 8px; }
  .twk-wbar { width: 64px; height: 6px; border-radius: 3px; background: var(--surface-2, #1a2235); overflow: hidden; }
  .twk-wbar > span { display: block; height: 100%; border-radius: 3px; background: var(--you, #fbbf24); }
  .twk-wval { font-size: 12px; font-weight: 600; color: var(--text-muted); min-width: 46px; text-align: right; }
  .twk-wone { flex: none; font-size: 12.5px; font-weight: 600; color: var(--text-dim); }
  .twk-wone.done { color: var(--you, #fbbf24); }
  .twk-manage {
    display: block; width: 100%; margin-top: 6px; background: none; border: none;
    color: var(--accent); font-size: 13px; font-weight: 600; text-align: right; cursor: pointer; padding: 4px 2px;
  }
  .twk-manage:hover { color: var(--accent-hover); }

  /* Sheet slides up from the bottom; backdrop reuses .modal-backdrop but bottom-aligns. */
  /* Clip the slide-up overshoot: the sheet animates from translateY(28px), which in Chromium
     extends the fixed backdrop's scrollable overflow for ~0.22s → a right-edge scrollbar that
     blinks on open. The sheet is bottom-pinned + max-height:86% and scrolls its OWN body, so the
     backdrop never needs to scroll — hide its overflow to kill the flicker. */
  .todo-backdrop { align-items: flex-end; padding: 0; overflow: hidden; }
  .todo-sheet {
    /* position:relative so a stacked .sheet.l2 (the emoji picker opened from a row) pins to
       THIS narrow centered column, not the full-viewport .todo-backdrop (which made the
       picker span the whole desktop screen). */
    position: relative;
    width: 100%; max-width: var(--app-max, 460px); margin: 0 auto; background: var(--surface);
    border: 1px solid var(--border-strong); border-bottom: none; border-radius: 22px 22px 0 0;
    max-height: 86%; display: flex; flex-direction: column; padding: 18px 16px calc(16px + env(safe-area-inset-bottom));
    box-shadow: 0 -16px 50px rgba(0,0,0,0.5); animation: todoSheetUp .24s ease-out;
  }
  /* Full slide-up from the bottom edge — same entrance as the activity / edit sheets (.sheet's
     slideUp), instead of the old barely-there 28px nudge. */
  @keyframes todoSheetUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
  .todo-sheet-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
  .todo-sheet-close {
    flex: none; background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted);
    width: 32px; height: 32px; border-radius: 50%; font-size: 14px; cursor: pointer; line-height: 1;
  }
  .todo-sheet-close:hover { color: var(--text); }
  .todo-sheet-body { overflow-y: auto; flex: 1; min-height: 0; margin: 0 -4px; padding: 0 4px; }
  .todo-head { margin: 0 0 14px; }
  .todo-title { margin: 0; font-size: 22px; font-weight: 800; color: var(--text); letter-spacing: -0.01em; }
  .todo-sub { margin: 4px 0 0; font-size: 13px; color: var(--text-dim); }
  .todo-addbar { display: flex; gap: 8px; margin-bottom: 16px; }
  .todo-input {
    flex: 1; min-width: 0; background: var(--surface); border: 1px solid var(--border);
    border-radius: 12px; padding: 12px 14px; color: var(--text); font-size: 15px; outline: none;
    transition: border-color .15s, box-shadow .15s;
  }
  .todo-input::placeholder { color: var(--text-dim); }
  .todo-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16); }
  .todo-add-btn {
    flex: none; width: 46px; border: none; border-radius: 12px; background: var(--accent);
    color: var(--accent-text); font-size: 24px; font-weight: 700; line-height: 1; cursor: pointer;
    transition: background .15s, opacity .15s;
  }
  .todo-add-btn:hover:not(:disabled) { background: var(--accent-hover); }
  .todo-add-btn:disabled { opacity: 0.4; cursor: default; }

  /* Avatar reacts to your one-off load — speech line + a you-amber progress bar (race feel). */
  .todo-hero {
    display: flex; align-items: center; gap: 12px; margin: 0 0 14px; padding: 12px 14px;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 16px;
  }
  .todo-hero-face { flex: none; position: relative; width: 38px; height: 38px; display: grid; place-items: center; overflow: visible; }
  .todo-hero-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
  .todo-hero-say { font-size: 13.5px; font-weight: 600; color: var(--text); line-height: 1.25;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .todo-hero-bar { height: 7px; border-radius: 999px; background: rgba(var(--you-rgb, 251,191,36), 0.18); overflow: hidden; }
  .todo-hero-bar > span { display: block; height: 100%; border-radius: 999px;
    background: var(--you, #fbbf24); transition: width .3s ease; }
  .todo-hero-count { flex: none; font-size: 17px; font-weight: 800; color: var(--text); letter-spacing: -0.02em; }
  .todo-hero-count span { font-size: 12px; font-weight: 700; color: var(--text-dim); }
  .todo-hero.is-clear { border-color: rgba(var(--you-rgb, 251,191,36), 0.5); animation: todoCheer .5s ease; }
  @keyframes todoCheer { 0% { transform: scale(1); } 40% { transform: scale(1.025); } 100% { transform: scale(1); } }

  .todo-list { display: flex; flex-direction: column; gap: 8px; }
  .todo-row {
    display: flex; align-items: center; gap: 12px; background: var(--surface);
    border: 1px solid var(--border); border-radius: 12px; padding: 11px 12px;
  }
  .todo-check {
    flex: none; width: 24px; height: 24px; border-radius: 7px; border: 2px solid var(--border-strong);
    background: transparent; cursor: pointer; display: grid; place-items: center; padding: 0;
    -webkit-appearance: none; appearance: none; transition: background .15s, border-color .15s;
  }
  .todo-check:disabled { cursor: default; opacity: 0.6; }
  /* The row body (face + text) is itself the edit target — tap anywhere on it to open settings,
     mirroring how tapping an activity card opens its editor (not just a small button). */
  .todo-body {
    flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px; text-align: left;
    background: none; border: none; padding: 0; margin: 0; color: inherit; cursor: pointer;
    font: inherit; -webkit-tap-highlight-color: transparent;
  }
  .todo-body:disabled { cursor: default; }
  .todo-check svg { width: 14px; height: 14px; fill: none; stroke: var(--accent-text); stroke-width: 2.4;
    stroke-linecap: round; stroke-linejoin: round; opacity: 0; transition: opacity .12s; }
  .todo-row.is-done .todo-check { background: var(--accent); border-color: var(--accent); }
  .todo-row.is-done .todo-check svg { opacity: 1; }
  .todo-text { flex: 1; min-width: 0; color: var(--text); font-size: 15px; line-height: 1.35;
    word-break: break-word; overflow-wrap: anywhere; }
  .todo-row.is-done .todo-text { color: var(--text-dim); text-decoration: line-through; }
  /* Per-item face sits just left of the text, inside the tap target. */
  .todo-emoji { flex: none; display: inline-grid; place-items: center; width: 22px; height: 22px;
    margin-right: 2px; }
  .todo-emoji img, .todo-emoji .face-crop, .todo-emoji .face-img { border-radius: 5px; }
  .todo-del {
    flex: none; background: none; border: none; color: var(--text-dim); font-size: 15px; line-height: 1;
    cursor: pointer; padding: 6px; border-radius: 8px; transition: color .15s, background .15s;
  }
  .todo-del:hover { color: #f87171; background: rgba(248,113,113,0.12); }

  /* The check + text are one big tap target now (the lone 24px box was easy to miss). */
  .todo-tap {
    flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px;
    background: none; border: none; padding: 0; margin: 0; cursor: pointer; text-align: left;
    color: inherit; -webkit-tap-highlight-color: transparent;
  }
  .todo-edit {
    flex: none; background: none; border: none; color: var(--text-dim); font-size: 14px; line-height: 1;
    cursor: pointer; padding: 6px; border-radius: 8px; transition: color .15s, background .15s;
  }
  .todo-edit:hover { color: var(--accent); background: rgba(var(--accent-rgb), 0.12); }
  .todo-row.editing { padding: 7px 10px; }
  .todo-edit-input {
    flex: 1; min-width: 0; width: 100%; background: var(--surface); border: 1px solid var(--accent);
    border-radius: 9px; padding: 9px 11px; color: var(--text); font-size: 15px; outline: none;
    box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16);
  }
  .todo-clear.danger { color: #f87171; text-decoration: none; }

  .todo-done-head {
    display: flex; align-items: center; justify-content: space-between;
    margin: 14px 2px 2px; font-size: 12px; font-weight: 700; color: var(--text-dim);
    text-transform: uppercase; letter-spacing: 0.04em;
  }
  .todo-clear { background: none; border: none; color: var(--text-dim); font-size: 12px; font-weight: 700;
    cursor: pointer; padding: 2px 4px; text-transform: none; letter-spacing: 0; }
  .todo-clear:hover { color: var(--text-muted); text-decoration: underline; }
  .todo-allclear { text-align: center; color: var(--text-muted); font-size: 14px; padding: 18px 0 4px; }
  .todo-count { text-align: center; color: var(--text-dim); font-size: 12px; margin-top: 14px; }

  /* Pro "To-Do History" — an overlay ON TOP of .todo-sheet (own backdrop, click-out closes just it). */
  .todo-hist-backdrop { align-items: center; padding: 16px; }
  .todo-hist-panel {
    width: 100%; max-width: var(--app-max, 460px); max-height: 80vh; margin: 0 auto;
    background: var(--surface); border: 1px solid var(--border-strong); border-radius: 18px;
    display: flex; flex-direction: column; padding: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.5);
  }
  .todo-hist-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
  .todo-hist-head h3 { margin: 0; font-size: 17px; font-weight: 800; color: var(--text); }
  .todo-hist-body { overflow-y: auto; flex: 1; min-height: 0; }
  .todo-hist-day { margin-bottom: 16px; }
  .todo-hist-day:last-child { margin-bottom: 0; }
  .todo-hist-daylabel {
    font-size: 11px; font-weight: 700; color: var(--text-dim); text-transform: uppercase;
    letter-spacing: 0.04em; margin: 0 2px 6px;
  }
  .todo-hist-row {
    display: flex; align-items: center; gap: 8px; padding: 8px 2px; border-bottom: 1px solid var(--border);
  }
  .todo-hist-day .todo-hist-row:last-child { border-bottom: none; }
  .todo-hist-text { flex: 1; min-width: 0; font-size: 14px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .todo-hist-time { flex: none; font-size: 12px; color: var(--text-dim); }

  .todo-empty { text-align: center; padding: 48px 16px; }
  /* Animated (Noto GIF) emoji — the img sizes itself, so this is just centering. */
  .todo-empty-emoji { font-size: 40px; display: flex; justify-content: center; line-height: 1; }
  /* Day progress with zero blocks: one empty state instead of an empty stat scaffold. */
  .dayp-empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 7px;
    padding: 26px 18px 22px; border: 1px dashed var(--border); border-radius: 16px; background: var(--surface-2); }
  .dayp-empty-emoji { display: flex; justify-content: center; line-height: 1; }
  .dayp-empty-title { font-size: 15px; font-weight: 800; color: var(--text); }
  .dayp-empty-sub { font-size: 12.5px; color: var(--text-dim); max-width: 30ch; line-height: 1.45; }
  .dayp-empty-btn { margin-top: 6px; }
  .todo-empty-title { margin-top: 10px; font-size: 16px; font-weight: 700; color: var(--text); }
  .todo-empty-sub { margin-top: 4px; font-size: 13px; color: var(--text-dim); }

  /* ⚙ settings button (reuses .todo-edit base) active state */
  .todo-edit.on { color: var(--accent); background: rgba(var(--accent-rgb), 0.14); }
  .todo-tap:disabled { cursor: default; }

  /* Header cluster: the ✎ Edit (manage) toggle + the close ✕, mirroring the Activities list head. */
  .todo-head-actions { flex: none; display: flex; align-items: center; gap: 8px; }
  /* Per-row "Edit ›" link — same text-link treatment as an activity card's .act-card-edit, but a
     real button (the to-do row isn't itself one button). Replaces the old ⚙ gear. */
  .todo-edit-link {
    flex: none; background: none; border: none; color: var(--text-dim); font-size: 12px; font-weight: 700;
    cursor: pointer; padding: 6px 4px; white-space: nowrap; transition: color .15s;
  }
  /* Quiet, like an activity card's "Edit ›" — no accent box on hover (the whole row already
     reads as tappable); just brighten the text. */
  .todo-edit-link:hover, .todo-edit-link.on { color: var(--text); }
  /* Whole row signals it's tappable-to-edit (matches act-card cursor + a faint hover lift). */
  .todo-row:hover:not(.is-editing) { border-color: var(--border-strong); }
  /* In manage mode the row reads as a draggable card: a touch of surface + the grab cursor. */
  .todo-row.is-editing { cursor: grab; border-color: rgba(var(--danger-rgb, 239,68,68), 0.35); }

  /* Count / percent progress pill (replaces the checkbox for those goal modes). */
  .todo-tap-prog { cursor: default; }
  .todo-prog {
    flex: none; min-width: 44px; height: 28px; padding: 0 9px; border-radius: 8px; cursor: pointer;
    display: grid; place-items: center; font-size: 12.5px; font-weight: 800; letter-spacing: -0.01em;
    background: var(--surface-2); border: 1.5px solid var(--border-strong); color: var(--text);
    transition: background .12s, border-color .12s;
  }
  .todo-prog:disabled { cursor: default; }
  .todo-prog.is-done { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
  /* −/＋ stepper for reps & percent. */
  .todo-step { flex: none; display: flex; gap: 4px; }
  .todo-step button {
    width: 28px; height: 28px; border-radius: 8px; border: 1px solid var(--border-strong);
    background: var(--surface-2); color: var(--text); font-size: 15px; font-weight: 700; line-height: 1;
    cursor: pointer; display: grid; place-items: center; transition: background .12s, opacity .12s;
  }
  .todo-step button:hover:not(:disabled) { background: var(--surface); border-color: var(--accent); }
  .todo-step button:disabled { opacity: 0.35; cursor: default; }
  /* Off-day recurring rows: shown muted with their repeat tag, no progress control. */
  .todo-row.is-offday { opacity: 0.6; }
  .todo-offtag {
    flex: none; font-size: 11px; font-weight: 700; color: var(--text-dim); padding: 3px 8px;
    border-radius: 7px; background: var(--surface-2); border: 1px solid var(--border); white-space: nowrap;
  }
  /* 🔥 streak chip on a recurring to-do — ties it to the app's streak DNA. */
  .todo-streak {
    flex: none; font-size: 11.5px; font-weight: 800; color: #fb923c; padding: 3px 7px; border-radius: 999px;
    background: rgba(251,146,60,0.14); white-space: nowrap; letter-spacing: -0.02em;
  }
  /* "R" chip — marks a recurring (routine) to-do at a glance (everyday / pick-days). */
  .todo-routine {
    flex: none; font-size: 11px; font-weight: 800; color: var(--accent); padding: 3px 8px; border-radius: 999px;
    background: rgba(var(--accent-rgb),0.14); white-space: nowrap; letter-spacing: 0.02em;
  }
  /* 🔔 reminder-time chip. */
  .todo-remind {
    flex: none; font-size: 11px; font-weight: 700; color: var(--text-dim); padding: 3px 7px; border-radius: 999px;
    background: var(--surface-2); white-space: nowrap;
  }
  /* 📅 due-date chip (one-off); red when overdue, accent when due today. */
  .todo-due {
    flex: none; font-size: 11px; font-weight: 700; color: var(--text-dim); padding: 3px 8px; border-radius: 7px;
    background: var(--surface-2); border: 1px solid var(--border); white-space: nowrap;
  }
  .todo-due.today { color: var(--accent); border-color: var(--accent); }
  .todo-due.overdue { color: #f87171; border-color: rgba(248,113,113,0.5); background: rgba(248,113,113,0.10); }
  /* ⠿ drag handle (pointer-based reorder of active rows). */
  .todo-drag {
    flex: none; background: none; border: none; color: var(--text-dim); font-size: 16px; line-height: 1;
    cursor: grab; padding: 2px 4px; touch-action: none; -webkit-tap-highlight-color: transparent;
  }
  .todo-drag:active { cursor: grabbing; }
  /* Drag-to-reorder (mirrors the Activities list): held row lifts + follows the pointer; the rows it
     passes slide with a transition; DOM order is fixed until drop. */
  .todo-row.is-shift { transition: transform 0.16s ease; }
  /* Accent highlight is an inset box-shadow RING (not border-color) so it beats the .todo-row:hover
     border rule during a desktop drag — same visible highlight the Activities card gets. */
  .todo-row.is-armed { position: relative; z-index: 4; transform: scale(1.015); touch-action: none;
    user-select: none; -webkit-user-select: none;
    box-shadow: 0 0 0 2px var(--accent), 0 6px 18px rgba(0,0,0,0.4); transition: transform 0.12s ease, box-shadow 0.12s ease; }
  .todo-row.is-dragging { position: relative; z-index: 6; touch-action: none; user-select: none; -webkit-user-select: none;
    cursor: grabbing; opacity: 0.97; box-shadow: 0 0 0 2px var(--accent), 0 12px 28px rgba(0,0,0,0.55); }

  /* Inline ⚙ config panel: rename + repeat + goal + due/remind, expanded under a row.
     Reveal fades + slides UP into place (translateY(-6px)→0) so it never pushes content
     past the sheet body's bottom — a downward slide caused a scrollbar to blink on open. */
  @keyframes todoCfgIn { from { opacity: 0; transform: translateY(-10px) scaleY(0.97); } to { opacity: 1; transform: none; } }
  .todo-cfg {
    margin: -3px 0 4px; padding: 13px; border-radius: 12px;
    background: var(--surface-2); border: 1px solid var(--border); border-left: 3px solid var(--accent);
    display: flex; flex-direction: column; gap: 11px;
    animation: todoCfgIn .2s ease-out; transform-origin: top;
  }
  .todo-cfg-name {
    width: 100%; background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
    padding: 10px 12px; color: var(--text); font-size: 14px; font-weight: 600; outline: none;
  }
  .todo-cfg-name:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16); }
  .todo-cfg-label { display: flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 800;
    color: var(--text); text-transform: uppercase; letter-spacing: 0.06em;
    border-top: 1px solid var(--border); padding-top: 11px; margin-top: 1px; }
  /* Segmented control — same separated-chip family as the Task editor's .goalmode-row/.goalmode-opt. */
  .todo-cfg-seg { display: flex; gap: 6px; }
  .todo-cfg-seg button {
    flex: 1 1 0; min-width: 0; padding: 8px 3px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface);
    color: var(--text-muted); font-size: 12px; font-weight: 700; cursor: pointer; transition: all .14s;
    display: inline-flex; align-items: center; justify-content: center; gap: 4px; white-space: nowrap;
  }
  .todo-cfg-seg button .action-emoji, .todo-cfg-seg button .action-fallback { flex: none; }
  .todo-cfg-seg button.on { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
  .todo-cfg-days { display: flex; gap: 5px; }
  .todo-day {
    flex: 1; min-width: 0; padding: 8px 0; border-radius: 10px; border: 1px solid var(--border);
    background: var(--surface-2); color: var(--text-dim); font-size: 13px; font-weight: 700; cursor: pointer;
    height: 40px; transition: all .14s;
  }
  .todo-day.on { background: rgba(var(--accent-rgb), 0.16); border-color: var(--accent); color: var(--accent); }
  /* Boxed field rows for the count target / due date / reminder time. */
  .todo-cfg-target {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 8px 12px;
  }
  .todo-cfg-target > span { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; color: var(--text); }
  .todo-cfg-target input {
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px;
    padding: 7px 10px; color: var(--text); font-size: 14px; font-weight: 700; outline: none;
  }
  .todo-cfg-target input[type=number] { width: 62px; text-align: center; -moz-appearance: textfield; appearance: textfield; }
  /* Hide the ugly native number spinner (rendered as a diamond glyph in this theme). */
  .todo-cfg-target input[type=number]::-webkit-outer-spin-button,
  .todo-cfg-target input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .todo-cfg-target input:focus { border-color: var(--accent); }
  /* Emoji picker row: current face (or ＋) + a small clear ✕. */
  .todo-emoji-pick { display: flex; align-items: center; gap: 8px; }
  .todo-emoji-btn {
    width: 38px; height: 38px; border-radius: 9px; border: 1px solid var(--border);
    background: var(--surface-2); color: var(--text-dim); display: grid; place-items: center;
    font-size: 20px; line-height: 1; cursor: pointer; padding: 0;
  }
  .todo-emoji-btn:hover { border-color: var(--accent); }
  .todo-emoji-btn.has-emoji { border: 2px solid var(--accent); background: transparent; }
  .todo-emoji-x {
    width: 24px; height: 24px; border-radius: 50%; border: 1px solid var(--border);
    background: transparent; color: var(--text-dim); font-size: 12px; cursor: pointer;
    display: grid; place-items: center; padding: 0;
  }
  /* Done is PINNED to the bottom of the panel (sticky) so a long config (repeat + days + goal +
     target + due + remind) never forces a scroll-hunt for it — it's always one tap away at the
     bottom edge. Negative margins span the panel's 13px padding so it reads as a full-width footer
     bar; the solid bg + top shadow keep content from bleeding through as it scrolls behind. */
  .todo-cfg-close {
    position: sticky; bottom: 0; z-index: 2;
    align-self: stretch; margin: 7px -13px -13px; padding: 13px;
    border: 0; border-top: 1px solid var(--border); border-radius: 0 0 11px 11px;
    background: var(--surface-2); color: var(--text); font-size: 13px; font-weight: 800; cursor: pointer;
    box-shadow: 0 -10px 14px -10px rgba(0,0,0,0.5);
    transition: color .14s;
  }
  .todo-cfg-close:hover { color: var(--accent); }

  /* Time/Date pickers inside a cfg row: size to content (not the full row) and tone the big
     18px wheel-display down to match the compact boxed fields around them. */
  .todo-cfg-picker { flex: 0 0 auto; }
  .todo-cfg-picker .tp { flex: 0 0 auto; }
  .todo-cfg-picker .tp-display { font-size: 14px; padding: 7px 12px; min-width: 96px; }
  .todo-cfg-picker .dp .tp-display { min-width: 124px; }

  /* DatePicker calendar (popover reuses .tp-pop). */
  .dp-pop { width: 252px; left: auto; right: 0; padding: 12px; }
  /* SCOPED to .tp — the TimePicker/DatePicker popover. These share class names (dp-nav, dp-cell, …) with
     the SCHEDULE date popover (.dp, no .tp), and being later in the file they used to override it — which
     stacked the schedule's ‹ › arrows and turned its selected-today number green-on-green (invisible). */
  .tp .dp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
  .tp .dp-title { font-weight: 800; font-size: 14px; color: var(--text); }
  .tp .dp-nav {
    width: 30px; height: 30px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface-2);
    color: var(--text); font-size: 16px; line-height: 1; cursor: pointer; display: grid; place-items: center;
  }
  .tp .dp-nav:hover { border-color: var(--accent); }
  .tp .dp-wd { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 4px; }
  .tp .dp-wd span { text-align: center; font-size: 10px; font-weight: 800; color: var(--text-muted); text-transform: uppercase; }
  .tp .dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
  .tp .dp-cell {
    aspect-ratio: 1; border: 1px solid transparent; border-radius: 8px; background: transparent;
    color: var(--text); font-size: 13px; font-weight: 700; cursor: pointer; display: grid; place-items: center;
    font-variant-numeric: tabular-nums; transition: all .12s;
  }
  .tp .dp-cell:hover { background: var(--surface-2); }
  .tp .dp-cell.today { color: var(--accent); border-color: rgba(var(--accent-rgb), 0.4); }
  .tp .dp-cell.on { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
  .tp .dp-cell.dp-empty { cursor: default; }
  .tp .dp-cell.dp-empty:hover { background: transparent; }

  /* ===== Glance view (`?glance`) — tiny read-only "pin this window" card. No nav/tabs; the
     whole thing is one big tap target that opens the real app. Kept compact for a small
     PWA-window / pinned-tab size. */
  .glance-wrap {
    display: block; box-sizing: border-box; min-height: 100vh; padding: 16px;
    background: var(--bg); color: var(--text); text-decoration: none;
  }
  .glance-card {
    max-width: 420px; margin: 0 auto; display: flex; flex-direction: column; gap: 10px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 18px; padding: 14px;
  }
  .glance-head { display: flex; align-items: baseline; justify-content: space-between; padding: 0 2px; }
  .glance-head span:first-child { font-size: 15px; font-weight: 800; color: var(--text); }
  .glance-head-sub { font-size: 11px; color: var(--text-dim); }
  .glance-empty-day, .glance-empty-sub { font-size: 12px; color: var(--text-muted); text-align: center; padding: 10px 0; }
  .glance-list { display: flex; flex-direction: column; gap: 4px; }
  .glance-row {
    display: flex; align-items: center; gap: 8px; padding: 7px 8px; border-radius: 10px;
    background: var(--surface-2); font-size: 12px; color: var(--text-muted);
  }
  .glance-row.is-live { background: rgba(var(--accent-rgb), 0.14); color: var(--text); box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.4); }
  .glance-row.is-done { color: var(--text-dim); }
  .glance-row-emoji { font-size: 15px; line-height: 1; flex-shrink: 0; }
  .glance-row-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; }
  .glance-row-time { font-size: 11px; font-variant-numeric: tabular-nums; color: var(--text-dim); flex-shrink: 0; }
  .glance-row-status { font-size: 12px; flex-shrink: 0; width: 14px; text-align: center; }
  .glance-row.is-done .glance-row-status { color: var(--accent); }
  .glance-row.is-live .glance-row-status { color: var(--you); }
  .glance-next {
    display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted);
    padding: 6px 8px; border-top: 1px solid var(--border); margin-top: 2px; padding-top: 10px;
  }
  .glance-next-emoji { font-size: 14px; line-height: 1; }
  .glance-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    text-align: center; gap: 4px;
  }
  .glance-empty-emoji { font-size: 40px; line-height: 1; margin-bottom: 6px; }
  .glance-empty-title { font-size: 15px; font-weight: 800; color: var(--text); }

