      /* ============================================================
       Second Brain — Journal edition
       Editorial / serif-forward · warm paper · terracotta accent
       Light + dark via html[data-theme]. Variable names kept
       backward-compatible so inline styles keep resolving.
       ============================================================ */

      *,
      *::before,
      *::after {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
      }

      :root {
        /* surfaces */
        --bg: #ffffff;
        --bg-card: #fcfbf7;
        --bg-tag: #ece8dd;
        --bg-secondary: #fcfbf7;
        --bg-confirm: rgba(253, 84, 10, 0.1);
        --bg-tag-confirmed: #fd540a;
        --surface-2: #f2efec;
        --surface-3: #e8e3df;

        /* This surface is deliberately dark in BOTH themes — it is an overlay
           chip (the toast), not a page surface, and its ink is therefore
           fixed rather than theme-flipping. --text-on-elevated on
           --surface-elevated measures 14.55:1 here. Do not point
           .app-toast-msg at --text-primary: that token flips to near-black
           in light mode, which on this near-black surface is how this
           shipped unreadable in the first place.
           --accent-on-elevated exists because --accent itself cannot be
           reused for the toast action: --accent is tuned per theme against
           each theme's own page surface (light page / dark page), but
           --surface-elevated is dark in BOTH themes, so light mode's
           --accent needs re-checking against a surface it was never tuned
           for. Here it happens to still measure 5.12:1 and clears AA, so
           this token is the current --accent value restated rather than a
           new colour. Do not consolidate the two back together: the day
           --accent moves for page-surface reasons, this one must not move
           with it. */
        --surface-elevated: #1e1e1e;
        --text-on-elevated: #f2efec;
        --accent-on-elevated: #fd540a;

        /* The knob of an on/off switch (.sb-switch). Fixed near-white in BOTH
           themes, like --text-on-elevated and for the same reason: it never
           sits on the page surface, only on a filled track — --surface-3 when
           off, --accent when on — so a theme-flipping value would go dark on
           dark the moment the switch was turned on. Defined in both blocks
           rather than reached for with a var() fallback: an undefined token
           must fail loudly, which is how the black-on-black toast shipped. */
        --switch-knob: #ffffff;

        /* ink */
        /* Ink ramp, all three steps at WCAG AA (4.5:1) against every surface
           they are set on — #ffffff through the darkest, --surface-3 #e8e3df.
           Tertiary was #96908b, which measured 2.48:1 on --surface-3 and 3.15:1
           on plain white at the 10-12px it is actually used at: timestamps,
           sources, section labels, card meta. Secondary moved down with it,
           because three passing inks live in a narrower band than two passing
           and one failing, and leaving secondary at #68635f would have put it
           within 1.1:1 of the new tertiary — a ramp with no visible steps.
           Separation is now 2.27 primary/secondary and 1.39 secondary/tertiary. */
        --text-primary: #161616;
        --text-secondary: #54504c;
        --text-tertiary: #6a6560;
        --text-tag: #68635f;
        --text-tag-confirmed: #161616;

        /* lines */
        --border: rgba(22, 22, 22, 0.09);
        --border-card: rgba(22, 22, 22, 0.075);
        --border-input: rgba(22, 22, 22, 0.11);
        --line-soft: rgba(22, 22, 22, 0.06);

        /* accent — brand orange */
        --accent: #fd540a;
        --accent-press: #a83200;
        --accent-soft: rgba(253, 84, 10, 0.09);
        --accent-ink: #c43d00;
        --good: #18794e;
        --warn: #b45309;
        --danger: #b42318;
        --danger-soft: rgba(180, 35, 24, 0.08);
        --on-accent: #161616;

        /* type — CJK faces are appended so Chinese glyphs resolve to a real
           Chinese font instead of the browser's last-resort fallback.
           PingFang SC (macOS/iOS), Microsoft YaHei (Windows), Noto Sans SC
           (Android/Linux). Latin text still renders in Geist/Lora first, so
           the original typography is preserved for English and Italian. */
        --font-serif: 'Lora', Georgia, 'Songti SC', 'SimSun', serif;
        --font-sans: 'Geist', 'Inter', system-ui, -apple-system, 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', 'Hiragino Sans GB', sans-serif;

        /* radii */
        --radius-card: 14px;
        --radius-pill: 999px;
        --radius-tag: 999px;
        --radius-bubble: 18px;

        /* elevation */
        --shadow-card: 0 1px 2px rgba(22, 22, 22, 0.05), 0 4px 14px rgba(22, 22, 22, 0.06);
        --shadow-float: 0 2px 6px rgba(22, 22, 22, 0.07), 0 14px 34px rgba(22, 22, 22, 0.12);
        --shadow-sheet: 0 -10px 44px rgba(22, 22, 22, 0.16);

        /* brand mark (S-ribbon), used to replace the brain glyph in identity spots */
        --sb-mark: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAtNTMuMzUgMjcwLjI3IDI3MC4yNyI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiNmZDU0MGE7fS5jbHMtMntmaWxsOiNmZDZmMTI7fTwvc3R5bGU+PC9kZWZzPjxnPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTS4wNCwxMDUuODNjLS4wMi40MS0uMDQuODQtLjA0LDEuMjZsLjAyLTEuMjZoLjAyWiIvPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTI2OC43NCwxNjMuNThsLTIxNS44Ny0zLjI0Yy0yOS4xNi0uNDMtNTIuNTYtMjQuMTYtNTIuODctNTMuMjJ2LS4wMmw5NS4wMywxLjQyLDE0Mi45NSw1LjY5YzUuODcsMi43MiwxMS4xMyw2LjUxLDE1LjU4LDExLjE1LDkuNiw5Ljg1LDE1LjQsMjMuMzcsMTUuMTcsMzguMjFaIi8+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMjcwLjI2LDU3LjVsLTExOS4yNS0xLjc5LTExNC41MS00LjUxQzE1Ljg1LDQzLjQ1LDEuMjYsMjMuMzksMS42MSwwbDIxNS44MSwzLjI0YzE0Ljg0LjIzLDI4LjE3LDYuNDEsMzcuNzIsMTYuMyw5LjUsOS43OSwxNS4yOSwyMy4yNSwxNS4xMywzNy45NloiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0yNzAuMjYsNTcuNXYuMjVjLS4yOSwxNC43LTYuNDcsMjcuOTctMTYuMjQsMzcuNDctNS40LDUuMjMtMTEuOTMsOS4zNi0xOS4xMSwxMS45M2gtLjA2bC04Ny44Ljg5aC0uMzFsLTUxLjU5LjQ5aC0uMTJMMCwxMDcuMTF2LS4wMmMwLS40MS4wMi0uODQuMDQtMS4yNi44Ny0yMi40NCwxNS41Mi00MS4zNiwzNS42NC00OC40OGwxMjUuMjEtMS4yNi05Ljg3LS4zOSwxMTkuMjUsMS43OVoiLz48L2c+PC9zdmc+Cg==');

        /* motion */
        --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
        --ease-spring: cubic-bezier(0.34, 1.45, 0.5, 1);
      }

      html[data-theme='dark'] {
        --bg: #161616;
        --bg-card: #221f17;
        --bg-tag: #2c2820;
        --bg-secondary: #221f17;
        --bg-confirm: rgba(253, 111, 18, 0.15);
        --bg-tag-confirmed: #fd6f12;
        --surface-2: #2c2820;
        --surface-3: #38332a;

        /* Same deliberately-dark overlay surface as the light theme, reusing
           --surface-3 so the toast still separates from --bg (#161616) — the
           flat #1e1e1e used everywhere else in this theme sits only 1.44:1
           from --bg and reads as barely distinct. --text-on-elevated on
           --surface-elevated measures 10.94:1. Ink stays fixed here for the
           same reason as light: do not swap it back to --text-primary.
           --accent itself (#fd6f12) measures only 4.4529:1 here, just under
           the 4.5:1 AA floor — dark theme's --accent was tuned against
           --bg-card and friends, not against this dark-in-both-themes
           overlay, so it cannot simply be reused. --accent-on-elevated uses
           --accent-ink instead (#ffab6e, already the theme's answer to
           "orange that needs to sit on something dark"), which measures
           6.75:1 here and clears AA with real headroom. Do not consolidate
           this back into --accent: that token is deliberate, measured work
           for the page surfaces, and rescuing one control by moving it would
           ripple through every other accent use in the product. */
        --surface-elevated: #38332a;
        --text-on-elevated: #f2efec;
        --accent-on-elevated: #ffab6e;

        /* Not #ffffff: pure white is the one ink this theme never uses, and the
           knob reads as a hole punched in the page against --bg #161616.
           #f2efec is the theme's own lightest ink, 12.5:1 on the off track
           (--surface-3) and 4.9:1 on the on track (--accent). */
        --switch-knob: #f2efec;

        --text-primary: #f2efec;
        --text-secondary: #c9c5c1;
        /* Was #8a857f: 3.43:1 on --surface-3 and 4.01:1 on --surface-2. Lifted
           to clear AA on all four dark surfaces; secondary stays put, since the
           two are still 1.61:1 apart. */
        --text-tertiary: #9f9b96;
        --text-tag: #c9c5c1;
        --text-tag-confirmed: #161616;

        --border: rgba(255, 255, 255, 0.085);
        --border-card: rgba(255, 255, 255, 0.075);
        --border-input: rgba(255, 255, 255, 0.11);
        --line-soft: rgba(255, 255, 255, 0.055);

        --accent: #fd6f12;
        --accent-press: #ff8a3d;
        --accent-soft: rgba(253, 111, 18, 0.16);
        --accent-ink: #ffab6e;
        --good: #7bae8a;
        --warn: #d9a15c;
        --danger: #d9806b;
        --danger-soft: rgba(217, 128, 107, 0.14);
        --on-accent: #161616;

        --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.32), 0 6px 18px rgba(0, 0, 0, 0.28);
        --shadow-float: 0 2px 8px rgba(0, 0, 0, 0.4), 0 16px 36px rgba(0, 0, 0, 0.5);
        --shadow-sheet: 0 -10px 44px rgba(0, 0, 0, 0.55);
      }

      html,
      body {
        height: 100%;
        background: var(--bg);
        font-family: var(--font-sans);
        color: var(--text-primary);
        -webkit-font-smoothing: antialiased;
        text-rendering: optimizeLegibility;
        overflow: hidden;
      }

      body {
        transition: background 0.45s var(--ease);
      }

      i.ti {
        line-height: 1;
      }

      ::selection {
        background: var(--accent-soft);
      }

      #app {
        display: flex;
        flex-direction: column;
        height: 100svh;
        width: 100%;
        max-width: 440px;
        margin: 0 auto;
        background: var(--bg);
        position: relative;
      }

      #sidebar {
        display: none;
      }

      #main-panel {
        flex: 1;
        display: flex;
        flex-direction: column;
        min-width: 0;
        overflow: hidden;
      }

      /* ============ AUTH ============ */
      #auth-overlay {
        position: fixed;
        inset: 0;
        background: var(--bg);
        z-index: 100;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        width: 100%;
        animation: fade-in 0.5s var(--ease);
      }

      @keyframes fade-in {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }

      .auth-card {
        width: 100%;
        max-width: 400px;
        padding: 40px 32px;
        display: flex;
        flex-direction: column;
        align-items: center;
      }

      .auth-link {
        background: none;
        border: none;
        padding: 10px 0 0;
        min-height: 32px;
        font-family: var(--font-sans);
        font-size: 13px;
        color: var(--text-secondary);
        text-decoration: underline;
        cursor: pointer;
      }
      .auth-invite-help {
        margin-top: 6px;
        font-size: 13px;
        line-height: 1.55;
        color: var(--text-secondary);
      }
      .auth-invite-help ol {
        margin: 0;
        padding-left: 18px;
      }
      .auth-invite-help li {
        margin-bottom: 6px;
      }

      #auth-overlay .brain-logo {
        width: 70px;
        height: 70px;
        border-radius: 50%;
        background: var(--accent-soft);
        color: var(--accent);
        display: flex;
        align-items: center;
        justify-content: center;
        margin-bottom: 24px;
        position: relative;
      }

      #auth-overlay .brain-logo i {
        font-size: 33px;
      }

      #auth-overlay .brain-logo::after {
        content: '';
        position: absolute;
        inset: -7px;
        border-radius: 50%;
        border: 1px solid var(--accent-soft);
      }

      #auth-overlay h1 {
        font-family: var(--font-serif);
        font-size: 29px;
        font-weight: 500;
        color: var(--text-primary);
        margin-bottom: 9px;
        letter-spacing: -0.015em;
      }

      #auth-overlay p {
        font-size: 14px;
        color: var(--text-secondary);
        margin-bottom: 34px;
        text-align: center;
        line-height: 1.6;
        max-width: 300px;
      }

      #auth-overlay .field-group {
        width: 100%;
        display: flex;
        flex-direction: column;
        gap: 11px;
        margin-bottom: 14px;
      }

      #auth-overlay input {
        width: 100%;
        padding: 14px 16px;
        background: var(--bg-card);
        border: 0.5px solid var(--border-input);
        border-radius: 13px;
        font-family: var(--font-sans);
        font-size: 15px;
        color: var(--text-primary);
        outline: none;
        transition:
          border-color 0.18s,
          box-shadow 0.18s;
      }

      #auth-overlay input::placeholder {
        color: var(--text-tertiary);
      }

      #auth-overlay input:focus {
        border-color: var(--accent);
        box-shadow: 0 0 0 3px var(--accent-soft);
      }

      #auth-connect {
        width: 100%;
        padding: 15px;
        background: var(--accent);
        color: var(--on-accent);
        border: none;
        border-radius: 13px;
        font-family: var(--font-sans);
        font-size: 15px;
        font-weight: 600;
        cursor: pointer;
        transition:
          background 0.18s,
          transform 0.12s var(--ease);
      }

      #auth-connect:hover {
        background: var(--accent-press);
      }

      #auth-connect:active {
        transform: scale(0.985);
      }

      #auth-error {
        font-size: 13px;
        color: var(--danger);
        text-align: center;
        margin-top: 10px;
        min-height: 18px;
      }

      /* ============ TOP BAR ============ */
      #topbar {
        display: flex;
        align-items: center;
        gap: 11px;
        padding: 14px 18px 12px;
        background: var(--bg);
        flex-shrink: 0;
        position: relative;
        z-index: 10;
      }

      .brain-avatar {
        width: 36px;
        height: 36px;
        border-radius: 50%;
        background: var(--accent-soft);
        color: var(--accent);
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
      }

      .brain-avatar i {
        font-size: 20px;
      }

      /* identity spots render the brand mark instead of the icon-font glyph */
      .brain-avatar i.ti-brain,
      #auth-overlay .brain-logo i.ti-brain {
        font-size: 0;
        width: 62%;
        height: 62%;
        background-color: var(--accent);
        mask: var(--sb-mark) center / contain no-repeat;
        -webkit-mask: var(--sb-mark) center / contain no-repeat;
      }
      .brain-avatar i.ti-brain::before,
      #auth-overlay .brain-logo i.ti-brain::before {
        content: none;
      }

      .topbar-info {
        flex: 1;
        min-width: 0;
      }

      .topbar-name {
        font-family: var(--font-serif);
        font-size: 18px;
        font-weight: 500;
        color: var(--text-primary);
        line-height: 1.15;
        letter-spacing: -0.01em;
      }

      .topbar-status {
        font-size: 11.5px;
        color: var(--text-secondary);
        line-height: 1.3;
        margin-top: 1px;
        display: flex;
        align-items: center;
        gap: 6px;
      }

      .topbar-status::before {
        content: '';
        width: 5px;
        height: 5px;
        border-radius: 50%;
        background: var(--good);
        flex-shrink: 0;
      }

      .topbar-menu {
        background: none;
        border: none;
        cursor: pointer;
        color: var(--text-secondary);
        width: 38px;
        height: 38px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        transition:
          background 0.15s,
          color 0.15s;
      }

      .topbar-menu i {
        font-size: 22px;
      }

      .topbar-menu:hover {
        background: var(--surface-2);
        color: var(--text-primary);
      }

      /* ============ SCREENS ============ */
      #screens {
        flex: 1;
        overflow: hidden;
        position: relative;
      }

      .screen {
        display: none;
        flex-direction: column;
        height: 100%;
        position: absolute;
        inset: 0;
      }

      .screen.active {
        display: flex;
        animation: screen-in 0.34s var(--ease);
      }

      @keyframes screen-in {
        from {
          transform: translateY(8px);
        }
        to {
          transform: none;
        }
      }

      #recall-messages {
        flex: 1;
        overflow-y: auto;
        overflow-x: hidden;
        padding: 16px 18px 8px;
        display: flex;
        flex-direction: column;
        gap: 10px;
        -webkit-overflow-scrolling: touch;
        scroll-behavior: smooth;
      }

      /* ============ BOTTOM NAV ============ */
      #navbar {
        display: flex;
        border-top: 0.5px solid var(--border);
        background: var(--bg);
        flex-shrink: 0;
        padding: 9px 8px calc(16px + env(safe-area-inset-bottom));
      }

      .nav-tab {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 4px;
        background: none;
        border: none;
        cursor: pointer;
        padding: 6px 0;
        color: var(--text-tertiary);
        transition: color 0.2s var(--ease);
      }

      .nav-tab i {
        font-size: 22px;
        transition: transform 0.32s var(--ease-spring);
      }

      .nav-tab span {
        font-family: var(--font-serif);
        font-size: 11.5px;
        letter-spacing: 0.005em;
      }

      .nav-tab.active {
        color: var(--accent-ink);
      }

      .nav-tab.active i {
        transform: translateY(-1px);
      }

      .nav-tab:active i {
        transform: scale(0.84);
      }

      /* ============ CHAT BUBBLES ============ */
      .bubble-row {
        display: flex;
        animation: bubble-in 0.36s var(--ease) both;
      }

      .bubble-row.user {
        justify-content: flex-end;
      }

      .bubble-row.brain {
        justify-content: flex-start;
      }

      @keyframes bubble-in {
        from {
          transform: translateY(9px);
        }
        to {
          transform: none;
        }
      }

      .bubble {
        max-width: 84%;
        padding: 11px 15px;
        border-radius: var(--radius-bubble);
        font-size: 14px;
        line-height: 1.5;
        word-wrap: break-word;
      }

      .bubble.user {
        background: var(--text-primary);
        color: var(--bg);
        border-bottom-right-radius: 6px;
      }

      .bubble.user .hashtag {
        color: color-mix(in srgb, var(--bg) 68%, var(--accent));
      }

      .bubble.brain {
        background: var(--bg-card);
        color: var(--text-primary);
        border: 0.5px solid var(--border-card);
        border-bottom-left-radius: 6px;
        box-shadow: var(--shadow-card);
      }

      /* Journal serif voice — AI answers + welcome lines */
      .bubble.brain.answer,
      .bubble.brain.voice {
        font-family: var(--font-serif);
        font-size: 16.5px;
        line-height: 1.6;
        letter-spacing: -0.003em;
        padding: 14px 17px;
        max-width: 90%;
      }

      .bubble.brain.answer strong,
      .bubble.brain.voice strong {
        color: var(--accent-ink);
        font-weight: 600;
      }

      .bubble.brain.answer em {
        color: var(--accent-ink);
      }

      .hashtag {
        color: var(--accent-ink);
        font-weight: 500;
      }

      .bubble-time {
        font-size: 11px;
        color: var(--text-tertiary);
        padding: 0 6px;
        margin-top: 4px;
        text-align: right;
      }

      .bubble-row.user > div {
        display: flex;
        flex-direction: column;
        align-items: flex-end;
        max-width: 84%;
      }

      /* loading dots */
      .loading-dots {
        display: flex;
        gap: 6px;
        padding: 16px 2px;
        background: transparent;
        border: none;
        border-radius: 0;
        width: fit-content;
        box-shadow: none;
      }

      .loading-dots span {
        width: 7px;
        height: 7px;
        border-radius: 50%;
        background: var(--text-tertiary);
        animation: bounce 1.3s infinite ease-in-out;
      }

      .loading-dots span:nth-child(2) {
        animation-delay: 0.16s;
      }
      .loading-dots span:nth-child(3) {
        animation-delay: 0.32s;
      }

      @keyframes bounce {
        0%,
        80%,
        100% {
          transform: scale(0.7);
          opacity: 0.4;
        }
        40% {
          transform: scale(1);
          opacity: 1;
        }
      }

      .brain-cards-wrapper {
        display: flex;
        flex-direction: column;
        gap: 9px;
      }

      #recall-welcome {
        gap: 10px;
      }

      /* ============================================================
       JOURNAL EDITORIAL — the conversation reads as prose
       ============================================================ */
      #recall-messages {
        gap: 0;
        padding: 20px 20px 10px;
      }

      /* opening hero */
      .recall-hero {
        padding: 6px 0 2px;
        animation: bubble-in 0.4s var(--ease) both;
      }

      .recall-hero .eyebrow {
        font-size: 11px;
        letter-spacing: 0.14em;
        text-transform: uppercase;
        color: var(--accent-ink);
        margin-bottom: 13px;
      }

      .recall-hero .hero-line {
        font-family: var(--font-serif);
        font-size: 23px;
        line-height: 1.42;
        letter-spacing: -0.012em;
        color: var(--text-primary);
        max-width: 22em;
      }

      .recall-hero .hero-line .hashtag {
        color: var(--accent-ink);
      }

      /* a recall exchange: uppercase question label + large serif answer */
      .ex-q {
        display: flex;
        gap: 8px;
        align-items: baseline;
        flex-wrap: wrap;
        font-size: 11px;
        letter-spacing: 0.13em;
        text-transform: uppercase;
        color: var(--accent-ink);
        padding: 24px 0 13px;
        border-top: 0.5px solid var(--line-soft);
        animation: bubble-in 0.36s var(--ease) both;
      }

      #recall-messages > .ex-q:first-child {
        border-top: none;
        padding-top: 6px;
      }

      .ex-q .q-dash {
        opacity: 0.5;
      }

      .ex-q .q-text {
        color: var(--text-secondary);
        letter-spacing: 0.03em;
        font-weight: 500;
      }

      .ex-a {
        font-family: var(--font-serif);
        font-size: 19px;
        line-height: 1.58;
        letter-spacing: -0.004em;
        color: var(--text-primary);
        animation: bubble-in 0.36s var(--ease) both;
      }

      .ex-a strong {
        color: var(--accent-ink);
        font-weight: 600;
      }
      .ex-a em {
        color: var(--accent-ink);
        font-style: italic;
      }

      .ex-a > *:first-child {
        margin-top: 0;
      }
      .ex-a > *:last-child {
        margin-bottom: 0;
      }
      .ex-a p {
        margin: 0 0 0.7em;
      }
      .ex-a p:last-child {
        margin-bottom: 0;
      }

      .ex-a h3,
      .ex-a h4 {
        font-family: var(--font-serif);
        font-weight: 600;
        color: var(--text-primary);
        letter-spacing: -0.01em;
        line-height: 1.3;
        margin: 1.1em 0 0.45em;
      }
      .ex-a h3 {
        font-size: 0.92em;
      }
      .ex-a h4 {
        font-size: 0.66em;
        font-weight: 600;
        font-style: normal;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: var(--accent-ink);
        font-family: var(--font-sans);
      }

      .ex-a ul,
      .ex-a ol {
        margin: 0.55em 0 0.8em;
        padding: 0;
        list-style: none;
        counter-reset: exli;
      }
      .ex-a li {
        position: relative;
        padding-left: 1.3em;
        margin-bottom: 0.42em;
        line-height: 1.5;
      }
      .ex-a li:last-child {
        margin-bottom: 0;
      }
      .ex-a ul > li::before {
        content: '';
        position: absolute;
        left: 0.15em;
        top: 0.62em;
        width: 5px;
        height: 5px;
        border-radius: 50%;
        background: var(--accent);
      }
      .ex-a ol > li {
        counter-increment: exli;
      }
      .ex-a ol > li::before {
        content: counter(exli);
        position: absolute;
        left: 0;
        top: 0.04em;
        font-family: var(--font-serif);
        font-style: italic;
        font-size: 0.82em;
        color: var(--accent-ink);
        font-variant-numeric: tabular-nums;
      }
      .ex-a code {
        font-family: ui-monospace, 'SF Mono', Menlo, monospace;
        font-size: 0.82em;
        background: var(--surface-2);
        padding: 0.1em 0.4em;
        border-radius: 5px;
      }

      /* system note (no result / error) */
      .recall-sys {
        font-family: var(--font-serif);
        font-style: italic;
        font-size: 18px;
        line-height: 1.55;
        color: var(--text-secondary);
        padding: 24px 0 0;
        border-top: 0.5px solid var(--line-soft);
        animation: bubble-in 0.36s var(--ease) both;
      }

      /* sources, sitting under an answer */
      .ex-a + .sources-toggle,
      .sources-toggle {
        margin-top: 16px;
      }

      /* ---- Remember: editorial capture notes ---- */
      .capture-note {
        position: relative;
        font-family: var(--font-serif);
        font-size: 18px;
        line-height: 1.5;
        color: var(--text-primary);
        padding: 22px 0 4px 16px;
        border-top: 0.5px solid var(--line-soft);
        animation: bubble-in 0.36s var(--ease) both;
      }

      .capture-note::before {
        content: '';
        position: absolute;
        left: 0;
        top: 24px;
        bottom: 11px;
        width: 2px;
        background: var(--accent);
        border-radius: 2px;
      }

      .capture-note .hashtag {
        font-family: var(--font-sans);
        font-size: 13.5px;
        vertical-align: 1px;
      }

      .sys-note {
        font-family: var(--font-serif);
        font-style: italic;
        font-size: 13px;
        color: var(--text-tertiary);
        padding: 8px 0 4px 16px;
        animation: bubble-in 0.36s var(--ease) both;
      }

      /* ---- underline "writing" input ---- */
      #screen-home .input-inner {
        background: transparent;
        border: none;
        border-bottom: 1.5px solid var(--accent);
        border-radius: 0;
        padding: 4px 2px 9px;
        margin: 0 4px;
        box-shadow: none;
        align-items: flex-end;
        gap: 10px;
      }

      #screen-home .input-inner:focus-within {
        box-shadow: none;
        border-bottom-color: var(--accent-press);
      }

      #screen-home .input-field {
        font-family: var(--font-serif);
        font-size: 16.5px;
        padding: 6px 0;
      }

      #screen-home .input-field::placeholder {
        font-style: italic;
        color: var(--text-tertiary);
      }

      #screen-home .send-btn {
        background: transparent;
        width: auto;
        height: auto;
        padding: 4px;
      }

      #screen-home .send-btn:hover {
        background: transparent;
        transform: translateY(-1px);
      }

      #screen-home .send-btn i {
        font-size: 23px;
        color: var(--accent);
      }

      #screen-home .send-btn:disabled {
        opacity: 0.4;
      }

      /* sources toggle */
      .sources-toggle {
        display: flex;
        flex-direction: column;
        gap: 9px;
        animation: bubble-in 0.36s var(--ease) both;
      }

      .sources-toggle > button {
        display: inline-flex;
        align-items: center;
        gap: 7px;
        align-self: flex-start;
        background: none;
        border: none;
        cursor: pointer;
        color: var(--text-secondary);
        font-family: var(--font-sans);
        font-size: 12px;
        padding: 3px 2px;
        transition: color 0.15s;
      }

      .sources-toggle > button i {
        font-size: 15px;
        color: var(--accent);
      }

      .sources-toggle > button:hover {
        color: var(--text-primary);
      }

      /* ============ MEMORY CARD (recall sources) ============ */
      .memory-card {
        background: var(--bg-card);
        border: 0.5px solid var(--border-card);
        border-radius: var(--radius-card);
        padding: 12px 14px;
        box-shadow: var(--shadow-card);
        transition:
          transform 0.25s var(--ease),
          box-shadow 0.25s var(--ease),
          opacity 0.3s;
        animation: card-in 0.42s var(--ease) both;
      }

      @keyframes card-in {
        from {
          transform: translateY(8px);
        }
        to {
          transform: none;
        }
      }

      .memory-card:hover {
        box-shadow: var(--shadow-float);
      }

      .memory-card.card--rolled-up {
        opacity: 0.65;
      }

      /* Dashed rather than tinted, so it reads as provisional next to
         card--synthesized without touching the card background — which also
         matches how the other card modifiers signal state.

         This once carried a second reason: --text-tertiary sat below WCAG AA on
         --bg-card in both themes, so a tint in either direction pushed one of
         them further down and there was no headroom to spend. That was true of
         tinting THIS card while the token stayed where it was; the token has
         since moved, and both themes now clear AA on every surface. The border
         stays because the first reason still holds. */
      .memory-card.card--stale {
        border-left: 3px dashed var(--warn);
      }

      .memory-card.card--synthesized {
        border-left: 3px solid var(--accent);
      }

      .tag-chip.tag-chip--synthesized {
        background: var(--accent);
        color: var(--on-accent);
        font-weight: 500;
      }

      .vec-chip {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        font-size: 11px;
        padding: 3px 8px;
        border-radius: var(--radius-tag);
        white-space: nowrap;
      }
      .vec-chip--on {
        background: var(--accent-soft);
        color: var(--accent-ink);
      }
      .vec-chip--pending {
        background: var(--surface-2);
        color: var(--text-tag);
      }
      .vec-chip--off {
        background: color-mix(in srgb, var(--danger) 15%, transparent);
        color: var(--danger);
        font-weight: 500;
      }

      .match-line {
        display: flex;
        align-items: center;
        gap: 9px;
        margin-bottom: 9px;
      }

      .match-pct {
        font-size: 10.5px;
        color: var(--accent-ink);
        font-weight: 600;
        font-variant-numeric: tabular-nums;
        flex-shrink: 0;
      }

      .match-bar-bg {
        flex: 1;
        height: 3px;
        background: var(--surface-2);
        border-radius: 2px;
        overflow: hidden;
      }

      .match-bar-fill {
        height: 100%;
        background: var(--accent);
        border-radius: 2px;
        transform-origin: left;
        animation: bar-grow 0.65s var(--ease) both;
      }

      @keyframes bar-grow {
        from {
          transform: scaleX(0);
        }
        to {
          transform: scaleX(1);
        }
      }

      .card-content {
        font-size: 14px;
        color: var(--text-primary);
        line-height: 1.55;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
      }

      .card-footer {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 10px;
        margin-top: 11px;
      }

      .card-tags {
        display: flex;
        flex-wrap: wrap;
        gap: 6px;
        min-width: 0;
      }

      .tag-chip {
        background: var(--surface-2);
        color: var(--text-tag);
        font-size: 11px;
        padding: 3px 10px;
        border-radius: var(--radius-tag);
        white-space: nowrap;
        font-family: var(--font-sans);
      }

      /* Accent-toned chips. Both were inline styles setting `color: var(--accent)`
         on --surface-2 — 2.84:1 at 11px, the least legible thing on the Memories
         screen and, being inline, invisible to the token that fixed the rest.
         --accent-ink is the same hue at AA. */
      .tag-chip--shared {
        color: var(--accent-ink);
        border-color: var(--accent-ink);
      }

      .tag-chip--hop {
        background: var(--accent-soft);
        color: var(--accent-ink);
        flex-shrink: 0;
      }

      .card-tags .tag-chip:first-child {
        background: var(--accent-soft);
        color: var(--accent-ink);
      }

      .card-actions {
        display: flex;
        gap: 4px;
        flex-shrink: 0;
      }

      .card-action-btn {
        background: none;
        border: none;
        cursor: pointer;
        color: var(--text-secondary);
        font-size: 11px;
        font-family: var(--font-sans);
        display: flex;
        align-items: center;
        gap: 4px;
        padding: 5px 7px;
        border-radius: 8px;
        transition:
          background 0.15s,
          color 0.15s;
      }

      .card-action-btn:hover {
        background: var(--surface-2);
        color: var(--text-primary);
      }

      .card-action-btn i {
        font-size: 14px;
      }

      /* ============ RECENT — numbered editorial list ============ */
      #recent-list {
        flex: 1;
        overflow-y: auto;
        /* The last row used to stop 8px above whatever follows — the tab bar on
           a phone, the panel edge on a desktop — which reads as the list being
           cut off rather than ended. */
        padding: 14px 18px 22px;
        counter-reset: memo;
        -webkit-overflow-scrolling: touch;
      }

      .date-group {
        margin-bottom: 22px;
      }

      .date-label {
        font-family: var(--font-serif);
        font-style: italic;
        font-weight: 400;
        font-size: 15px;
        color: var(--text-secondary);
        margin: 0 2px 6px;
        letter-spacing: 0;
      }

      #recent-list .recent-cards {
        display: flex;
        flex-direction: column;
        gap: 0;
      }

      /* recent rows: strip the card chrome, become editorial entries */
      #recent-list .memory-card {
        background: transparent;
        border: none;
        border-top: 0.5px solid var(--line-soft);
        border-radius: 0;
        box-shadow: none;
        padding: 14px 2px 14px 34px;
        position: relative;
        counter-increment: memo;
      }

      #recent-list .memory-card:first-child {
        border-top: none;
      }

      #recent-list .memory-card::before {
        content: counter(memo, decimal-leading-zero);
        position: absolute;
        left: 2px;
        top: 15px;
        font-family: var(--font-serif);
        font-style: italic;
        font-size: 13px;
        color: var(--accent-ink);
        font-variant-numeric: tabular-nums;
      }

      #recent-list .memory-card:hover {
        box-shadow: none;
      }

      #recent-list .card-content {
        font-size: 14.5px;
        line-height: 1.5;
      }

      #recent-list .card-footer {
        margin-top: 8px;
      }

      /* ── The memory is the hero ───────────────────────────────────────────
         Measured before this block: a card was 158px tall and its content was
         46px of that — the memory occupied 29% of its own card, and five of
         them fitted on a phone holding 2,394. The other 112px was chrome:
         three stacked bands (a meta line, a tag row forced onto its own line by
         `flex: 1 0 100%`, and a 44px action row) all competing at the same
         visual weight.

         The bands collapse into ONE quiet line — source, time, tags and the
         actions share a row and truncate rather than stack — and the content
         keeps everything that buys back. */
      #recent-list .card-footer {
        margin-top: 8px;
        gap: 10px;
        flex-wrap: nowrap;
      }

      /* Reading order on the line: where it came from and when, then what it is
         about, then what you can do to it. Provenance first because it is the
         thing that orients you in a list of 2,394. */
      #recent-list .card-meta {
        margin-bottom: 0;
        flex-shrink: 0;
        order: 0;
      }

      /* `flex: 1 0 100%` is what pushed the tags onto a line of their own. They
         share the meta line now and scroll within it, as they already did. */
      #recent-list .card-tags {
        order: 1;
        flex: 1 1 auto;
        min-width: 0;
      }

      #recent-list .card-actions {
        order: 2;
        margin-left: auto;
        flex-shrink: 0;
      }

      /* 44px was well past the 32px this project holds itself to, and it set the
         height of the whole line: three of these were the tallest thing in the
         footer on every card in the list. */
      #recent-list .card-action-btn {
        min-height: 32px;
        padding-top: 0;
        padding-bottom: 0;
      }

      #recent-list .card-action-btn {
        padding: 4px 6px;
        font-size: 10.5px;
        color: var(--text-tertiary);
      }

      #recent-list .card-action-btn:hover {
        color: var(--text-primary);
      }

      /* ============ FILTER BAR ============ */
      .filter-bar {
        padding: 8px 18px 10px;
        flex-shrink: 0;
        background: var(--bg);
      }

      /* ── v2.3 Memories: one corpus, two projections ──────────────────────
         Filters sit above the list they narrow. They used to be pinned to the
         bottom, so scanning top-down and deciding to narrow meant travelling to
         the far end of the screen and back. */
      .mem-bar {
        display: flex;
        align-items: center;
        gap: 10px;
        padding: 10px 18px;
        flex-shrink: 0;
        background: var(--bg);
        border-bottom: 0.5px solid var(--border);
      }

      /* Grows to fill a phone, stops well short of it on a wide window — two
         dropdowns stretched across 1,300px read as a form, not a filter. */
      .mem-filters {
        flex: 1;
        min-width: 0;
        max-width: 420px;
      }

      .mem-filters[hidden],
      #mem-legend[hidden] {
        display: none;
      }

      #mem-legend {
        flex: 1;
        min-width: 0;
      }

      .mem-caption {
        font-size: 12.5px;
        color: var(--text-tertiary);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .view-toggle {
        display: flex;
        gap: 2px;
        padding: 2px;
        background: var(--surface-2);
        border-radius: var(--radius-pill);
        flex-shrink: 0;
        /* Pinned right in both views. Capping the filters at 420px stopped them
           filling the bar, which left the toggle stranded mid-row in list view
           while graph view — whose caption does stretch — kept it at the edge. */
        margin-left: auto;
      }

      .view-toggle-btn {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        padding: 6px 12px;
        border: none;
        background: none;
        border-radius: var(--radius-pill);
        cursor: pointer;
        color: var(--text-secondary);
        font-family: var(--font-sans);
        font-size: 13px;
        transition:
          background 0.15s,
          color 0.15s;
      }

      .view-toggle-btn i {
        font-size: 16px;
      }

      .view-toggle-btn.active {
        background: var(--bg-card);
        color: var(--text-primary);
        box-shadow: var(--shadow-card);
      }

      #recent-list[hidden] {
        display: none;
      }

      .filter-inner {
        display: flex;
        align-items: center;
        background: var(--bg-card);
        border: 0.5px solid var(--border-input);
        border-radius: var(--radius-pill);
        padding: 7px 8px 7px 14px;
        gap: 8px;
        box-shadow: var(--shadow-card);
      }

      .filter-field {
        flex: 1;
        background: none;
        border: none;
        outline: none;
        font-family: var(--font-sans);
        font-size: 13px;
        color: var(--text-secondary);
        min-width: 0;
      }

      .filter-field::placeholder {
        color: var(--text-tertiary);
      }

      select.filter-field {
        cursor: pointer;
        -webkit-appearance: none;
        appearance: none;
      }

      select.filter-field option {
        color: #161616;
        background: #fcfbf7;
      }

      .refresh-btn {
        width: 30px;
        height: 30px;
        border-radius: 50%;
        background: var(--surface-2);
        border: none;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
        color: var(--text-secondary);
        transition:
          background 0.15s,
          color 0.15s;
      }

      .refresh-btn i {
        font-size: 15px;
      }

      .refresh-btn:hover {
        background: var(--surface-3);
        color: var(--text-primary);
      }

      .refresh-btn.spinning i,
      .refresh-now.spinning i {
        animation: spin 0.7s linear infinite;
      }

      @keyframes spin {
        to {
          transform: rotate(360deg);
        }
      }

      /* ============ SUGGESTIONS ============ */
      .suggestions-row {
        display: flex;
        gap: 8px;
        overflow-x: auto;
        padding: 6px 18px 6px;
        flex-shrink: 0;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
      }

      .suggestions-row::-webkit-scrollbar {
        display: none;
      }

      .suggestion-pill {
        background: var(--bg-card);
        border: 0.5px solid var(--border-input);
        color: var(--text-secondary);
        font-size: 12.5px;
        padding: 7px 14px;
        border-radius: var(--radius-pill);
        white-space: nowrap;
        cursor: pointer;
        font-family: var(--font-sans);
        flex-shrink: 0;
        transition:
          background 0.15s,
          color 0.15s,
          border-color 0.15s;
      }

      .suggestion-pill:hover {
        background: var(--accent-soft);
        border-color: transparent;
        color: var(--accent-ink);
      }

      /* ============ INPUT BAR ============ */
      .input-bar {
        padding: 8px 18px calc(12px + env(safe-area-inset-bottom));
        flex-shrink: 0;
        background: var(--bg);
      }

      .input-inner {
        display: flex;
        align-items: flex-end;
        background: var(--bg-card);
        border: 0.5px solid var(--border-input);
        border-radius: 24px;
        padding: 6px 6px 6px 16px;
        gap: 8px;
        box-shadow: var(--shadow-card);
        transition:
          border-color 0.18s,
          box-shadow 0.18s;
      }

      .input-inner:focus-within {
        border-color: var(--accent);
        box-shadow: 0 0 0 3px var(--accent-soft);
      }

      .input-field {
        flex: 1;
        background: none;
        border: none;
        outline: none;
        font-family: var(--font-sans);
        font-size: 14.5px;
        color: var(--text-primary);
        resize: none;
        line-height: 1.45;
        padding: 7px 0;
        max-height: 80px;
        overflow-y: auto;
      }

      .input-field::placeholder {
        color: var(--text-tertiary);
      }

      .send-btn {
        width: 36px;
        height: 36px;
        border-radius: 50%;
        background: var(--accent);
        border: none;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
        transition:
          background 0.18s,
          transform 0.14s var(--ease-spring);
      }

      .send-btn:hover {
        background: var(--accent-press);
      }

      .send-btn:active {
        transform: scale(0.88);
      }

      .send-btn i {
        font-size: 18px;
        color: var(--on-accent);
      }

      .send-btn:disabled {
        opacity: 0.45;
        cursor: default;
      }

      .input-hint {
        font-size: 11.5px;
        color: var(--text-tertiary);
        padding: 0 4px 8px;
      }

      .input-hint .hint-tags {
        color: var(--accent-ink);
        font-weight: 500;
      }

      /* ============ CONFIRM BLOCK (remember) ============ */
      .confirm-block {
        background: var(--bg-confirm);
        border-radius: var(--radius-card);
        padding: 11px 14px;
        display: flex;
        flex-direction: column;
        gap: 8px;
        align-self: flex-start;
        max-width: 84%;
        animation: bubble-in 0.36s var(--ease) both;
      }

      .confirm-line {
        display: flex;
        align-items: center;
        gap: 7px;
        font-size: 12.5px;
        color: var(--accent-ink);
        font-weight: 500;
      }

      .confirm-line i {
        font-size: 16px;
        color: var(--accent);
      }

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

      .confirm-tag {
        background: var(--bg-tag-confirmed);
        color: var(--text-tag-confirmed);
        font-size: 11px;
        padding: 3px 10px;
        border-radius: var(--radius-tag);
        font-family: var(--font-sans);
      }

      /* ============ EMPTY STATE ============ */
      .empty-state {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 56px 32px;
        gap: 10px;
        color: var(--text-tertiary);
        font-family: var(--font-serif);
        font-style: italic;
        font-size: 15px;
        line-height: 1.5;
        text-align: center;
        height: 100%;
      }

      .empty-state i {
        font-size: 34px;
        margin-bottom: 4px;
        font-style: normal;
        color: var(--text-tertiary);
      }

      .first-run-steps {
        margin: 14px 0 0;
        padding-left: 20px;
        text-align: left;
        font-family: var(--font-sans);
        font-style: normal;
        font-size: 14px;
        line-height: 1.65;
        color: var(--text-secondary);
        max-width: 460px;
      }

      .first-run-steps li {
        margin-bottom: 8px;
      }

      /* ============ BOTTOM SHEETS ============ */
      #confirm-dialog,
      #append-sheet,
      #edit-sheet,
      #menu-sheet,
      #integrations-sheet,
      #patterns-sheet,
      #stale-sheet,
      #view-sheet {
        display: none;
        position: fixed;
        inset: 0;
        z-index: 50;
        background: rgba(20, 18, 13, 0.42);
        align-items: flex-end;
        justify-content: center;
        opacity: 0;
        transition: opacity 0.28s var(--ease);
        -webkit-backdrop-filter: blur(2px);
        backdrop-filter: blur(2px);
      }

      /* Action modals paint above the surface that launched them.
         Everything above shares one z-index, so which overlay wins was decided
         by document order — fine while no sheet could open another. The
         out-of-date queue is the first that can: Edit, Append and Forget all
         launch from inside it and all three are declared earlier in index.html,
         so they opened BEHIND it. On a phone that is indistinguishable from the
         tap doing nothing — the sheet does not move, no dialog appears, and the
         confirm is found waiting underneath only after closing the queue.
         Reordering the markup would fix this instance and break on the next
         sheet added below them; the layer is what is actually meant. */
      #confirm-dialog,
      #append-sheet,
      #edit-sheet {
        z-index: 60;
      }

      #confirm-dialog.open,
      #append-sheet.open,
      #edit-sheet.open,
      #menu-sheet.open,
      #integrations-sheet.open,
      #patterns-sheet.open,
      #stale-sheet.open,
      #view-sheet.open {
        display: flex;
        opacity: 1;
      }

      .confirm-sheet,
      .append-inner,
      .edit-inner,
      .menu-inner,
      .view-inner {
        background: var(--bg);
        border-radius: 24px 24px 0 0;
        width: 100%;
        max-width: 440px;
        box-shadow: var(--shadow-sheet);
        transform: translateY(100%);
        transition: transform 0.34s var(--ease);
      }

      .open .confirm-sheet,
      .open .append-inner,
      .open .edit-inner,
      .open .menu-inner,
      .open .view-inner {
        transform: translateY(0);
      }

      .confirm-sheet {
        padding: 26px 24px calc(34px + env(safe-area-inset-bottom));
      }
      .append-inner {
        padding: 24px 22px calc(34px + env(safe-area-inset-bottom));
      }
      .edit-inner {
        padding: 24px 22px calc(34px + env(safe-area-inset-bottom));
      }
      .menu-inner {
        padding: 24px 22px calc(34px + env(safe-area-inset-bottom));
        max-height: 80vh;
        overflow-y: auto;
      }

      .view-inner {
        padding: 22px 22px calc(34px + env(safe-area-inset-bottom));
        display: flex;
        flex-direction: column;
        max-height: 90vh;
      }

      .confirm-sheet h3,
      .append-inner h3,
      .edit-inner h3,
      .menu-inner h3,
      .view-header h3 {
        font-family: var(--font-serif);
        font-size: 21px;
        font-weight: 500;
        margin-bottom: 9px;
        letter-spacing: -0.01em;
        color: var(--text-primary);
      }

      .confirm-sheet p {
        font-size: 14px;
        color: var(--text-secondary);
        margin-bottom: 22px;
        line-height: 1.55;
      }

      /* The sheet's optional modifier — "and also delete the memories". A full
         32px row because the whole label is the tap target, and secondary ink
         because it is a qualifier on the question above, not the question. */
      .confirm-check {
        display: flex;
        align-items: center;
        gap: 9px;
        font-size: 13.5px;
        color: var(--text-secondary);
        margin-bottom: 18px;
        min-height: 32px;
        cursor: pointer;
      }

      .view-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 14px;
        flex-shrink: 0;
      }

      .btn-close-icon {
        background: var(--surface-2);
        border: none;
        color: var(--text-secondary);
        width: 32px;
        height: 32px;
        border-radius: 50%;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: background 0.15s;
      }

      .btn-close-icon i {
        font-size: 18px;
      }
      .btn-close-icon:hover {
        background: var(--surface-3);
      }

      .view-content {
        font-family: var(--font-serif);
        font-size: 17px;
        color: var(--text-primary);
        line-height: 1.62;
        overflow-y: auto;
        margin-bottom: 18px;
        white-space: pre-wrap;
        /* pre-wrap wraps at spaces but will not break a long unbroken token, so
           one file path or URL pushed the whole sheet sideways and the text
           scrolled off the left edge on a phone. */
        overflow-wrap: anywhere;
        word-break: break-word;
      }

      .view-tags {
        display: flex;
        flex-wrap: wrap;
        gap: 6px;
        margin-bottom: 22px;
        flex-shrink: 0;
      }

      .view-actions {
        display: flex;
        gap: 8px;
        flex-shrink: 0;
        /* Separated from the scrolling region above rather than pushed down by
           margin-top:auto, which did nothing once the content overflowed. The
           rule is not decoration: a long memory scrolls underneath this row, and
           without it the text simply stopped mid-sentence at the buttons with
           nothing saying the rest was still there. */
        padding-top: 14px;
        border-top: 0.5px solid var(--border);
      }

      .btn-view-append,
      .btn-view-edit,
      .btn-view-forget {
        flex: 1;
        padding: 13px;
        border: none;
        border-radius: 13px;
        font-family: var(--font-sans);
        font-size: 13.5px;
        font-weight: 500;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
        background: var(--surface-2);
        color: var(--text-primary);
        transition:
          background 0.15s,
          color 0.15s;
      }

      .btn-view-append i,
      .btn-view-edit i,
      .btn-view-forget i {
        font-size: 16px;
      }

      .btn-view-append:hover,
      .btn-view-edit:hover {
        background: var(--surface-3);
      }

      .btn-view-forget {
        color: var(--danger);
      }
      .btn-view-forget:hover {
        background: var(--danger);
        color: #fff;
      }

      .confirm-actions,
      .append-actions {
        display: flex;
        gap: 10px;
      }

      .btn-cancel,
      .btn-append-cancel {
        flex: 1;
        padding: 14px;
        background: var(--surface-2);
        border: none;
        border-radius: 13px;
        font-family: var(--font-sans);
        font-size: 14.5px;
        font-weight: 500;
        color: var(--text-primary);
        cursor: pointer;
        transition: background 0.15s;
      }

      .btn-cancel:hover,
      .btn-append-cancel:hover {
        background: var(--surface-3);
      }

      .btn-delete {
        flex: 1;
        padding: 14px;
        background: var(--danger);
        border: none;
        border-radius: 13px;
        font-family: var(--font-sans);
        font-size: 14.5px;
        font-weight: 600;
        color: #fff;
        cursor: pointer;
        transition: opacity 0.15s;
      }

      .btn-delete:hover {
        opacity: 0.92;
      }

      .btn-append-save {
        flex: 1;
        padding: 14px;
        background: var(--accent);
        border: none;
        border-radius: 13px;
        font-family: var(--font-sans);
        font-size: 14.5px;
        font-weight: 600;
        color: var(--on-accent);
        cursor: pointer;
        transition: background 0.15s;
      }

      .btn-append-save:hover {
        background: var(--accent-press);
      }

      .btn-append-save:disabled {
        opacity: 0.55;
        cursor: default;
      }

      .append-context {
        font-family: var(--font-serif);
        font-style: italic;
        font-size: 13.5px;
        color: var(--text-secondary);
        margin-bottom: 16px;
        line-height: 1.5;
        padding: 12px 14px;
        background: var(--bg-card);
        border: 0.5px solid var(--border-card);
        border-radius: 12px;
        display: -webkit-box;
        -webkit-line-clamp: 3;
        -webkit-box-orient: vertical;
        overflow: hidden;
      }

      .append-input-wrap {
        background: var(--bg-card);
        border: 0.5px solid var(--border-input);
        border-radius: 13px;
        padding: 13px 15px;
        margin-bottom: 14px;
        transition:
          border-color 0.18s,
          box-shadow 0.18s;
      }

      .append-input-wrap:focus-within {
        border-color: var(--accent);
        box-shadow: 0 0 0 3px var(--accent-soft);
      }

      .append-input-wrap textarea {
        width: 100%;
        background: none;
        border: none;
        outline: none;
        font-family: var(--font-sans);
        font-size: 14.5px;
        color: var(--text-primary);
        resize: none;
        line-height: 1.5;
        min-height: 60px;
      }

      .append-input-wrap textarea::placeholder {
        color: var(--text-tertiary);
      }

      .edit-existing-tags {
        display: flex;
        flex-wrap: wrap;
        gap: 6px;
        margin-bottom: 14px;
      }

      .edit-hint {
        font-size: 12px;
        color: var(--text-tertiary);
        margin-bottom: 14px;
      }

      .edit-hint span {
        color: var(--accent-ink);
      }

      /* ── v2.3: the editor claims the height it needs ──────────────────────
         This is the only sheet whose whole job is a long piece of text, so it
         takes the screen rather than being sized to fit around its own
         furniture. It used to read the textarea's scrollHeight while the sheet
         was still display:none — which is 0 — and cap the result at 200px, so a
         two-thousand-character memory was edited through about three visible
         lines. Height is CSS's job now and nothing measures anything. */
      /* A definite height, not a max-height, and that is the whole trick.
         flex-grow only hands out *free* space, and a container sized by its own
         content has none — so `flex: 1 1 auto` on the editor below did nothing
         and the textarea fell back to a 60px floor on a 20,000-character
         memory. Fixed rather than content-sized is also the right shape for a
         work surface: the box should not jump size between memories.

         overflow:hidden so nothing can escape the padding box. Without it a
         sheet whose children declare more height than it has renders them over
         its own padding, flush to the card's edge. */
      .edit-inner {
        display: flex;
        flex-direction: column;
        height: 82vh;
        max-height: 82vh;
        overflow: hidden;
      }

      .edit-header {
        flex-shrink: 0;
      }

      .edit-inner .edit-header h3 {
        margin-bottom: 3px;
      }

      /* Which memory this is, since the sheet is otherwise identical whichever
         row opened it. */
      .edit-sub {
        font-size: 12.5px;
        color: var(--text-tertiary);
        margin-bottom: 14px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      /* Takes everything the tags, hint and buttons do not. The min-height is
         only a floor for a very short window; the height comes from the grow. */
      .edit-input-wrap {
        flex: 1 1 auto;
        min-height: 120px;
        display: flex;
        overflow: hidden;
      }

      .edit-input-wrap textarea {
        flex: 1 1 auto;
        /* `height: 100%` resolved against the wrapper in a way that left the
           textarea at its own 60px minimum; plain stretch fills it. */
        height: auto;
        align-self: stretch;
        overflow-y: auto;
        overflow-wrap: anywhere;
      }

      /* Sized to its contents, with a safety valve rather than a tight cap. A
         fixed 62px clipped the third row of chips halfway through, which reads
         as a broken layout rather than as something that scrolls — and the
         editor above is protected by its own min-height either way. */
      .edit-existing-tags {
        flex-shrink: 0;
        max-height: 20vh;
        overflow-y: auto;
        margin-top: 14px;
      }

      .edit-hint,
      .edit-inner .append-actions {
        flex-shrink: 0;
      }

      /* Tags could be added but never removed anywhere in the product, while
         these chips sat next to a hint about adding them — so they looked like
         a control and were not one. */
      .tag-chip--removable {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        border: 0.5px solid var(--border);
        cursor: pointer;
        font-family: var(--font-sans);
        transition:
          background 0.15s,
          color 0.15s;
      }

      .tag-chip--removable i {
        font-size: 12px;
        opacity: 0.5;
      }

      .tag-chip--removable:hover {
        background: var(--danger-soft);
        color: var(--danger);
      }

      .tag-chip--removable:hover i {
        opacity: 1;
      }

      /* ============ MENU SHEET ============ */
      .menu-inner h3 {
        margin-bottom: 18px;
      }

      .theme-row {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 4px 0 16px;
        margin-bottom: 4px;
      }

      .theme-row-label {
        font-size: 14px;
        color: var(--text-secondary);
      }

      .theme-toggle {
        display: flex;
        gap: 3px;
        background: var(--surface-2);
        border-radius: var(--radius-pill);
        padding: 3px;
      }

      .theme-toggle button {
        background: none;
        border: none;
        cursor: pointer;
        padding: 7px 13px;
        border-radius: var(--radius-pill);
        font-family: var(--font-sans);
        font-size: 12.5px;
        color: var(--text-secondary);
        display: flex;
        align-items: center;
        gap: 5px;
        transition:
          background 0.18s,
          color 0.18s;
      }

      .theme-toggle button i {
        font-size: 16px;
      }

      .theme-toggle button.active {
        background: var(--bg-card);
        color: var(--accent-ink);
        box-shadow: var(--shadow-card);
      }

      .menu-item {
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 15px 0;
        border-top: 0.5px solid var(--border);
        cursor: pointer;
        color: var(--text-primary);
        font-size: 15px;
        background: none;
        border-left: none;
        border-right: none;
        border-bottom: none;
        width: 100%;
        font-family: var(--font-sans);
        text-align: left;
        transition: color 0.15s;
      }

      .menu-item:hover {
        color: var(--text-secondary);
      }

      .menu-item i {
        font-size: 20px;
        color: var(--text-secondary);
      }

      .menu-item.danger {
        color: var(--danger);
      }
      .menu-item.danger i {
        color: var(--danger);
      }

      .about-credits {
        margin: 18px 0 14px;
        padding: 14px 16px;
        background: var(--bg-card);
        border: 0.5px solid var(--border-card);
        border-radius: var(--radius-card);
        font-size: 13px;
        color: var(--text-secondary);
        line-height: 1.5;
      }

      .about-credits-label {
        font-family: var(--font-serif);
        font-size: 15px;
        font-weight: 500;
        color: var(--text-primary);
        margin-bottom: 10px;
      }

      .about-credits-kicker {
        font-size: 11px;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        font-weight: 500;
        color: var(--text-tertiary);
        margin: 0 0 6px;
      }

      .about-credits-line {
        margin: 0 0 12px;
      }

      .about-credits-list {
        margin: 0;
        padding-left: 18px;
      }

      .about-credits-list li {
        margin-bottom: 4px;
      }

      .about-credits a {
        color: var(--accent-ink);
        text-decoration: none;
      }

      .about-credits a:hover {
        text-decoration: underline;
      }

      /* ── v2.3 settings sheet: grouped by what the thing is ───────────────
         It was fourteen items in one stack — a stats panel, five chore panels, a
         theme toggle, three data actions and an about block — with nothing
         saying which was which. The Tauri Advanced Settings window groups by
         what a control affects; this borrows that and nothing else, because its
         staged Save/Cancel model would be wrong for a sheet whose controls are
         all immediate verbs. The stats panel is gone entirely: home shows the
         count, the week, the sources and the tags. */
      .menu-group {
        margin-bottom: 18px;
      }

      .menu-group[hidden] {
        display: none;
      }

      /* Deliberately unlike .digest-section-label, which is the 11px uppercase
         tertiary style used *inside* a group. Two identically-styled labels
         stacked ("UPKEEP" over "READY TO COMPRESS") read as two peers rather
         than as a heading and its contents. */
      .menu-group-label {
        font-family: var(--font-serif);
        font-size: 15px;
        font-weight: 500;
        color: var(--text-primary);
        margin-bottom: 10px;
        padding-bottom: 7px;
        border-bottom: 0.5px solid var(--border);
      }

      .digest-section {
        margin-bottom: 6px;
      }

      .digest-section-label {
        font-size: 11px;
        color: var(--text-tertiary);
        text-transform: uppercase;
        letter-spacing: 0.06em;
        font-weight: 500;
        margin-bottom: 9px;
      }

      /* ── v2.3 pattern review queue ────────────────────────────────────────
         Home shows two patterns as a daily nudge; this is the backlog, which on
         a brain that has been running a while is hundreds long. It is its own
         sheet rather than a panel inside settings for that reason. */
      .patterns-inner {
        display: flex;
        flex-direction: column;
        max-height: 88vh;
      }

      .patterns-bulkbar {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        flex-shrink: 0;
        padding: 10px 0;
        margin-bottom: 4px;
        border-top: 0.5px solid var(--border);
        border-bottom: 0.5px solid var(--border);
        position: sticky;
        top: 0;
        background: var(--bg);
        z-index: 1;
      }

      .patterns-bulkbar[hidden] {
        display: none;
      }

      .patterns-selectall {
        display: inline-flex;
        align-items: center;
        gap: 9px;
        font-size: 13.5px;
        color: var(--text-secondary);
        cursor: pointer;
        min-width: 0;
      }

      .patterns-bulk-actions {
        display: flex;
        gap: 8px;
        flex-shrink: 0;
      }

      #patterns-list {
        flex: 1 1 auto;
        overflow-y: auto;
        min-height: 0;
        padding-bottom: 6px;
      }

      /* The whole row is the label, so tapping anywhere on a pattern ticks it —
         a checkbox-sized target is the wrong size for a phone. */

      /* One flagged memory, with the four ways out of the flag. Mirrors
         .pattern-row's rhythm; no checkbox, because ruling on staleness is a
         per-memory judgement rather than a bulk one. */
      .stale-row {
        padding: 12px 2px;
        border-bottom: 0.5px solid var(--border);
      }

      .stale-row:last-child {
        border-bottom: none;
      }

      .stale-text {
        margin: 0 0 6px;
        font-size: 14px;
        line-height: 1.5;
        color: var(--text-primary);
      }

      .stale-when {
        display: block;
        font-size: 12px;
        color: var(--text-tertiary);
        margin-bottom: 8px;
      }

      .stale-actions {
        display: flex;
        gap: 8px;
        flex-wrap: wrap;
      }

      .pattern-row {
        display: flex;
        align-items: flex-start;
        gap: 11px;
        padding: 12px 2px;
        border-bottom: 0.5px solid var(--border);
        cursor: pointer;
      }

      .pattern-row:last-child {
        border-bottom: none;
      }

      .pattern-check,
      #patterns-select-all {
        flex-shrink: 0;
        width: 17px;
        height: 17px;
        margin: 2px 0 0;
        accent-color: var(--accent);
        cursor: pointer;
      }

      .pattern-body {
        display: flex;
        flex-direction: column;
        gap: 4px;
        min-width: 0;
      }

      .pattern-text {
        font-family: var(--font-serif);
        font-size: 15px;
        line-height: 1.5;
        color: var(--text-primary);
        overflow-wrap: anywhere;
      }

      .pattern-when {
        font-size: 11.5px;
        color: var(--text-tertiary);
      }

      .pattern-sources {
        display: flex;
        flex-direction: column;
        gap: 3px;
        margin: 2px 0 0;
        padding: 0 0 0 14px;
        list-style: disc;
      }

      .pattern-source {
        font-size: 12.5px;
        line-height: 1.4;
        color: var(--text-secondary);
        overflow-wrap: anywhere;
      }

      .pattern-source--gone {
        color: var(--text-tertiary);
        font-style: italic;
      }

      #patterns-more {
        flex-shrink: 0;
        align-self: flex-start;
      }

      #patterns-more[hidden] {
        display: none;
      }

      .digest-more {
        background: none;
        border: none;
        padding: 6px 0;
        cursor: pointer;
        color: var(--text-secondary);
        font-family: var(--font-sans);
        font-size: 13px;
      }

      .digest-more:hover {
        color: var(--accent-ink);
      }

      .digest-candidate-row {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
        padding: 8px 0;
        border-bottom: 0.5px solid var(--line-soft);
      }

      .digest-candidate-row:last-of-type {
        border-bottom: none;
      }

      .digest-candidate-label {
        font-size: 13px;
        color: var(--text-secondary);
        display: flex;
        align-items: center;
        gap: 6px;
      }

      .digest-candidate-count {
        font-size: 11px;
        color: var(--text-tertiary);
      }

      /* Browsers do not inherit font-family into form controls: a <button>,
         <select>, <input> or <textarea> falls back to a system font unless you
         say otherwise. Half the controls in this app — 207 of 416 — were
         rendering in Arial next to Geist copy, which is most of why the
         interface read as unfinished.

         font-family only, not the `font` shorthand: size, weight and
         line-height are set deliberately per control and inheriting them would
         flatten that. */
      button,
      select,
      input,
      textarea {
        font-family: inherit;
      }

      .digest-btn {
        font-size: 12px;
        font-weight: 500;
        color: var(--accent-ink);
        background: var(--accent-soft);
        border: none;
        border-radius: var(--radius-pill);
        padding: 5px 12px;
        cursor: pointer;
        white-space: nowrap;
        transition: background 0.15s;
      }

      .digest-btn:hover {
        background: rgba(253, 84, 10, 0.14);
      }

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

      .digest-btn--loading i {
        animation: spin 0.7s linear infinite;
        display: inline-block;
      }

      .digest-note {
        font-size: 12px;
        color: var(--text-tertiary);
        line-height: 1.5;
        margin-bottom: 10px;
      }

      .digest-note a {
        color: var(--accent-ink);
        text-decoration: none;
        border-bottom: 1px solid var(--accent-soft);
      }

      .digest-note a:hover {
        border-bottom-color: var(--accent);
      }

      .integration-row {
        padding: 16px 0;
      }

      .integration-row + .integration-row {
        border-top: 0.5px solid var(--border-input);
      }

      .integration-category-row {
        display: flex;
        align-items: center;
        gap: 11px;
        width: 100%;
        padding: 15px 4px;
        background: transparent;
        border: none;
        border-bottom: 0.5px solid var(--border-input);
        font-family: inherit;
        font-size: 14px;
        color: var(--text-primary);
        cursor: pointer;
        text-align: left;
      }
      .integration-category-row:last-child {
        border-bottom: none;
      }
      .integration-category-row:hover {
        background: rgba(128, 128, 128, 0.08);
      }
      .integration-category-row > i.ti {
        color: var(--accent);
        font-size: 18px;
      }
      .integration-category-name {
        font-weight: 500;
      }
      .integration-category-summary {
        margin-left: auto;
        font-size: 12px;
        color: var(--text-tertiary);
      }
      .integration-category-chevron {
        color: var(--text-tertiary) !important;
        font-size: 16px !important;
      }

      .integration-head {
        display: flex;
        align-items: center;
        gap: 7px;
        font-size: 13px;
        font-weight: 500;
        color: var(--text-primary);
        margin-bottom: 6px;
      }

      .integration-head i {
        color: var(--accent);
        font-size: 15px;
      }

      .integration-state {
        margin-left: auto;
        font-size: 11px;
        color: var(--text-tertiary);
      }

      .integration-state.connected {
        color: var(--good);
      }

      .integration-connect-row {
        display: flex;
        gap: 8px;
        margin-bottom: 6px;
      }

      .integration-connect-col {
        flex-direction: column;
        align-items: stretch;
      }

      .integration-connect-row input {
        flex: 1;
        min-width: 0;
        padding: 8px 10px;
        background: transparent;
        border: 0.5px solid var(--border-input);
        border-radius: 9px;
        font-size: 13px;
        font-family: inherit;
        color: var(--text-primary);
        outline: none;
      }

      .integration-connect-row input:focus {
        border-color: var(--accent);
      }

      .integration-actions {
        display: flex;
        gap: 8px;
      }

      .digest-btn.danger {
        color: var(--danger);
        background: rgba(179, 38, 30, 0.08);
      }

      .integration-error {
        font-size: 12px;
        color: var(--danger);
        margin-bottom: 6px;
      }

      .digest-result {
        font-size: 12px;
        color: var(--text-secondary);
        margin-top: 6px;
        line-height: 1.5;
        padding: 8px 10px;
        background: var(--accent-soft);
        border-radius: 8px;
      }

      .digest-result-meta {
        margin-top: 6px;
        font-size: 11px;
        color: var(--good);
        font-weight: 500;
      }

      /* ============ DESKTOP SIDEBAR ============ */
      #sidebar {
        width: 248px;
        flex-shrink: 0;
        flex-direction: column;
        background: var(--bg);
        border-right: 0.5px solid var(--border);
        padding: 20px 12px 22px;
      }

      .sb-logo {
        display: flex;
        align-items: center;
        gap: 11px;
        padding: 6px 10px 26px;
      }

      .sb-brand-name {
        font-family: var(--font-serif);
        font-size: 16px;
        font-weight: 500;
        color: var(--text-primary);
      }

      /* The team a member belongs to, between the product name and the status
         line. Sized between the two so it reads as the middle of a hierarchy
         rather than a second title, and truncated rather than wrapped — the
         sidebar is a fixed column and a two-line team name would push the nav. */
      .topbar-team {
        font-size: 11.5px;
        font-weight: 500;
        line-height: 1.35;
        color: var(--accent-ink);
        margin-top: 1px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .sb-brand-team {
        font-size: 12px;
        font-weight: 500;
        line-height: 1.35;
        color: var(--accent-ink);
        margin-top: 2px;
        max-width: 148px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .sb-brand-status {
        font-size: 11.5px;
        color: var(--text-secondary);
        margin-top: 1px;
      }

      .sb-nav {
        flex: 1;
        display: flex;
        flex-direction: column;
        gap: 3px;
      }

      .sb-tab {
        display: flex;
        align-items: center;
        gap: 11px;
        padding: 10px 11px;
        border-radius: 10px;
        background: none;
        border: none;
        cursor: pointer;
        color: var(--text-secondary);
        font-size: 14.5px;
        font-family: var(--font-serif);
        width: 100%;
        text-align: left;
        transition:
          background 0.15s,
          color 0.15s;
      }

      .sb-tab i {
        font-size: 19px;
        flex-shrink: 0;
      }

      .sb-tab:hover {
        background: var(--surface-2);
        color: var(--text-primary);
      }

      .sb-tab.active {
        background: var(--accent-soft);
        color: var(--accent-ink);
      }

      .sb-footer {
        padding-top: 12px;
        border-top: 0.5px solid var(--border);
      }

      .sb-footer-btn {
        display: flex;
        align-items: center;
        gap: 11px;
        padding: 10px 11px;
        border-radius: 10px;
        background: none;
        border: none;
        cursor: pointer;
        color: var(--text-secondary);
        font-size: 14.5px;
        font-family: var(--font-sans);
        width: 100%;
        text-align: left;
        transition:
          background 0.15s,
          color 0.15s;
      }

      .sb-footer-btn:hover {
        background: var(--surface-2);
        color: var(--text-primary);
      }

      .sb-footer-btn i {
        font-size: 19px;
      }

      /* ============ DESKTOP ============ */
      /* ── v2.3 Recent rows: title, meta, and a hidden destructive action ──
         Mobile-first. Actions are always present on touch (the overflow is the
         primary affordance); the hover reveal below is a desktop enhancement. */
      .card-title {
        font-weight: 500;
        font-size: 15px;
        line-height: 1.4;
        color: var(--text-primary);
        margin-bottom: 4px;
      }

      .card-preview {
        font-size: 13.5px;
        line-height: 1.5;
        color: var(--text-secondary);
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
      }

      .card-meta {
        display: flex;
        align-items: center;
        gap: 10px;
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 11px;
        color: var(--text-tertiary);
        margin-bottom: 6px;
      }

      .card-source {
        display: inline-flex;
        align-items: center;
        gap: 4px;
      }

      .card-source i {
        font-size: 13px;
      }

      /* Tags scroll sideways rather than stacking into a tall wrap — a row's
         height should not depend on how many tags it carries.
         `flex-wrap: nowrap` is doing real work: the base rule above wraps, and
         inside the footer's narrow middle column that put every chip on its own
         line — a memory with nine tags became a nine-line row on a phone. */
      .card-tags {
        display: flex;
        flex-wrap: nowrap;
        gap: 6px;
        overflow-x: auto;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        padding-bottom: 2px;
      }

      /* Phones give the tags their own full-width line. Squeezing them between
         the source badge and the action buttons leaves ~120px, which truncates
         chips mid-word ("second-brain-cl…") no matter how they wrap. */
      .card-footer {
        flex-wrap: wrap;
      }

      .card-meta {
        order: 1;
      }

      .card-actions {
        order: 2;
        margin-left: auto;
      }

      .card-tags {
        order: 3;
        flex: 1 0 100%;
      }

      .card-tags::-webkit-scrollbar {
        display: none;
      }

      .card-tags .tag-chip {
        flex: 0 0 auto;
      }

      .card-overflow {
        position: relative;
      }

      .overflow-btn {
        min-width: 44px;
        min-height: 44px;
        justify-content: center;
      }

      .card-overflow-menu {
        position: absolute;
        right: 0;
        bottom: calc(100% + 6px);
        z-index: 20;
        background: var(--bg-card);
        border: 1px solid var(--border-card);
        border-radius: 10px;
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
        padding: 4px;
        min-width: 200px;
      }

      .card-overflow-menu[hidden] {
        display: none;
      }

      .card-overflow-item {
        display: flex;
        align-items: center;
        gap: 8px;
        width: 100%;
        min-height: 44px;
        padding: 0 12px;
        background: none;
        border: 0;
        border-radius: 8px;
        font-size: 14px;
        color: var(--text-primary);
        cursor: pointer;
        text-align: left;
      }

      .card-overflow-item.danger {
        color: var(--danger);
      }

      .card-overflow-item.danger:hover {
        background: var(--danger-soft);
      }

      /* ── Safe areas ──────────────────────────────────────────────────────
         Installed as a PWA the app owns the whole screen, so the bottom bars
         sat under the iPhone home indicator. Paired with viewport-fit=cover. */
      .input-bar,
      .filter-bar {
        padding-bottom: max(env(safe-area-inset-bottom), 0px);
      }

      #menu-sheet .menu-inner,
      #integrations-sheet .menu-inner {
        padding-bottom: max(env(safe-area-inset-bottom), 16px);
      }

      @media (hover: hover) {
        .card-actions {
          opacity: 0;
          transition: opacity 0.15s ease;
        }

        .memory-card:hover .card-actions,
        .memory-card:focus-within .card-actions,
        .memory-card.card--menu-open .card-actions {
          opacity: 1;
        }
      }

      /* ── v2.3 memory detail: what the brain knows ─────────────────────── */
      .view-meta {
        display: flex;
        flex-wrap: wrap;
        gap: 12px;
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 11px;
        color: var(--text-tertiary);
        margin-bottom: 14px;
        flex-shrink: 0;
      }

      .view-meta-item {
        display: inline-flex;
        align-items: center;
        gap: 4px;
      }

      .view-meta-item i {
        font-size: 13px;
      }

      .view-brain {
        background: var(--bg-card);
        border: 1px solid var(--border-card);
        border-radius: 12px;
        padding: 12px 14px;
        margin-bottom: 18px;
        flex-shrink: 0;
      }

      .view-brain-label {
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 10px;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--text-tertiary);
        margin-bottom: 8px;
      }

      .view-brain-row {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        font-size: 13.5px;
        color: var(--text-secondary);
        padding: 3px 0;
      }

      .view-brain-row strong {
        color: var(--text-primary);
        font-weight: 500;
      }

      .view-brain-row .dots {
        color: var(--accent-ink);
        letter-spacing: 2px;
        font-size: 12px;
      }

      /* The sentence that explains a verdict, in the voice the rest of the
         product uses rather than the tag it is stored as. */
      .view-brain-note {
        font-family: var(--font-serif);
        font-style: italic;
        font-size: 13px;
        line-height: 1.5;
        color: var(--text-secondary);
        margin-top: 6px;
      }

      .view-brain-note--warn {
        color: var(--warn);
        font-style: normal;
        font-family: var(--font-sans);
      }

      /* Citation chips in an answer, and the card they point at. */
      .cite {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 18px;
        height: 18px;
        padding: 0 5px;
        margin: 0 2px;
        vertical-align: baseline;
        background: var(--accent-soft);
        color: var(--accent-ink);
        border: 0;
        border-radius: 5px;
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 10.5px;
        line-height: 1;
        cursor: pointer;
      }

      .cite:hover {
        background: var(--accent);
        color: #fff;
      }

      .memory-card--cited {
        box-shadow: 0 0 0 2px var(--accent);
        transition: box-shadow 0.3s ease;
      }

      /* Capture receipt — the site's "● stored to brain" moment. */
      .receipt {
        background: var(--bg-card);
        border: 1px solid var(--border-card);
        border-radius: 12px;
        padding: 12px 14px;
        margin: 8px 0 4px;
      }

      .receipt-headline {
        display: flex;
        align-items: center;
        gap: 8px;
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 11.5px;
        color: var(--accent-ink);
      }

      .receipt-dot {
        width: 7px;
        height: 7px;
        border-radius: 50%;
        background: var(--accent);
        flex-shrink: 0;
      }

      .receipt-filed {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 6px;
        margin-top: 10px;
        font-size: 13px;
        color: var(--text-secondary);
      }

      .receipt-note {
        font-family: var(--font-serif);
        font-style: italic;
        font-size: 13.5px;
        line-height: 1.5;
        color: var(--text-secondary);
        margin-top: 8px;
      }

      /* The number the answer cites this source by. Same visual language as the
         inline chip, so [2] in the prose and 2 on the card read as one thing. */
      .cite-badge {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 18px;
        height: 18px;
        padding: 0 5px;
        background: var(--accent-soft);
        color: var(--accent-ink);
        border-radius: 5px;
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 10.5px;
        line-height: 1;
        flex-shrink: 0;
      }

      /* A scrolling tag row clipped hard at the card edge reads as a rendering
         fault; the fade says "there is more this way". Harmless when the tags
         already fit, because then it only fades empty space. */
      .card-tags {
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
        mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
      }

      /* ── Sheet proportions ────────────────────────────────────────────────
         The memory is the point of this sheet, and it was losing: three rows of
         tags, the verdict panel and three related cards left the text about
         four lines in a 90vh sheet. The content now takes the space and the
         supporting sections are capped. */
      /* The middle of the sheet scrolls as one, so the memory renders at its
         natural length instead of through a keyhole while the panels below it
         each keep their own scrollbar — and, more importantly, so nothing can
         push the action row past the sheet's own padding. */
      .view-scroll {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        /* Room for the fixed action row below, which would otherwise sit right
           on top of the last line of text as it scrolls under. */
        padding-bottom: 4px;
      }

      .view-content {
        flex: 0 0 auto;
        overflow-y: visible;
      }

      /* One scrolling line, like the tag rows on cards — a memory with a dozen
         tags should not cost three lines of the reading area. */
      .view-tags {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
        mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
        margin-bottom: 14px;
      }

      .view-tags::-webkit-scrollbar {
        display: none;
      }

      .view-tags .tag-chip {
        flex: 0 0 auto;
      }

      /* Related is context, not the subject: it scrolls within its own bounds
         rather than pushing the memory off the top of the sheet. */
      /* No longer its own scroll area: the region above scrolls, and a panel
         that scrolled inside a scrolling panel meant two gestures to read one
         memory. */
      .view-related {
        flex-shrink: 0;
      }

      /* ── v2.3 daily brief ─────────────────────────────────────────────────
         The home surface. Quiet by construction: when nothing happened it does
         not render, and the welcome hero stands in its place. */
      /* Explicit separation from the home block above. #brief is a sibling of
         #home, not a child, and the two were previously kept apart only by
         whatever slack happened to be left at the bottom of #home — which is
         how "YOUR BRAIN, LATELY" ended up sitting on the tag chips on iOS. */
      .brief {
        padding: 4px 0 8px;
        margin-top: 20px;
      }

      .brief-eyebrow {
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 10px;
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: var(--accent-ink);
        margin-bottom: 14px;
      }

      .brief-card {
        background: var(--bg-card);
        border: 1px solid var(--border-card);
        border-radius: 12px;
        padding: 12px 14px;
        margin-bottom: 10px;
      }

      /* Nothing to decide here — context, not a prompt for action. */
      .brief-card--quiet {
        background: none;
        border-style: dashed;
      }

      .brief-label {
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 10px;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--text-tertiary);
        margin-bottom: 6px;
      }

      .brief-body {
        font-family: var(--font-serif);
        font-size: 15px;
        line-height: 1.55;
        color: var(--text-primary);
      }

      .brief-actions {
        display: flex;
        gap: 8px;
        margin-top: 10px;
      }

      /* Sits in the same list as the cards above it, so it takes the same
         block rhythm rather than the inline width a bare <button> defaults to. */
      .brief-more {
        display: block;
        margin: 0 0 10px;
      }

      .brief-suggestions {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        margin-top: 14px;
      }

      /* ── Brief dashboard panels ───────────────────────────────────────── */
      .brief-grid {
        display: grid;
        grid-template-columns: 1fr;
        gap: 10px;
        margin-bottom: 12px;
      }

      .brief-panel {
        background: var(--bg-card);
        border: 1px solid var(--border-card);
        border-radius: 12px;
        padding: 12px 14px;
      }

      /* Activity strip. No axes: the shape is the point, and the counts are in
         the tooltips. */
      .spark {
        display: flex;
        align-items: flex-end;
        gap: 3px;
        height: 46px;
        margin-top: 4px;
      }

      .spark-bar {
        flex: 1 1 0;
        min-width: 0;
        background: var(--accent);
        border-radius: 2px 2px 0 0;
        opacity: 0.85;
      }

      /* A day with nothing is a fact worth seeing, so it keeps its slot. */
      .spark-bar--empty {
        background: var(--surface-3);
        opacity: 1;
      }

      .src-row {
        display: flex;
        align-items: center;
        gap: 8px;
        margin-top: 7px;
        font-size: 12.5px;
        color: var(--text-secondary);
      }

      .src-name {
        display: inline-flex;
        align-items: center;
        gap: 5px;
        min-width: 88px;
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 11px;
      }

      .src-bar {
        flex: 1;
        height: 6px;
        background: var(--surface-2);
        border-radius: 3px;
        overflow: hidden;
      }

      .src-fill {
        display: block;
        height: 100%;
        background: var(--accent);
        opacity: 0.8;
      }

      .src-n {
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 11px;
        color: var(--text-tertiary);
        min-width: 22px;
        text-align: right;
      }

      .topic-chips {
        display: flex;
        flex-wrap: wrap;
        gap: 6px;
        margin-top: 8px;
      }

      .topic-chip {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        background: var(--bg-tag);
        color: var(--text-tag);
        border: 0;
        border-radius: var(--radius-tag);
        padding: 5px 10px;
        font-size: 12px;
        font-family: var(--font-sans);
        cursor: pointer;
      }

      .topic-chip span {
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 10px;
        color: var(--text-tertiary);
      }

      .topic-chip:hover {
        background: var(--accent-soft);
        color: var(--accent-ink);
      }

      .brief-attention {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        margin-bottom: 14px;
      }

      .attn {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        background: none;
        border: 1px solid var(--border-input);
        border-radius: 999px;
        padding: 6px 12px;
        font-size: 12.5px;
        color: var(--warn);
        cursor: pointer;
        font-family: var(--font-sans);
      }

      .attn:hover {
        background: var(--surface-2);
      }

      /* ── v2.4 home: greeting and one input, composed as a unit ──────────
         The old layout pinned a hero to the top and the input to the bottom
         and left a trench between them, which is what made a brain holding
         two thousand memories feel empty. */
      .home {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        min-height: 58vh;
        padding: 24px 4px 8px;
        text-align: center;
      }

      .home-greet {
        display: flex;
        align-items: center;
        gap: 12px;
        font-family: var(--font-serif);
        font-size: 30px;
        color: var(--text-primary);
      }

      .home-mark {
        color: var(--accent);
        font-size: 24px;
        display: inline-flex;
      }

      .home-sub {
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 11.5px;
        color: var(--text-tertiary);
        margin-top: 10px;
      }

      .home-input {
        width: 100%;
        max-width: 620px;
        margin-top: 26px;
        background: var(--bg-card);
        border: 1px solid var(--border-input);
        border-radius: 18px;
        padding: 14px 16px 10px;
        text-align: left;
        transition: border-color 0.15s;
      }

      .home-input:focus-within {
        border-color: var(--accent);
      }

      .home-field {
        width: 100%;
        border: 0;
        background: none;
        resize: none;
        outline: none;
        font-family: var(--font-serif);
        font-size: 16px;
        line-height: 1.5;
        color: var(--text-primary);
        max-height: 40vh;
      }

      .home-field::placeholder {
        color: var(--text-tertiary);
      }

      .home-row {
        display: flex;
        align-items: center;
        gap: 8px;
        margin-top: 10px;
      }

      /* Mode pill anchors left; the layer target and send button anchor right,
         as one cluster. A middle-anchored dropdown in a full-width box reads
         as floating — this way the wide middle is just the textarea's space. */
      .home-row #home-mode {
        margin-right: auto;
      }

      /* The prediction, always visible and always one tap from being overridden.
         Hidden only while the field is empty, when there is nothing to predict. */
      .home-mode {
        display: inline-flex;
        align-items: center;
        gap: 7px;
        background: none;
        border: 1px solid var(--border-input);
        border-radius: 999px;
        padding: 5px 12px;
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 11px;
        color: var(--text-secondary);
        cursor: pointer;
        visibility: hidden;
      }

      .home-mode:hover {
        border-color: var(--accent);
        color: var(--accent-ink);
      }

      .home-mode-dot {
        width: 6px;
        height: 6px;
        border-radius: 50%;
        background: var(--text-tertiary);
      }

      .home-mode--remember .home-mode-dot {
        background: var(--accent);
      }

      .home-topics {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: 8px;
        margin-top: 18px;
      }

      .home-more {
        width: 100%;
        max-width: 620px;
        margin-top: 14px;
        text-align: left;
      }

      /* With nothing to show this element is zero-height, and its margin was
         the only thing holding the brief off the tag chips. Margin on an empty
         box is not spacing anyone declared — it is leftover, and an engine that
         lays it out differently drops the two sections onto each other. */
      .home-more:empty {
        margin-top: 0;
      }

      /* On the home screen the old bottom bars are redundant: the input above
         is the input, and a tag filter with nothing to filter is furniture. */
      #screen-home.home-visible .input-bar,
      #screen-home.home-visible .suggestions-row,
      #screen-home.home-visible .filter-bar {
        display: none;
      }

      /* The hashtag lesson, inherited from the deleted Remember tab — which was
         the only place the product ever taught it. */
      .home-hint {
        font-size: 12.5px;
        color: var(--text-tertiary);
        text-align: center;
        margin-top: 10px;
      }

      .home-layer-hint {
        font-size: 12px;
        color: var(--text-tertiary);
        text-align: center;
        margin-top: 8px;
      }

      /* First-run coach marks (js/coach.js). An inline callout under the
         control it explains, not a floating popover — see that file for why.
         The 32px tap target is on the base rule rather than in the phone
         media query, because the mark is the same size at every width. */
      .coach-mark {
        margin-top: 10px;
        padding: 12px 14px;
        border: 1px solid var(--border);
        border-radius: 8px;
        background: var(--surface-2);
      }

      .coach-mark-title {
        font-size: 13.5px;
        font-weight: 600;
        color: var(--text-primary);
        margin-bottom: 4px;
      }

      .coach-mark-body {
        margin: 0;
        font-size: 12.5px;
        line-height: 1.5;
        color: var(--text-secondary);
      }

      .coach-mark-dismiss {
        /* 31px wide before this: a hair under the 32px minimum, and the one
           control on the card a thumb is most likely to reach for. */
        min-width: 32px;
        margin-top: 8px;
        min-height: 32px;
        padding: 0;
        background: none;
        border: none;
        font-family: var(--font-sans);
        font-size: 12.5px;
        color: var(--text-secondary);
        text-decoration: underline;
        cursor: pointer;
      }

      .home-hint .hashtag {
        color: var(--accent-ink);
        font-style: italic;
      }

      @media (min-width: 768px) {
        .brief-grid {
          grid-template-columns: repeat(3, 1fr);
        }
      }

      @media (min-width: 768px) {
        /* Wide enough for one row again: badge, tags, actions. */
        .card-footer {
          flex-wrap: nowrap;
        }

        .card-tags {
          order: 2;
          flex: 1 1 auto;
        }

        .card-actions {
          order: 3;
          margin-left: 0;
        }
      }

      @media (min-width: 768px) {
        html,
        body {
          height: 100%;
          overflow: auto;
        }

        body {
          background: var(--surface-3);
        }

        #auth-overlay {
          position: fixed;
          inset: 0;
          max-width: none;
          background: color-mix(in srgb, var(--bg) 88%, transparent);
          backdrop-filter: blur(8px);
          align-items: center;
          justify-content: center;
          padding: 0;
        }

        .auth-card {
          background: var(--bg);
          border-radius: 22px;
          padding: 44px 38px;
          width: 420px;
          box-shadow: var(--shadow-float);
          display: flex;
          flex-direction: column;
          align-items: center;
        }

        #app {
          flex-direction: row;
          height: 100vh;
          max-width: 100%;
          width: 100%;
          border-radius: 0;
          overflow: hidden;
        }

        #sidebar {
          display: flex;
        }
        #topbar {
          display: none;
        }
        #navbar {
          display: none;
        }

        #main-panel {
          margin: 0 auto;
          border-left: 0.5px solid var(--border);
          border-right: 0.5px solid var(--border);
        }

        #confirm-dialog,
        #append-sheet,
        #edit-sheet,
        #menu-sheet,
        #integrations-sheet,
        #patterns-sheet,
        #stale-sheet,
        #view-sheet {
          align-items: center;
          justify-content: center;
        }

        .confirm-sheet,
        .append-inner,
        .edit-inner,
        .menu-inner,
        .view-inner {
          border-radius: 18px;
          max-width: 420px;
          transform: translateY(16px) scale(0.98);
          /* Bottom-sheet shadow points upward; on centered modals it reads as a
             flat dark bar under the panel. Use the floating elevation instead. */
          box-shadow: var(--shadow-float);
          border: 0.5px solid var(--border-card);
        }

        /* The editor is the exception to the 420px modal width. Every other
           sheet presents something to read or a short list to pick from; this
           one is a writing surface, and 420px on a 1,500px window meant editing
           a long memory through a column narrower than the row it came from. */
        .edit-inner {
          max-width: 680px;
        }

        .open .confirm-sheet,
        .open .append-inner,
        .open .edit-inner,
        .open .menu-inner,
        .open .view-inner {
          transform: none;
        }
      }

      ::-webkit-scrollbar {
        width: 0;
      }

      /* forget animation */
      @keyframes explode-out {
        0% {
          transform: scale(1);
          opacity: 1;
          filter: brightness(1) blur(0);
        }
        20% {
          transform: scale(1.04) translateY(-2px);
          opacity: 1;
          filter: brightness(1.4) blur(1px);
        }
        100% {
          transform: scale(0.6) translateY(20px);
          opacity: 0;
          filter: brightness(2.2) blur(8px);
        }
      }

      .explode-out {
        animation: explode-out 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards !important;
        pointer-events: none;
      }

      @media (prefers-reduced-motion: reduce) {
        *,
        *::before,
        *::after {
          animation-duration: 0.01ms !important;
          transition-duration: 0.05s !important;
        }
      }

      /* Download-the-app CTA (sidebar footer).
         A solid pill rather than another nav row like Settings — it is the one
         thing here aimed at someone who has not installed the app yet.
         .sb-footer-btn was written for <button>, so as an <a> it also needs the
         underline removed. */
      #sb-download-app {
        --dl-bg: #1f2532;
        --dl-fg: #ffffff;
        box-sizing: border-box;
        justify-content: center;
        gap: 9px;
        margin-bottom: 10px;
        padding: 11px 14px;
        border: none;
        border-radius: var(--radius-pill);
        background: var(--dl-bg);
        color: var(--dl-fg);
        font-weight: 650;
        /* "Download for Windows" is the longest label and wraps to two lines in
           a narrow sidebar, which reads as broken rather than tight. */
        white-space: nowrap;
        font-size: 14px;
        text-decoration: none;
        box-shadow: 0 1px 2px rgba(22, 22, 22, 0.14);
        transition:
          background 0.15s,
          box-shadow 0.15s,
          transform 0.08s;
      }

      /* Inverted in dark mode: the light-mode fill is nearly --bg there, so the
         button would disappear into the sidebar. */
      html[data-theme='dark'] #sb-download-app {
        --dl-bg: var(--text-primary);
        --dl-fg: #161616;
        box-shadow: none;
      }

      #sb-download-app i {
        color: inherit;
        font-size: 17px;
      }

      #sb-download-app:hover {
        background: #2a3444;
        color: var(--dl-fg);
        box-shadow: 0 2px 6px rgba(22, 22, 22, 0.18);
      }

      html[data-theme='dark'] #sb-download-app:hover {
        background: #ffffff;
      }

      /* A press that visibly depresses is most of what makes a link feel like a
         button. */
      #sb-download-app:active {
        transform: translateY(1px);
        box-shadow: 0 1px 1px rgba(22, 22, 22, 0.16);
      }

      /* ── Team panel (public/js/team.js) ─────────────────────────────
         A roster that reads like a table without being one: hairline
         rows in a single rounded container, an aligned header, and
         quiet icon actions that only speak on hover. */
      /* Team name editor. Matches the org-default pill above the roster: same
         border, radius and surface, so the two settings rows read as a pair. */
      .team-name-row {
        display: flex;
        align-items: center;
        gap: 10px;
        padding: 10px 14px;
        border: 0.5px solid var(--border-input);
        border-radius: 13px;
        background: var(--surface-2);
      }

      .team-name-icon {
        color: var(--text-tertiary);
        font-size: 13px;
        flex-shrink: 0;
      }

      .team-name-input {
        flex: 1 1 auto;
        min-width: 0;
      }

      .team-name-note {
        margin: 8px 2px 0;
      }

      .team-table {
        border: 0.5px solid var(--border-input);
        border-radius: 13px;
        overflow: hidden;
        background: var(--surface);
      }

      .team-head,
      .team-row {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto auto;
        gap: 16px;
        align-items: center;
        padding: 10px 14px;
      }

      .team-head {
        font-size: 10.5px;
        font-weight: 500;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--text-tertiary);
        background: var(--surface-2);
        border-bottom: 0.5px solid var(--border-input);
      }

      .team-row + .team-row {
        border-top: 0.5px solid var(--border-input);
      }

      .team-row.suspended .team-name {
        color: var(--text-tertiary);
      }

      .team-name {
        display: flex;
        align-items: center;
        gap: 6px;
        flex-wrap: wrap;
        min-width: 0;
      }

      .team-sub {
        font-size: 11.5px;
        color: var(--text-tertiary);
        margin-top: 2px;
      }

      .team-actions {
        display: flex;
        align-items: center;
        gap: 2px;
      }

      .team-icon-btn {
        border: none;
        background: none;
        padding: 6px;
        border-radius: 8px;
        cursor: pointer;
        color: var(--text-tertiary);
        font-size: 15px;
        line-height: 1;
        display: inline-flex;
        transition: background 0.15s, color 0.15s;
      }

      .team-icon-btn:hover {
        background: var(--surface-2);
        color: var(--text-secondary);
      }

      .team-icon-btn.danger:hover {
        background: var(--danger-soft);
        color: var(--danger);
      }

      /* Team panel dropdowns: native select behaviour, dressed like the rest
         of the panel. The chevron is a sibling icon (not a background image)
         so it follows the theme's text color in light and dark mode. */
      .team-select-wrap {
        position: relative;
        display: inline-flex;
        align-items: center;
      }

      .team-select-wrap select {
        appearance: none;
        -webkit-appearance: none;
        font-size: 12px;
        font-weight: 500;
        color: var(--text-secondary);
        background: var(--surface);
        border: 0.5px solid var(--border-input);
        border-radius: 9px;
        padding: 5px 26px 5px 11px;
        cursor: pointer;
        transition: border-color 0.15s, background 0.15s;
      }

      .team-select-wrap select:hover {
        border-color: var(--text-tertiary);
      }

      .team-select-wrap select:focus {
        outline: none;
        border-color: var(--accent);
      }

      .team-select-wrap .ti {
        position: absolute;
        right: 9px;
        font-size: 12px;
        color: var(--text-tertiary);
        pointer-events: none;
        transition: color 0.15s;
      }

      .team-select-wrap select:hover + .ti {
        color: var(--text-secondary);
      }

      /* On/off switch, for a setting that is genuinely binary — a two-option
         <select> makes the reader open a menu to find out there was nothing to
         choose. Built on a real <input type="checkbox"> so it is focusable,
         Space-toggles, and is announced as a checkbox; the input is made
         TRANSPARENT rather than display:none or visibility:hidden, both of
         which would take it out of the tab order along with the pixels.
         Sits alongside .team-select-wrap and borrows its language: the same
         --border-input hairline, the same --accent focus boundary. */
      .sb-switch {
        position: relative;
        display: inline-flex;
        align-items: center;
        /* A base rule, not a phone-only one: the pointer that most often misses
           a 22px control is a thumb, and this row is reachable at every width. */
        min-height: 32px;
        flex-shrink: 0;
        cursor: pointer;
      }

      .sb-switch-input {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        margin: 0;
        opacity: 0;
        cursor: inherit;
      }

      .sb-switch-track {
        width: 40px;
        height: 22px;
        padding: 2px;
        display: inline-flex;
        align-items: center;
        border-radius: var(--radius-pill);
        background: var(--surface-3);
        border: 0.5px solid var(--border-input);
        /* The input is on top; without this the track would eat its own clicks
           in browsers that hit-test the sibling first. */
        pointer-events: none;
        transition: background 0.18s var(--ease), border-color 0.18s var(--ease);
      }

      .sb-switch-knob {
        width: 17px;
        height: 17px;
        border-radius: 50%;
        background: var(--switch-knob);
        border: 0.5px solid var(--border-input);
        box-shadow: var(--shadow-card);
        transition: transform 0.18s var(--ease);
      }

      /* --accent as a FILL and as a boundary, never as ink: nothing is
         written on the track. */
      .sb-switch-input:checked + .sb-switch-track {
        background: var(--accent);
        border-color: var(--accent);
      }

      .sb-switch-input:checked + .sb-switch-track .sb-switch-knob {
        /* 40 track - 4 padding - 1 border - 17 knob. */
        transform: translateX(18px);
      }

      /* Focus lands on the invisible input, so the ring has to be drawn on the
         track. :focus-visible rather than :focus, so a pointer tap does not
         leave a ring sitting there. */
      .sb-switch-input:focus-visible + .sb-switch-track {
        outline: 2px solid var(--accent);
        outline-offset: 2px;
      }

      /* Locked on by real membership. Dimmed and not-allowed rather than
         removed: a control that vanishes leaves the reader wondering where the
         setting went, and the hint beside it explains the lock. */
      .sb-switch-input:disabled {
        cursor: not-allowed;
      }

      .sb-switch-input:disabled + .sb-switch-track {
        opacity: 0.55;
      }

      @media (prefers-reduced-motion: reduce) {
        .sb-switch-track,
        .sb-switch-knob {
          transition: none;
        }
      }

      .team-capture-label {
        display: flex;
        align-items: center;
        gap: 7px;
        font-size: 11.5px;
        color: var(--text-tertiary);
        white-space: nowrap;
      }

      .app-toast {
        position: fixed;
        bottom: 24px;
        left: 50%;
        transform: translateX(-50%) translateY(12px);
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 10px 14px;
        background: var(--surface-elevated);
        border: 1px solid var(--border);
        border-radius: 10px;
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.2s, transform 0.2s;
        z-index: 9999;
        max-width: min(90vw, 420px);
      }

      .app-toast.visible {
        opacity: 1;
        pointer-events: auto;
        transform: translateX(-50%) translateY(0);
      }

      .app-toast-msg {
        font-size: 13px;
        color: var(--text-on-elevated);
      }

      .app-toast-action {
        background: none;
        border: none;
        color: var(--accent-on-elevated);
        font-size: 13px;
        font-weight: 600;
        cursor: pointer;
        padding: 0;
        white-space: nowrap;
      }

      .view-timeline {
        margin-top: 12px;
        padding-top: 12px;
        border-top: 1px solid var(--border);
      }

      .view-timeline-label {
        font-size: 11px;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        color: var(--text-tertiary);
        margin-bottom: 8px;
      }

      .view-timeline-item {
        font-size: 12px;
        color: var(--text-secondary);
        padding: 4px 0;
      }

      /* Why the two view buttons below are unavailable. Tertiary ink: it is a
         footnote on the history, not another entry in it. */
      .view-timeline-note {
        font-size: 12px;
        color: var(--text-tertiary);
        padding: 6px 0 0;
      }

      /* Dimming rather than a colour change — the view buttons already vary
         colour by role (.btn-view-forget carries --danger), and overriding that
         would lose the role while trying to say "unavailable". The list card's
         locked controls share the rule rather than a second one: they are the
         same three buttons over the same row, and two rules would let the two
         surfaces look different about the same fact. */
      .view-btn--locked,
      .card-action-btn--locked {
        opacity: 0.45;
        cursor: not-allowed;
      }

      /* ── Phone-width overrides ─────────────────────────────────────
         Last in the file on purpose. A media query adds no specificity,
         so these have to come after every base rule they override or the
         base rule simply wins — which is what happened when this block
         sat above .team-row and its three-column grid went on applying at
         390px, laying the columns over each other. */
      /* Touch targets on phone-width layouts.
         This stylesheet is mobile-first, so these are the sizes a phone actually
         gets; desktop keeps its own via the min-width:768px blocks above. The
         home topic chips, the layer select and the send arrow all measured
         26-31px tall at 390px wide, which is under every published minimum and
         noticeably fiddly on the one screen where the composer is the whole
         point. Raised to 32px rather than the 44px Apple suggests, because these
         sit in dense rows and 44 would push the composer below the fold — 32 is
         the point at which mis-taps stop, without redesigning the screen. */
      @media (max-width: 767px) {
        .topic-chip,
        .team-select-wrap select,
        .nav-tab {
          min-height: 32px;
        }

        #screen-home .send-btn,
        #screen-recall .send-btn {
          min-width: 32px;
          min-height: 32px;
          display: inline-flex;
          align-items: center;
          justify-content: center;
        }

        /* .filter-field carries no padding of its own — it is a bare input
           inside a padded .filter-inner pill, so the pill looks like the control
           while the thing that actually takes the tap is one line tall (17px).
           Filling the pill costs nothing visually and makes the hit area match
           what the eye already believes it is aiming at. */
        .filter-field {
          min-height: 32px;
        }

        .digest-btn,
        .view-toggle-btn {
          min-height: 32px;
        }

        .team-icon-btn {
          min-width: 32px;
          min-height: 32px;
        }

        /* The roster is a three-column grid — member, capture policy, actions —
           and its two `auto` tracks demand more width than a phone has, so they
           were laid over the first column instead of wrapping: a member's email
           rendered on top of the "Captures:" label, and the role chip on top of
           it again. Stack it. The column headings go with it, because they name
           columns that no longer exist once the row is vertical. */
        .team-head {
          display: none;
        }

        .team-row {
          grid-template-columns: minmax(0, 1fr);
          gap: 10px;
          align-items: flex-start;
          padding: 14px;
        }

        .team-capture {
          justify-content: flex-start;
        }

        .team-actions {
          justify-content: flex-start;
        }

        /* The Memories bar puts the filters and the list/graph toggle on one
           row. At 390px the toggle takes what it needs first and the filter pill
           is left with ~215px for three controls, so each select collapsed to
           40px and every one of them read "All" — the tag filter, the time
           filter and the layer filter became indistinguishable. Wrapping the bar
           gives the filters their own full-width row, which is the only way all
           three labels fit. */
        .mem-bar {
          flex-wrap: wrap;
        }

        .mem-filters {
          flex: 1 0 100%;
          max-width: none;
          order: 2;
        }
      }

      /* The admin activity feed. Rows are separated by a rule rather than by a
         card each: this is a record to be scanned top to bottom, and fifty
         cards read as fifty things to act on. --border, --text-primary and
         --text-tertiary are all defined in the token block above, in both the
         light and dark palettes; nothing here invents a token or carries a
         var() fallback for one that does not exist.

         No new tappable control lives here — #activity-more and
         #activity-export both reuse .digest-btn, which already carries the
         phone tap target. */
      .activity-row {
        padding: 9px 0;
        border-top: 1px solid var(--border);
      }

      .activity-row:first-child {
        border-top: none;
      }

      .activity-line {
        font-size: 12.5px;
        color: var(--text-primary);
      }

      .activity-when {
        font-size: 11.5px;
        color: var(--text-tertiary);
        margin-top: 2px;
      }

      /* ── Memories multi-select ──────────────────────────────────────────
         The bar the Select button raises, and the per-card tick it puts on
         every row while the mode is on. Team brains only: renderBulkBar()
         (js/recent.js) holds both at display:none otherwise. */
      /* Matches .mem-bar directly above it — same gutter, same rule beneath —
         so the two read as one stack of controls rather than a strip that
         wandered in on top of the list. Without the gutter the count sat flat
         against the edge of a phone screen. */
      .mem-bulk-bar {
        display: flex;
        gap: 8px;
        flex-wrap: wrap;
        align-items: center;
        padding: 10px 18px;
        border-bottom: 0.5px solid var(--border);
      }

      /* Two kinds of button share this bar and they are not equivalent.
         Select all, Clear and Done change what is selected or leave the mode;
         Share with team and Make private MOVE memories between layers, and are
         the only controls here that touch data. Same size and same 32px tap
         target — the weight is what differs, so the pair that changes who can
         read a memory is not one of five identical pills. */
      .digest-btn--quiet {
        background: var(--surface-3);
        color: var(--text-secondary);
      }

      .digest-btn--quiet:hover {
        background: var(--surface-2);
      }

      .mem-bulk-count {
        font-size: 12.5px;
        color: var(--text-secondary);
      }

      /* The label, not the input, carries the tap target: a bare 13px checkbox
         is well under the 32px minimum, and growing the box itself would
         change how the control is drawn on every platform. */
      .card-select {
        min-height: 32px;
        min-width: 32px;
        display: inline-flex;
        align-items: center;
      }

      /* The native control is drawn by the OS, so it looked like a different
         product on every platform and ignored the palette entirely. Same shape
         language as the rest: the app's card radius, the app's border, and
         --accent as a FILL when on, never as ink. */
      .card-select input[type='checkbox'] {
        appearance: none;
        -webkit-appearance: none;
        /* The control draws no text, but an unset size leaves the browser's
           13.3333px default in the computed styles and in any audit of the
           page's type scale. */
        font-size: inherit;
        width: 18px;
        height: 18px;
        margin: 0;
        border: 1.5px solid var(--border-input);
        border-radius: 5px;
        background: var(--bg-card);
        cursor: pointer;
        display: grid;
        place-content: center;
        transition: background 0.15s var(--ease), border-color 0.15s var(--ease);
      }

      .card-select input[type='checkbox']::after {
        content: '';
        width: 10px;
        height: 10px;
        transform: scale(0);
        transition: transform 0.12s var(--ease);
        background: var(--switch-knob);
        clip-path: polygon(14% 44%, 0 60%, 39% 100%, 100% 18%, 84% 4%, 39% 68%);
      }

      .card-select input[type='checkbox']:checked {
        background: var(--accent);
        border-color: var(--accent);
      }

      .card-select input[type='checkbox']:checked::after {
        transform: scale(1);
      }

      .card-select input[type='checkbox']:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 2px;
      }

      /* In select mode the tick takes over the gutter the row number sits in.
         Two leading markers on one row is clutter, and the number is the less
         useful of the two while you are picking rows. Putting the tick in the
         gutter rather than in the flow also means the content column does not
         move when select mode turns on — the list does not reflow under your
         thumb. */
      #recent-list .memory-card--selecting::before {
        content: none;
      }

      #recent-list .memory-card--selecting > .card-select {
        position: absolute;
        left: 1px;
        /* Optically centred on the title's first line rather than the card:
           a tall card would otherwise float its tick somewhere near the tags. */
        top: 8px;
        margin: 0;
        justify-content: center;
      }

      /* --accent as a BOUNDARY, never as ink. An outline (rather than a
         border) so a selected card does not shift by a pixel against its
         unselected neighbours. */
      .memory-card--selected {
        outline: 1px solid var(--accent);
        outline-offset: -1px;
      }
