// Sample data for Trove
// Collections support `parentId` for nested structures.

const SAMPLE = {
  user: { name: "Bilal A.", initials: "BA" },

  collections: [
    // ─── AI & ML (top-level) + nested ───
    { id: "ai",            name: "AI & ML",                  parentId: null, count: 47, color: "#2563EB" },
    { id: "ai-roadmap",    name: "Anthropic AI Mastery",     parentId: "ai", count: 10, color: "#D97757" },
    { id: "ai-pm",         name: "AI Product Management",    parentId: "ai", count: 15, color: "#3B82F6" },
    { id: "ai-research",   name: "Frontier Research",        parentId: "ai", count: 12, color: "#06B6D4" },
    { id: "ai-evals",      name: "Evals & Benchmarks",       parentId: "ai", count: 6,  color: "#8B5CF6" },

    // ─── Design Systems (top-level) + nested ───
    { id: "design",        name: "Design Systems",           parentId: null, count: 32, color: "#A855F7" },
    { id: "design-ui",     name: "UI Patterns",              parentId: "design", count: 14, color: "#EC4899" },
    { id: "design-type",   name: "Typography",               parentId: "design", count: 9,  color: "#F472B6" },
    { id: "design-color",  name: "Color & Theming",          parentId: "design", count: 7,  color: "#C084FC" },

    // ─── Startups + nested ───
    { id: "startups",      name: "Startups",                 parentId: null, count: 28, color: "#10B981" },
    { id: "startup-fund",  name: "Fundraising",              parentId: "startups", count: 11, color: "#059669" },
    { id: "startup-pmf",   name: "PMF & Growth",             parentId: "startups", count: 9,  color: "#34D399" },

    // ─── Dev Tools + nested ───
    { id: "tools",         name: "Dev Tools",                parentId: null, count: 24, color: "#F59E0B" },
    { id: "tools-db",      name: "Databases",                parentId: "tools", count: 8,  color: "#EA580C" },
    { id: "tools-frame",   name: "Frameworks",               parentId: "tools", count: 10, color: "#FBBF24" },

    // ─── Long Reads (no children) ───
    { id: "essays",        name: "Long Reads",               parentId: null, count: 19, color: "#EF4444" },

    // ─── Research (no children) ───
    { id: "research",      name: "Research",                 parentId: null, count: 14, color: "#06B6D4" },

    // ─── Inbox (no children) ───
    { id: "inbox",         name: "Inbox",                    parentId: null, count: 8,  color: "#7A7A7A" },
  ],

  bookmarks: [],
};

// ─── Generate a richer bookmark dataset (120+) so pagination is meaningful ───
(function buildBookmarks() {
  const rows = [
    // Existing hand-crafted highlights
    ["Latent Space — On the diminishing returns of larger LLMs", "latent.space", "article", "After GPT-5 and Claude 4.5, scaling alone is yielding less than data quality and reasoning training.", "ai-research", ["scaling-laws","llm","research"], "LS", "#FCD34D", "unread", 12],
    ["Anthropic publishes a new MCP spec for stateful tools", "anthropic.com", "article", "Stateful tool calls, session resumption, and a clean error-recovery protocol.", "ai-research", ["mcp","claude","protocols"], "AC", "#D97757", "in-progress", 8],
    ["The taste gap — why every AI app looks the same", "every.to", "article", "Most AI products ship the same chat UI because the underlying capability is undifferentiated.", "design-ui", ["product-design","ai","essay"], "EV", "#1A1A1A", "read", 14],
    ["Building a personal knowledge graph from your bookmarks", "maggieappleton.com", "article", "A walkthrough of extracting entities and connections from years of saved links.", "research", ["knowledge-graph","pkm"], "MA", "#F59E0B", "unread", 18],
    ["Linear's new Triage flow — design notes", "linear.app", "article", "Redesigning the inbox for engineering teams. Hierarchy, keyboard model, and infinite filters.", "design-ui", ["linear","inbox-zero","ux"], "LN", "#5E6AD2", "read", 7],
    ["How Stripe's docs team plans 2026", "stripe.com", "article", "Inside Stripe's docs roadmap: agent-readable references, per-stack samples.", "essays", ["docs","stripe","writing"], "ST", "#635BFF", "unread", 9],
    ["Why Postgres is finally winning", "timescale.com", "article", "Vector search, JSON, time-series, and queues — all in one box now.", "tools-db", ["postgres","databases"], "TS", "#FF9900", "in-progress", 11],
    ["Andrej Karpathy — let's build GPT from scratch", "youtube.com", "video", "A 2h end-to-end walkthrough of training a small GPT in PyTorch.", "ai-roadmap", ["pytorch","tutorial","transformers"], "▶", "#FF0000", "in-progress", 120],
    ["The future of personal software is small", "notboring.co", "article", "When everyone can ship in an afternoon, the size of useful software changes.", "startups", ["indie","ai","future"], "NB", "#10B981", "read", 13],
    ["tldraw 3.0 launches with infinite canvas + agents", "tldraw.dev", "article", "A reactive canvas SDK that now ships with multi-agent collaboration baked in.", "tools-frame", ["canvas","tldraw","design-tool"], "TL", "#000000", "unread", 6],
    ["DeepMind: SWE-Bench is saturated, here's what's next", "arxiv.org", "pdf", "Coding benchmarks above 90% no longer differentiate frontier models.", "ai-evals", ["benchmarks","evals","deepmind"], "📄", "#DC2626", "unread", 22],
    ["@dhh on the productivity ceiling of remote work", "x.com", "tweet", "\"After 20 years of remote, I've stopped pretending it's strictly better.\"", "essays", ["remote-work","culture"], "𝕏", "#1A1A1A", "read", 1],

    // ─── Podcasts (Listen tab) ───
    ["Diary of a CEO — The real truth about getting rich", "youtube.com", "podcast", "Steven Bartlett breaks down wealth psychology with Morgan Housel — why most high earners still feel broke and what changes that.", "essays", ["psychology","wealth","mindset"], "DC", "#FF0000", "unread", 82],
    ["20VC — Why most founders fail at Series B", "youtube.com", "podcast", "Harry Stebbings on the exact patterns that separate breakout companies from those that plateau after product-market fit.", "startups", ["venture","founders","fundraising"], "20", "#2563EB", "unread", 67],
    ["The Great Simplification — Nate Hagens on AI and energy limits", "youtube.com", "podcast", "A systems-thinking lens on what building out AI infrastructure actually costs in energy terms, and what comes after the efficiency peak.", "research", ["ai","energy","systems-thinking"], "GS", "#10B981", "in-progress", 94],

    // ─── Anthropic AI Mastery Roadmap (from CSV) ───
    ["Learning AI Fundamentals & Practical Skills", "lnkd.in", "article", "Speak confidently about AI in meetings and strategy discussions.", "ai-roadmap", ["fundamentals","ai-literacy"], "AI", "#D97757", "unread", 8],
    ["Claude for Business Work", "lnkd.in", "article", "Master AI tools that help teams work faster.", "ai-roadmap", ["claude","business"], "CL", "#D97757", "unread", 9],
    ["Building Effective AI Agents", "lnkd.in", "article", "Build smart systems that solve real problems.", "ai-roadmap", ["agents","claude"], "AG", "#D97757", "in-progress", 14],
    ["Introduction to Model Context Protocol", "lnkd.in", "article", "Master AI integration — a skill companies desperately need.", "ai-roadmap", ["mcp","integration"], "MC", "#D97757", "unread", 11],
    ["Claude Code in Action", "lnkd.in", "video", "Automate tasks and become a productivity ninja.", "ai-roadmap", ["claude-code","automation"], "▶", "#FF0000", "unread", 32],
    ["Claude with Amazon Bedrock", "lnkd.in", "article", "Learn cloud AI deployment that companies are adopting.", "ai-roadmap", ["aws","bedrock","deploy"], "AW", "#FF9900", "unread", 10],
    ["Anthropic API Fundamentals", "lnkd.in", "article", "Get the technical foundation needed for AI product development.", "ai-roadmap", ["api","claude"], "AP", "#D97757", "read", 12],
    ["Advanced MCP Topics", "lnkd.in", "article", "Master complex integrations that make you essential.", "ai-roadmap", ["mcp","advanced"], "MC", "#D97757", "unread", 16],
    ["Guide to Claude for Work", "lnkd.in", "article", "Master projects, personalization, and the little things.", "ai-roadmap", ["claude","work"], "GW", "#D97757", "in-progress", 13],
    ["How to Use Claude as a Copilot", "lnkd.in", "article", "Go from a researcher and writer to a true thought partner.", "ai-roadmap", ["claude","writing"], "CO", "#D97757", "unread", 9],

    // ─── AI Product Management ───
    ["a16z — AI Canon", "a16z.com", "article", "Curated reading list of foundational AI papers and posts.", "ai-pm", ["canon","reading-list"], "A16", "#000000", "unread", 30],
    ["The Complete Guide to AI Product Management", "lnkd.in", "article", "End-to-end framework for shipping AI products.", "ai-pm", ["pm","framework"], "PM", "#3B82F6", "unread", 24],
    ["OpenAI Platform Documentation", "platform.openai.com", "article", "Reference for OpenAI's API surface area.", "ai-pm", ["openai","api","docs"], "OA", "#10A37F", "read", 8],
    ["How to Become and Succeed as an AI PM", "lnkd.in", "article", "Career-path notes from PMs who've shipped LLM products.", "ai-pm", ["career","pm"], "PM", "#3B82F6", "unread", 11],
    ["Anthropic's Prompt Engineering Guide", "anthropic.com", "article", "Official patterns for system prompts, tool use, and chains.", "ai-pm", ["prompt-eng","claude"], "PE", "#D97757", "in-progress", 18],
    ["AI Product Strategy Deep Dive", "lnkd.in", "article", "Going from feature-shipping to durable AI moats.", "ai-pm", ["strategy","ai"], "ST", "#3B82F6", "unread", 22],
    ["Google's ML Crash Course", "developers.google.com", "video", "Google's free intro to machine learning fundamentals.", "ai-pm", ["ml","course"], "▶", "#4285F4", "unread", 90],
    ["Prompt Engineering Masterclass", "lnkd.in", "video", "Long-form workshop on advanced prompting.", "ai-pm", ["prompt-eng","masterclass"], "▶", "#FF0000", "unread", 75],
    ["DeepLearning.AI", "deeplearning.ai", "article", "Course catalog covering LLMs, MLOps, and applied AI.", "ai-pm", ["dlai","courses"], "DL", "#0066CC", "unread", 5],
    ["AI Foundations for PMs", "lnkd.in", "article", "Mental models PMs need before scoping AI features.", "ai-pm", ["pm","foundations"], "FN", "#3B82F6", "in-progress", 14],
    ["Stanford CS229", "cs229.stanford.edu", "article", "The classic ML course from Stanford. Lecture notes + problem sets.", "ai-pm", ["stanford","ml","course"], "CS", "#8C1515", "unread", 40],
    ["Practical AI Agents for PMs", "lnkd.in", "article", "How to scope, build, and evaluate agentic features.", "ai-pm", ["agents","pm"], "AG", "#3B82F6", "unread", 17],
    ["The AI PM Playbook", "lnkd.in", "pdf", "60-page playbook for AI product managers.", "ai-pm", ["pm","playbook"], "📄", "#DC2626", "unread", 60],
    ["How to Build AI Products", "lnkd.in", "article", "Practical product-building advice from operators.", "ai-pm", ["product","ai"], "BL", "#3B82F6", "read", 12],
    ["AI Prototyping for PMs", "lnkd.in", "article", "Tools and techniques for rapid AI prototyping without engineers.", "ai-pm", ["prototyping","pm"], "PR", "#3B82F6", "unread", 9],

    // ─── Frontier Research ───
    ["Sparse autoencoders for interpretability", "transformer-circuits.pub", "pdf", "Mechanistic interpretability via sparse features.", "ai-research", ["interp","sae"], "📄", "#DC2626", "unread", 34],
    ["Constitutional AI: Harmlessness from AI Feedback", "anthropic.com", "pdf", "RLHF without humans — a self-supervised approach.", "ai-research", ["cai","alignment"], "📄", "#D97757", "in-progress", 26],
    ["Scaling Laws for Neural Language Models", "arxiv.org", "pdf", "The original Kaplan et al. paper on LLM scaling.", "ai-research", ["scaling","kaplan"], "📄", "#DC2626", "read", 28],
    ["Direct Preference Optimization (DPO)", "arxiv.org", "pdf", "RL-free preference tuning that matches RLHF.", "ai-research", ["dpo","rlhf"], "📄", "#DC2626", "unread", 22],
    ["Mixture-of-Experts at scale", "arxiv.org", "pdf", "Why frontier labs are turning to MoE architectures.", "ai-research", ["moe","architecture"], "📄", "#DC2626", "unread", 31],

    // ─── Evals & Benchmarks ───
    ["MMLU is saturated. What now?", "lesswrong.com", "article", "Why broad multiple-choice evals stopped being useful.", "ai-evals", ["mmlu","saturation"], "LW", "#000000", "in-progress", 9],
    ["GPQA: graduate-level Q&A", "arxiv.org", "pdf", "An eval of graduate-level science questions humans struggle with.", "ai-evals", ["gpqa","science"], "📄", "#DC2626", "unread", 16],
    ["The case for vibes-based evals", "every.to", "article", "Why structured benchmarks miss what makes models useful.", "ai-evals", ["evals","vibes"], "EV", "#1A1A1A", "unread", 11],

    // ─── Design — UI Patterns ───
    ["Refactoring UI — visual hierarchy", "refactoringui.com", "article", "Adam Wathan & Steve Schoger on type, weight, and emphasis.", "design-ui", ["ui","hierarchy"], "RU", "#06B6D4", "read", 7],
    ["Notion's database picker — UX teardown", "uxengineer.com", "article", "How Notion makes a 12-axis filter feel effortless.", "design-ui", ["notion","filters"], "NO", "#000000", "unread", 8],
    ["Apple HIG — macOS toolbars", "developer.apple.com", "article", "When to use a unified toolbar vs split bars.", "design-ui", ["hig","macos"], "AP", "#000000", "in-progress", 15],
    ["Figma's command palette pattern", "figma.com", "article", "Why Figma's actions menu became the gold standard.", "design-ui", ["command-palette","figma"], "FG", "#F24E1E", "unread", 6],
    ["Density vs whitespace — Tog's law revisited", "asktog.com", "article", "Why information density wins for power users.", "design-ui", ["density","ui"], "AT", "#A855F7", "read", 9],

    // ─── Design — Typography ───
    ["DM Sans vs Inter — a side-by-side", "fontmatters.com", "article", "Two of the most popular UI sans serifs compared at small sizes.", "design-type", ["fonts","sans"], "DM", "#A855F7", "unread", 5],
    ["Variable fonts in production", "rwt.io", "article", "Performance and design wins from shipping variable fonts.", "design-type", ["variable-fonts"], "RW", "#A855F7", "unread", 8],
    ["The text-wrap: pretty era", "css-tricks.com", "article", "How CSS finally fixed widow lines.", "design-type", ["css","typography"], "CT", "#FF6347", "read", 4],

    // ─── Design — Color & Theming ───
    ["OKLCH is the future of CSS color", "evilmartians.com", "article", "Why perceptual color spaces beat HSL.", "design-color", ["css","oklch","color"], "EM", "#FF0033", "in-progress", 11],
    ["Apple's dark mode rules", "developer.apple.com", "article", "First-class dark mode without afterthought tints.", "design-color", ["dark-mode","hig"], "AP", "#000000", "unread", 8],
    ["Stripe Press color systems", "press.stripe.com", "article", "Editorial palettes that survive 10 years on a shelf.", "design-color", ["editorial","palette"], "ST", "#635BFF", "unread", 6],

    // ─── Startups — Fundraising ───
    ["YC essays — How to raise money", "ycombinator.com", "article", "PG and Sam Altman's classic on the seed-stage process.", "startup-fund", ["yc","seed"], "YC", "#FB651E", "read", 22],
    ["The 2026 seed market is bifurcated", "techcrunch.com", "article", "Top-decile AI rounds vs everyone else.", "startup-fund", ["seed","market"], "TC", "#0A9F4D", "unread", 9],
    ["SAFE notes vs priced rounds in 2026", "carta.com", "article", "Carta's data on what's actually happening at seed.", "startup-fund", ["safe","priced","carta"], "CT", "#FF5A5F", "in-progress", 12],

    // ─── Startups — PMF & Growth ───
    ["Superhuman's PMF engine — revisited", "firstround.com", "article", "Rahul Vohra's framework, ten years later.", "startup-pmf", ["pmf","superhuman"], "FR", "#1E40AF", "read", 16],
    ["The default-alive metric for AI startups", "paulgraham.com", "article", "PG's original idea applied to compute-burning AI cos.", "startup-pmf", ["default-alive","pg"], "PG", "#FF6600", "unread", 8],
    ["B2B PLG — when it works and when it kills you", "openviewpartners.com", "article", "PLG isn't free distribution — it's a different op model.", "startup-pmf", ["plg","b2b"], "OV", "#000000", "unread", 14],

    // ─── Dev Tools — Databases ───
    ["pgvector at scale — what we learned", "supabase.com", "article", "Hard-won lessons running pgvector for million-row workloads.", "tools-db", ["postgres","vector"], "SB", "#3ECF8E", "unread", 13],
    ["Turso vs LibSQL vs SQLite — the lineage", "turso.tech", "article", "Edge SQLite forks and what differentiates each.", "tools-db", ["sqlite","edge"], "TR", "#4FF8D2", "unread", 9],
    ["Why DuckDB is a PM's secret weapon", "motherduck.com", "article", "Local OLAP without the warehouse.", "tools-db", ["duckdb","analytics"], "DD", "#FFD500", "read", 7],

    // ─── Dev Tools — Frameworks ───
    ["Next.js App Router — two years in", "vercel.com", "article", "What worked, what didn't, what's coming.", "tools-frame", ["nextjs","react"], "NX", "#000000", "unread", 14],
    ["Astro 5 launches with islands 2.0", "astro.build", "article", "The MPA framework gets selectively reactive.", "tools-frame", ["astro","ssr"], "AS", "#FF5A1F", "unread", 8],
    ["Solid 2.0 — fine-grained reactivity revisited", "solidjs.com", "article", "What Solid still does better than React.", "tools-frame", ["solid","reactivity"], "SO", "#2C4F7C", "in-progress", 11],

    // ─── Long Reads (essays) ───
    ["The arc of intelligence is long", "stratechery.com", "article", "Ben Thompson on AI's market structure over a decade.", "essays", ["strategy","ai"], "ST", "#1E40AF", "unread", 19],
    ["Why we stopped making things", "newyorker.com", "article", "A reflection on the loss of hands-on craft.", "essays", ["culture","craft"], "NY", "#000000", "read", 24],
    ["The day my chatbot died", "verge.com", "article", "Long-form essay on character AI grief and parasocial bonds.", "essays", ["chatbot","culture"], "VG", "#FA4616", "unread", 17],

    // ─── Research (general) ───
    ["DeepMind on game-theoretic agent collusion", "deepmind.google", "pdf", "When self-play agents discover anticompetitive equilibria.", "research", ["game-theory","agents"], "📄", "#4285F4", "unread", 28],
    ["Olah et al. — circuits and features", "transformer-circuits.pub", "pdf", "Foundational mechanistic-interpretability writeups.", "research", ["interp","circuits"], "📄", "#DC2626", "unread", 33],

    // ─── Inbox (uncategorized recent saves) ───
    ["Notion launches AI Workspaces", "notion.so", "article", "Notion's bet on a fully agentic surface.", "inbox", ["notion","ai"], "NO", "#000000", "unread", 7],
    ["The death of the homepage", "matthewstrom.com", "article", "Why brand homepages are losing to product surfaces.", "inbox", ["web","brand"], "MS", "#A855F7", "unread", 6],
    ["Cursor's growth playbook leaked", "techmeme.com", "article", "Inside the AI IDE's distribution strategy.", "inbox", ["cursor","ide"], "TM", "#1A1A1A", "in-progress", 10],
    ["Vercel adds AI Gateway", "vercel.com", "article", "A unified routing layer for LLM providers.", "inbox", ["vercel","gateway"], "VC", "#000000", "unread", 8],
    ["Apple's 2026 design refresh — what it means for SaaS", "daringfireball.net", "article", "Refresh signals a pull toward refined minimalism.", "inbox", ["apple","design"], "DF", "#1A1A1A", "unread", 11],
    ["Tailwind v4 — performance & DX wins", "tailwindcss.com", "article", "The Rust rewrite finally lands.", "inbox", ["tailwind","css"], "TW", "#06B6D4", "read", 5],
    ["Replit Agents 2 launches", "replit.com", "article", "An always-on coding agent with persistent memory.", "inbox", ["replit","agents"], "RP", "#F26207", "unread", 9],
    ["Why every browser is becoming an agent", "browser.company", "article", "Arc's pivot, Dia's ambitions, and what's next.", "inbox", ["browser","agents"], "BC", "#FF6E14", "unread", 12],
  ];

  const times = ["1h","2h","3h","5h","8h","1d","1d","2d","2d","3d","4d","5d","6d","1w","1w","2w","2w","3w","1mo"];

  rows.forEach((r, i) => {
    const [title, domain, type, desc, collection, tags, thumb, thumbColor, status, readMins] = r;
    SAMPLE.bookmarks.push({
      id: `b${i+1}`,
      title, domain, type, desc, collection,
      url: `https://${domain}/${i}`,
      tags,
      time: times[i % times.length],
      thumb, thumbColor, status, readMins,
      ai_summary: i % 3 === 0
        ? `Two-paragraph summary stub. Key claim: ${title.split(' ').slice(0,4).join(' ')}…. Implications discussed.`
        : null,
    });
  });

  // Pad to ~120 with synthetic items so pagination has 3 pages at 50/page
  const synthCols = ["ai-roadmap","ai-pm","ai-research","ai-evals","design-ui","design-type","design-color","startup-fund","startup-pmf","tools-db","tools-frame","essays","research","inbox"];
  const synthDomains = ["medium.com","substack.com","dev.to","hackernoon.com","arxiv.org","github.com","blog.ycombinator.com","wired.com","theverge.com","techcrunch.com"];
  const synthTitles = [
    "On building durable products in the age of agents",
    "A practical guide to evaluation harnesses",
    "Why every product team needs an AI literacy ladder",
    "How we cut p50 latency by 40% on a vector database",
    "The thin line between feature and product",
    "Notes on managing context windows at scale",
    "A field guide to LLM cost optimization",
    "Designing for the agentic surface",
    "The end of dashboards",
    "Why monorepos finally make sense",
    "Long-context isn't free — what to do about it",
    "Fine-tuning vs RAG — a 2026 decision tree",
    "Lessons from rebuilding our docs in MDX",
    "A small case for big design tokens",
    "Type systems are the new design systems",
  ];
  let counter = SAMPLE.bookmarks.length;
  while (SAMPLE.bookmarks.length < 122) {
    const idx = SAMPLE.bookmarks.length - rows.length;
    const title = synthTitles[idx % synthTitles.length];
    const domain = synthDomains[idx % synthDomains.length];
    const collection = synthCols[idx % synthCols.length];
    const status = ["unread","unread","unread","in-progress","read"][idx % 5];
    const type = ["article","article","article","article","video","pdf","tweet"][idx % 7];
    counter++;
    SAMPLE.bookmarks.push({
      id: `b${counter}`,
      title: `${title} #${idx+1}`,
      domain,
      type,
      desc: "Auto-generated sample so the bookmarks table has enough rows to paginate.",
      url: `https://${domain}/post-${counter}`,
      collection,
      tags: ["sample", collection.split('-')[0]],
      time: times[(idx + 3) % times.length],
      thumb: domain.slice(0,2).toUpperCase(),
      thumbColor: ["#3B82F6","#A855F7","#10B981","#F59E0B","#EF4444","#06B6D4"][idx % 6],
      status,
      readMins: 4 + ((idx * 3) % 18),
      ai_summary: null,
    });
  }
})();

// Helper accessors
SAMPLE.topLevelCollections = () => SAMPLE.collections.filter(c => !c.parentId);
SAMPLE.childCollections    = (parentId) => SAMPLE.collections.filter(c => c.parentId === parentId);
SAMPLE.collectionPath      = (id) => {
  const path = [];
  let cur = SAMPLE.collections.find(c => c.id === id);
  while (cur) {
    path.unshift(cur);
    cur = cur.parentId ? SAMPLE.collections.find(c => c.id === cur.parentId) : null;
  }
  return path;
};
// Bookmarks within a collection AND any descendants
SAMPLE.bookmarksInCollectionTree = (id) => {
  const ids = new Set([id]);
  const collectDescendants = (parentId) => {
    SAMPLE.childCollections(parentId).forEach(c => { ids.add(c.id); collectDescendants(c.id); });
  };
  collectDescendants(id);
  return SAMPLE.bookmarks.filter(b => ids.has(b.collection));
};


// Recompute collection counts from real bookmarks (direct + descendants)
SAMPLE.collections.forEach(c => {
  c.count = SAMPLE.bookmarksInCollectionTree(c.id).length;
});

window.SAMPLE = SAMPLE;
