  /* ── Warm-status palette ── */
  /* Replaces scattered raw hex (#10b981, #ef4444, #94a3b8) that didn't
     harmonize with the cream "retro" base. Used by sparkline strokes,
     market-signal strip, sentiment dots, tooltip background. Coffee theme
     gets brightened equivalents that read on dark base. */
  :root {
    --warm-up:      #7d8c4d;  /* sage olive — bullish/利好/up */
    --warm-down:    #b04a2e;  /* terracotta — bearish/警惕/down */
    --warm-watch:   #cc8b1f;  /* amber — observe/watch */
    --warm-neutral: #8a7c66;  /* warm slate — baseline */
    --warm-tip-bg:  #2d1f0f;  /* tooltip dark coffee */
    --warm-tip-fg:  #f4ead0;  /* warm cream foreground */
  }
  [data-theme="coffee"] {
    --warm-up:      #a8b56b;
    --warm-down:    #cc6649;
    --warm-watch:   #e4a93f;
    --warm-neutral: #a89682;
    --warm-tip-bg:  #f4ead0;
    --warm-tip-fg:  #2d1f0f;
  }

  /* ── Typography stack ── */
  /* Apple devices get PingFang automatically; Windows falls to Microsoft YaHei.
     Tabular numerals make %/数字 columns line up cleanly. */
  html, body {
    font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB",
                 "Microsoft YaHei", "Helvetica Neue", Helvetica, "Source Han Sans SC",
                 system-ui, sans-serif;
    font-feature-settings: "tnum" 1, "kern" 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
  html { transition: background-color 0.3s, color 0.3s; }

  /* ── Paper texture ── */
  /* Subtle SVG fractal noise tiled on body bg. Adds tactile "real paper"
     feel to the cream "retro" base without web fonts or assets. Only ~6%
     alpha so it's perceptual atmosphere, not visual noise. background-
     attachment:fixed keeps the grain stable as the user scrolls. */
  body {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.18 0 0 0 0 0.10 0 0 0 0 0.04 0 0 0 0.07 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
    background-size: 180px 180px;
    background-attachment: fixed;
  }
  /* Mobile Safari has known bugs with background-attachment: fixed
     (breaks sticky elements like navbar / GSI iframe rendering).
     Use scroll attachment on touch viewports — slight perf cost (the
     noise scrolls with content) but safer for navbar children. */
  @media (max-width: 1023px) {
    body { background-attachment: scroll; }
  }

  /* ── Skeleton loaders ── */
  /* Replaces "Loading..." plain text in stream / story cards / market
     signals while waiting for network. Shimmer goes left-to-right at
     1.6s; alpha-mixed via base tokens so coffee theme reads correctly. */
  .mml-skel {
    border-radius: 8px;
    /* rgba wheat tones — retro base-200 is ~#e4d8b4 cream, so a warm
       tan grey at varying alpha gives a visible shimmer on it. (Was
       hsl(var(--b1)) which silently rendered transparent → no skeleton.) */
    background: linear-gradient(
      90deg,
      rgba(160, 140, 110, 0.18) 0%,
      rgba(160, 140, 110, 0.42) 50%,
      rgba(160, 140, 110, 0.18) 100%);
    background-size: 200% 100%;
    animation: mml-shimmer 1.6s linear infinite;
  }
  [data-theme="coffee"] .mml-skel {
    background: linear-gradient(
      90deg,
      rgba(255, 240, 220, 0.05) 0%,
      rgba(255, 240, 220, 0.18) 50%,
      rgba(255, 240, 220, 0.05) 100%);
    background-size: 200% 100%;
  }
  .mml-skel-card      { height: 84px; }
  .mml-skel-card.tall { height: 120px; }
  .mml-skel-card.lo   { height: 56px; }
  .mml-skel-rail-card { height: 64px; border-radius: 12px; }
  @keyframes mml-shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
  }

  /* ── Hint button (warm soft) ── */
  /* Replaces btn-outline btn-ghost (white outline thin) — that read as
     "weak suggestion" against cream cards. New treatment: very light
     warm fill, no border, hover lifts to primary-tinted. Active state
     (after click) keeps the primary fill from JS. */
  .hint-btn-warm {
    background: rgba(0, 0, 0, 0.045) !important;
    color: rgba(0, 0, 0, 0.78) !important;
    border: 1px solid transparent !important;
    transition: background 0.18s ease-out, color 0.18s, transform 0.12s;
  }
  .hint-btn-warm:hover {
    /* Same OKLCH/HSL mismatch fix — use the amber accent at low alpha */
    background: rgba(204, 139, 31, 0.18) !important;
    color: rgba(0, 0, 0, 0.92) !important;
    transform: translateX(2px);
  }
  /* Selected state — JS adds .btn-active after click. Without this rule,
     the !important warm bg blocked daisyUI's .btn-primary fill, so click
     had no visual feedback (the bug). Amber filled = "I picked this". */
  .hint-btn-warm.btn-active,
  .hint-btn-warm.btn-active:hover {
    background: var(--warm-watch) !important;
    color: #fff !important;
    transform: none !important;
    cursor: default;
  }
  [data-theme="coffee"] .hint-btn-warm {
    background: rgba(255, 255, 255, 0.06) !important;
    color: rgba(255, 255, 255, 0.82) !important;
  }
  [data-theme="coffee"] .hint-btn-warm:hover {
    background: rgba(228, 169, 63, 0.22) !important;
    color: rgba(255, 255, 255, 0.96) !important;
  }
  [data-theme="coffee"] .hint-btn-warm.btn-active,
  [data-theme="coffee"] .hint-btn-warm.btn-active:hover {
    background: var(--warm-watch) !important;
    color: #1c1210 !important;
  }

  /* ── Dual-tab layout (ship 11) ──
     PC: Feed pane shows 2 columns (时间倒排 + 推荐排序) side-by-side.
     Mobile: Feed pane shows 1 column at a time (toggled via top-right
     button, Twitter-style). Card pane unaffected — same content stacked
     vertically on both. */
  .feed-col {
    min-width: 0;  /* allow grid children to shrink below content width */
  }
  @media (max-width: 1023px) {
    /* Hide both columns by default on mobile; .mobile-active reveals one. */
    .feed-col { display: none; }
    .feed-col.mobile-active { display: block; }
  }

  /* Tab nav — daisyUI tabs-boxed with warm accent on active */
  .tabs.tabs-boxed .tab.tab-active {
    background: var(--warm-watch);
    color: #fff;
  }

  /* ── Rail strip layout ──
     Vertical column on both PC + mobile. Mobile shows only top-2 by
     default with a "查看全部" button to expand (rather than horizontal
     scroll which had carousel chaos: uneven card heights, partial cards
     at edges, accumulated section ornament noise). Density wins via
     compactness, not via squeezing horizontal carousels. */
  .rail-strip {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
  }
  .rail-strip.story-rail {
    gap: 0.625rem;
  }

  /* "查看全部 N →" button — only visible on mobile, only when there's
     more than 2 items to show. Click toggles .expanded on the previous
     .rail-strip sibling to reveal/collapse the rest. */
  .rail-show-all {
    display: none;
    width: 100%;
    margin-top: 0.4rem;
    font-size: 11px;
    font-weight: 500;
    text-align: center;
    padding: 0.5rem 0.75rem;
    background: rgba(204, 139, 31, 0.10);
    color: rgba(0, 0, 0, 0.62);
    border: 1px dashed rgba(204, 139, 31, 0.35);
    border-radius: 0.5rem;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
  }
  .rail-show-all:hover {
    background: rgba(204, 139, 31, 0.18);
    color: rgba(0, 0, 0, 0.88);
  }
  [data-theme="coffee"] .rail-show-all {
    background: rgba(228, 169, 63, 0.12);
    color: rgba(255, 255, 255, 0.65);
    border-color: rgba(228, 169, 63, 0.35);
  }
  [data-theme="coffee"] .rail-show-all:hover {
    background: rgba(228, 169, 63, 0.22);
    color: rgba(255, 255, 255, 0.95);
  }

  @media (max-width: 1023px) {
    /* Ship 11.1: Card 流 tab 取代了"右栏挤在 stream 上方"布局, 不再
       有空间竞争, mobile 也全展开 (移除 top-2 折叠). 信息密度优先. */
    .rail-show-all { display: none; }  /* 按钮也不再用了 */
    /* Section ornament hidden on mobile (减少视觉噪音, 跟 Ship 6 决策一致) */
    .section-bar { padding-top: 0; }
    .section-bar::before,
    .section-bar::after { display: none; }
  }

  /* Hint area collapsible (<details>). Custom triangle marker via ::before
     so PC + mobile share the same "▸ rotates to ▾ when open" affordance.
     Default rendering: PC renders <details open> via JS so old behavior
     stays; mobile renders collapsed for density. */
  .hint-summary {
    list-style: none;
    cursor: pointer;
    position: relative;
    padding-left: 12px;
    user-select: none;
  }
  .hint-summary::-webkit-details-marker { display: none; }
  .hint-summary::before {
    content: "▸";
    position: absolute;
    left: 0;
    transition: transform 0.18s ease-out;
    font-size: 9px;
    top: 1px;
  }
  details[open] > .hint-summary::before {
    transform: rotate(90deg);
  }

  /* ── Story Card design language ── */
  /* 3px accent strip on the left edge, color reflects status. DaisyUI 4
     uses OKLCH tokens (var(--bc) etc), so the easier path is to hardcode
     hex — they look the same on both retro & coffee themes. */
  .story-card {
    position: relative;
    overflow: hidden;
  }
  .story-card::before {
    content: "";
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: #cbd5e1;
    transition: background 0.2s;
  }
  .story-card[data-status="new"]::before     { background: var(--warm-watch); }
  .story-card[data-status="updated"]::before { background: #a8775c; } /* warm copper, was cool blue */
  .story-card[data-status="stable"]::before  { background: var(--warm-neutral); }
  .story-card { transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s; }
  .story-card:hover { transform: translateY(-1px); }
  .story-card .summary-block {
    /* Soft warm tint so the LLM briefing reads like a featured pull-quote,
       distinct from the bullet list below. Color picked from primary token
       (gold-orange in retro theme) at low alpha. */
    background: rgba(245, 158, 11, 0.05);
    border-radius: 0.5rem;
    padding: 0.55rem 0.7rem;
    line-height: 1.75;
    font-size: 12.5px;
    color: rgba(0, 0, 0, 0.72);
    text-justify: inter-ideograph;
    word-break: break-word;
  }
  [data-theme="coffee"] .story-card .summary-block {
    background: rgba(245, 158, 11, 0.08);
    color: rgba(255, 255, 255, 0.78);
  }
  .story-card .summary-block strong { font-weight: 600; }

  /* Section header bar — magazine-style "pull-quote" anchor.
     ::before is a 32×3px primary accent strip above the header (the
     visual anchor that says "this is a section"). ::after extends a
     1px hairline rule to the right margin for the trailing flourish. */
  .section-bar {
    display: flex; align-items: baseline; gap: 0.75rem;
    margin-bottom: 0.5rem; padding: 0.6rem 0.25rem 0;
    position: relative;
  }
  .section-bar::before {
    content: "";
    position: absolute;
    top: 0; left: 0.25rem;
    width: 36px; height: 3px;
    /* Warm amber direct hex — DaisyUI 4 retro stores --p as OKLCH triples
       so hsl(var(--p) / x) silently rendered transparent. Using
       --warm-watch keeps consistency with other accents. */
    background: var(--warm-watch);
    border-radius: 1px;
  }
  .section-bar h3 { font-weight: 800; letter-spacing: -0.01em; }
  .section-bar::after {
    content: ""; flex: 1; height: 1px;
    /* Same OKLCH/HSL mismatch as ::before — was silently transparent. */
    background: rgba(0, 0, 0, 0.10);
    align-self: center;
  }
  [data-theme="coffee"] .section-bar::after {
    background: rgba(255, 255, 255, 0.12);
  }

  /* Top Stories ticker tile lift */
  .ts-tile { transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s; }
  .ts-tile:hover { transform: translateY(-1px); }

  /* ── PINNED alert card variant — used for urgent_alerts inside the
     urgent-alerts rail (Ship 27 renamed from market-signals-rail).
     Slightly tinted background + thicker accent strip + brief one-time
     pulse on alerts the user hasn't seen. ── */
  .signal-card.pinned {
    border-width: 1px;
    border-left-width: 4px !important;
  }
  /* hex base-100 instead of hsl(var(--b1)) — that resolved transparent
     so gradient fell through to page bg by accident; explicit cream end
     stop matches the intent ("urgency tint fades back to card bg"). */
  .signal-card.pinned.urg-high {
    background: linear-gradient(135deg, #fef2f2 0%, #efeae0 60%);
    border-left-color: #dc2626 !important;
  }
  .signal-card.pinned.urg-med {
    background: linear-gradient(135deg, #fffbeb 0%, #efeae0 60%);
    border-left-color: #f59e0b !important;
  }
  .signal-card.pinned.urg-low {
    background: linear-gradient(135deg, #fefce8 0%, #efeae0 60%);
    border-left-color: #ca8a04 !important;
  }
  [data-theme="coffee"] .signal-card.pinned.urg-high {
    background: linear-gradient(135deg, #4a1c1c 0%, #221610 60%);
  }
  [data-theme="coffee"] .signal-card.pinned.urg-med {
    background: linear-gradient(135deg, #4a3a14 0%, #221610 60%);
  }
  [data-theme="coffee"] .signal-card.pinned.urg-low {
    background: linear-gradient(135deg, #3a3414 0%, #221610 60%);
  }
  .signal-card.pinned.fresh { animation: pinned-pulse 2.4s ease-in-out 2; }
  @keyframes pinned-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
    50%      { box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.20); }
  }

  /* ── Legacy ticker (unused, kept for parity) ── */
  .scroll-sentinel { height: 1px; }
  .ticker-wrap { overflow: hidden; white-space: nowrap; }
  .ticker-track {
    display: inline-flex;
    animation: ticker-scroll 40s linear infinite;
    gap: 32px;
    padding-right: 32px;
  }
  .ticker-track:hover { animation-play-state: paused; }
  @keyframes ticker-scroll {
    0% { transform: translateX(0); }
    100% { transform: translateX(-50%); }
  }

  /* ── Memory source toggle (declared / combined / derived) ──
     Used by Memory Widget on home page + mdfile preview on memory page.
     Sage active highlight matches --warm-up; ghost rest state. */
  .source-btn {
    font-size: 10.5px;
    height: 22px;
    min-height: 22px;
    padding: 0 8px;
    border: 1px solid transparent;
    color: #6b7752;
    letter-spacing: 0.3px;
  }
  .source-btn:hover:not(.btn-disabled) {
    background: rgba(125, 140, 77, 0.10);
    border-color: rgba(125, 140, 77, 0.18);
  }
  .source-btn-active {
    background: rgba(125, 140, 77, 0.20);
    border-color: rgba(125, 140, 77, 0.45);
    color: #4a5b2d;
    font-weight: 700;
  }
