<!doctype html>
<html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>weekly digest</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;700;800;900&amp;family=Inter:wght@400;500;600;700&amp;display=swap" rel="stylesheet">
<style>
  /* ============================================================
     BOLD direction — white canvas, heavy Archivo display, single
     vermilion accent, flat ink borders + hard offset shadows.
     Background stays white per brief; boldness comes from type
     weight, scale, and a decisive accent — not from a dark canvas.
     ============================================================ */
  :root{
    --bg:#ffffff;
    --surface:#ffffff;
    --wash:#f5f5f3;
    --ink:#0d0d10;
    --ink-2:#3b3b44;
    --muted:#74747f;
    --line:#0d0d10;            /* bold borders = ink */
    --line-soft:#e7e7ec;

    --accent:#ff3b2f;          /* vermilion */
    --accent-ink:#c81f15;
    --accent-on:#ffffff;

    /* bold, distinct semantic hues (none equal to nothing-but-accent confusion) */
    --c-decided:#13a05c;       /* settled            */
    --c-todo:#ff3b2f;          /* action on you      */
    --c-ask:#e98a00;           /* open question      */
    --c-at:#7c3aed;            /* you were mentioned */

    --font-display:"Archivo",-apple-system,BlinkMacSystemFont,system-ui,sans-serif;
    --font-body:"Inter",-apple-system,BlinkMacSystemFont,system-ui,sans-serif;

    --r:14px;
    --r-sm:10px;
    --shadow-hard:5px 5px 0 var(--ink);
    --shadow-accent:5px 5px 0 var(--accent);
    --maxw:980px;
  }

  *{box-sizing:border-box}
  html{-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
  body{
    font-family:var(--font-body);
    color:var(--ink);line-height:1.5;margin:0;background:var(--bg);
    font-variant-numeric:tabular-nums;
  }
  .num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
  .ic{width:16px;height:16px;flex:0 0 auto}
  .wrap{max-width:var(--maxw);margin:0 auto;padding:44px 28px 88px}
  @media(max-width:680px){.wrap{padding:28px 18px 64px}}

  /* ---- masthead ---- */
  .mast{display:flex;align-items:center;gap:14px;margin-bottom:34px}
  .mast .mark{width:46px;height:46px;border-radius:12px;display:grid;place-items:center;color:var(--accent-on);
    background:var(--accent);flex:0 0 auto;border:2px solid var(--ink);box-shadow:3px 3px 0 var(--ink)}
  .mast .mark .ic{width:23px;height:23px}
  .mast .nm{font-size:20px;font-weight:900;letter-spacing:-.02em;font-family:var(--font-display);line-height:1.05}
  .mast .wk{font-size:13px;color:var(--muted);margin-top:2px;font-weight:500}
  .mast .badge{margin-left:auto;font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--ink);
    background:#fff;border:2px solid var(--ink);border-radius:999px;padding:7px 15px}

  /* ---- lede ---- */
  .lede{font-size:clamp(34px,6vw,58px);line-height:1.02;font-weight:900;letter-spacing:-.035em;
    text-wrap:balance;margin:0 0 32px;font-family:var(--font-display);max-width:16ch}
  .lede em{font-style:normal;color:var(--accent);
    background:linear-gradient(transparent 70%, color-mix(in srgb,var(--accent) 22%, #fff) 0);padding:0 .04em}

  /* ---- grid ---- */
  .bento{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
  .tile{background:var(--surface);border:2px solid var(--ink);border-radius:var(--r);padding:22px}
  .span2{grid-column:span 2}
  .span4{grid-column:span 4}
  @media(max-width:860px){.bento{grid-template-columns:1fr 1fr}.span2{grid-column:span 1}.span4{grid-column:1/-1}}

  /* stat tiles */
  .stat{display:flex;flex-direction:column;justify-content:space-between;min-height:120px;padding:18px;box-shadow:var(--shadow-hard)}
  .stat .v{font-size:clamp(34px,5vw,48px);font-weight:900;letter-spacing:-.04em;line-height:.92;font-family:var(--font-display)}
  .stat .k{font-size:12px;color:var(--muted);margin-top:12px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}
  .stat.hl{background:var(--accent);border-color:var(--ink);box-shadow:var(--shadow-hard)}
  .stat.hl .v{color:#fff}
  .stat.hl .k{color:rgba(255,255,255,.85)}

  /* section header */
  .sec-h{display:flex;align-items:center;gap:12px;margin-bottom:6px}
  .sec-h h2{margin:0;font-size:13px;font-weight:900;letter-spacing:.06em;text-transform:uppercase;color:var(--ink);font-family:var(--font-display)}
  .sec-h .sub{font-size:12px;color:var(--muted);margin-left:auto;font-weight:700}
  .lead{font-size:13.5px;color:var(--ink-2);margin:0 0 20px;text-wrap:pretty;font-weight:500}

  /* ---- digest feed ---- */
  .split{display:grid;grid-template-columns:1fr 1fr;gap:14px 28px;align-items:start}
  @media(max-width:720px){.split{grid-template-columns:1fr;gap:22px}}
  .col-need{order:1}.col-done{order:2}
  .grp-h{display:flex;align-items:center;gap:9px;margin:0 0 12px;padding-bottom:9px;border-bottom:2px solid var(--ink)}
  .grp-h h3{margin:0;font-family:var(--font-display);font-weight:900;font-size:13px;letter-spacing:.04em;text-transform:uppercase}
  .grp-dot{width:11px;height:11px;border-radius:3px;background:var(--c);flex:0 0 auto}
  .grp-n{margin-left:auto;font-size:12px;font-weight:800;color:var(--muted);font-variant-numeric:tabular-nums}
  .feed{list-style:none;margin:0;padding:0;display:grid;gap:10px}
  .feed li{display:flex;gap:14px;align-items:flex-start;
    background:var(--wash);border:1.5px solid var(--line-soft);border-radius:12px;padding:14px 16px}
  .feed .av{width:42px;height:42px;border-radius:10px;flex:0 0 auto;border:2px solid var(--ink);background:#fff;object-fit:cover}
  .feed .ico{width:42px;height:42px;border-radius:10px;display:grid;place-items:center;flex:0 0 auto;
    background:var(--c);color:#fff;border:2px solid var(--ink)}
  .feed .ico .ic{width:20px;height:20px}
  .feed .body{min-width:0;flex:1}
  .feed .lab{font-size:10px;font-weight:900;letter-spacing:.09em;text-transform:uppercase;color:var(--c);font-family:var(--font-display)}
  .feed .tx{font-size:15px;color:var(--ink);margin-top:3px;line-height:1.42;text-wrap:pretty;font-weight:500}
  .feed .tx b{font-weight:800}
  .feed .mt{font-size:12px;color:var(--muted);margin-top:5px;font-weight:600}

  /* initials avatar (self-contained — no network image) */
  .avi{display:grid;place-items:center;color:#fff;font-family:var(--font-display);
    font-weight:900;font-size:14px;letter-spacing:.01em;line-height:1}

  .restline{display:flex;gap:10px;flex-wrap:wrap;margin-top:20px;font-size:12.5px;color:var(--muted);align-items:center;font-weight:600}
  .pill{display:inline-flex;align-items:center;gap:8px;background:#fff;border:2px solid var(--ink);
    border-radius:999px;padding:6px 14px;font-weight:600}
  .pill .d{width:8px;height:8px;border-radius:50%;background:var(--c)}
  .pill b{color:var(--ink);font-weight:800}

  /* ---- topics bars ---- */
  .bars{display:grid;gap:16px;margin-top:4px}
  .bar{display:grid;grid-template-columns:1fr auto;gap:7px 12px;align-items:center}
  .bar .bn{font-size:14px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:var(--font-display)}
  .bar .bc{font-size:14px;color:var(--ink);font-weight:800;text-align:right;font-family:var(--font-display)}
  .bar .tr{grid-column:1/-1;height:14px;border-radius:7px;background:var(--wash);overflow:hidden;border:1.5px solid var(--ink)}
  .bar .tr i{display:block;height:100%;border-radius:0;transition:width .7s cubic-bezier(.2,0,0,1)}

  /* ---- people leaderboard ---- */
  .plist{display:grid;gap:14px;margin-top:4px}
  .prow{display:grid;grid-template-columns:auto auto 1fr auto;gap:12px;align-items:center}
  .prow .rank{font-size:16px;font-weight:900;color:var(--muted);font-family:var(--font-display);width:18px;text-align:center}
  .prow .av{width:40px;height:40px;border-radius:10px;border:2px solid var(--ink);background:#fff;flex:0 0 auto}
  .prow .pm{min-width:0;display:grid;gap:6px}
  .prow .pn{font-size:14px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:var(--font-display)}
  .prow .pn .me{font-size:10px;font-weight:900;color:#fff;background:var(--accent);border-radius:5px;padding:2px 7px;margin-left:8px;vertical-align:1px}
  .prow .tr{height:12px;border-radius:6px;background:var(--wash);overflow:hidden;border:1.5px solid var(--ink)}
  .prow .tr i{display:block;height:100%;background:var(--accent);transition:width .7s cubic-bezier(.2,0,0,1)}
  .prow .pc{font-size:15px;font-weight:900;font-family:var(--font-display)}

  footer{text-align:center;font-size:12px;color:var(--muted);margin-top:34px;padding-top:22px;font-weight:600}
</style>
</head>
<body>
<div class="wrap">

  <header class="mast">
    <span class="mark"><svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-8.5 8.5 8.5 8.5 0 0 1-3.9-.9L3 21l1.9-5.6a8.5 8.5 0 0 1-.9-3.9A8.38 8.38 0 0 1 12.5 3 8.38 8.38 0 0 1 21 11.5z"></path></svg></span>
    <div>
      <div class="nm" id="group"></div>
      <div class="wk" id="week"></div>
    </div>
    <span class="badge">This week</span>
  </header>

  <p class="lede" id="lede"></p>

  <!-- stat tiles -->
  <div class="bento" id="stats" style="margin-bottom:16px"></div>

  <!-- content tiles -->
  <div class="bento">
    <section class="tile span4">
      <div class="sec-h"><h2>While you were away</h2><span class="sub" id="away-sub"></span></div>
      <p class="lead">The handful of things actually worth knowing — what the group decided, and what's waiting on you.</p>
      <div class="split">
        <div class="col col-need">
          <div class="grp-h"><span class="grp-dot" style="--c:var(--c-todo)"></span><h3>Needs you</h3><span class="grp-n" id="need-n"></span></div>
          <ul class="feed" id="feed-need"></ul>
        </div>
        <div class="col col-done">
          <div class="grp-h"><span class="grp-dot" style="--c:var(--c-decided)"></span><h3>Decided</h3><span class="grp-n" id="done-n"></span></div>
          <ul class="feed" id="feed-done"></ul>
        </div>
      </div>
      <div class="restline" id="restline"></div>
    </section>

    <section class="tile span2">
      <div class="sec-h"><h2>What people talked about</h2><span class="sub" id="topics-sub"></span></div>
      <div class="bars" id="topics"></div>
    </section>

    <section class="tile span2">
      <div class="sec-h"><h2>Who was most active</h2><span class="sub" id="people-sub"></span></div>
      <div class="plist" id="people"></div>
    </section>
  </div>

  <footer id="foot"></footer>
</div>

<script>
/* ============================================================================
   WEEKLY DIGEST — data contract.
   Fill DATA from the WhatsApp digest, then everything below renders it.
   Only edit DATA. The render code does not need changing.

   FIELDS
   - group   : group name shown in the masthead.
   - week    : human week range, e.g. "Mon 8 – Sun 14 Jun 2026".
   - stats   : { messages, people, busiestDay, needYou } — the 4 top tiles.
   - needsYou: items waiting on the reader. type ∈ "do" | "ask" | "at".
               tx supports <b>…</b>. who = sender display name (drives avatar).
   - decided : settled items. tx supports <b>…</b>. mt = meta line, e.g.
               "Decided Thu · Match logistics".
   - restline: small "quietly handled" pills. type ∈ "ask" | "at" | "do" | "ok".
   - topics  : top themes, pre-sorted desc (max ~6). { n, v, c? } — c optional
               (a hex bar colour); palette used if omitted.
   - people  : most active, pre-sorted desc (max ~5). { n, c }. Use n:"me" for
               the reader — it gets a "you" badge.
   - footer  : footer line.

   PRIVACY: never put a phone number in here. Use display names only.
   ========================================================================== */
const DATA = {
  group: "test group",
  week: "Mon 8 – Sun 14 Jun 2026",
  stats: { messages: 1284, people: 12, busiestDay: "Wed", needYou: 4 },
  needsYou: [
    { type:"do",  tx:"Confirm the field booking by <b>Thursday</b>.", who:"Maya R." },
    { type:"do",  tx:"Review the open <b>PR</b> when you get a chance.", who:"Tom" },
    { type:"at",  tx:"@me are you in for Friday's match?", who:"Dan K." },
    { type:"ask", tx:"Who's collecting the <b>2 missing payments</b>?", who:"Avi B." }
  ],
  decided: [
    { tx:"Match moved to <b>Friday 19:00</b> — field is booked.", mt:"Decided Thu · Match logistics" },
    { tx:"Trip dates locked: <b>26–28 Jun</b>.", mt:"Decided Wed · Trips" },
    { tx:"Costs split via Bit, <b>₪40 / person</b>.", mt:"Decided Tue · Payments" },
    { tx:"Daily standup moved to <b>10:00</b>.", mt:"Decided Mon · Work / project" }
  ],
  restline: [
    { type:"ask", x:"18 questions answered in-thread" },
    { type:"at",  x:"no other open mentions" }
  ],
  topics: [
    { n:"Match logistics", v:142 },
    { n:"Payments",        v:96  },
    { n:"Trips",           v:73  },
    { n:"Work / project",  v:64  },
    { n:"Scheduling",      v:41  },
    { n:"Banter",          v:38  }
  ],
  people: [
    { n:"Maya R.", c:142 },
    { n:"me",      c:118 },
    { n:"Dan K.",  c:97  },
    { n:"Noa",     c:86  },
    { n:"Avi B.",  c:71  }
  ],
  footer: "A weekly read, not a dashboard"
};

/* ---- render (do not edit) ------------------------------------------------ */
const $=s=>document.querySelector(s);
function ic(p){return `<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${p}</svg>`;}
const I={
  ok:'<circle cx="12" cy="12" r="9.5"/><path d="M8 12.5l2.5 2.5 5.5-5.5"/>',
  do:'<rect x="5" y="6" width="14" height="15" rx="2"/><path d="M9 4h6a1 1 0 0 1 1 1v1H8V5a1 1 0 0 1 1-1z"/><path d="M9 12l2 2 4-4"/>',
  ask:'<circle cx="12" cy="12" r="9.5"/><path d="M9.2 9.3a2.8 2.8 0 0 1 5.5.8c0 1.9-2.8 2.5-2.8 2.5"/><path d="M12 17h.01"/>',
  at:'<circle cx="12" cy="12" r="4"/><path d="M16 12v1.5a2.5 2.5 0 0 0 5 0V12a9 9 0 1 0-3.5 7.1"/>'
};
const PAL=["#ff3b2f","#13a05c","#e98a00","#7c3aed","#2563eb","#c81f15","#0d0d10","#74747f"];
const esc=s=>String(s).replace(/[&<>"]/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c]));
const fmt=n=>Number(n).toLocaleString();

// deterministic colored initials avatar (self-contained, no network image)
function initials(name){
  const p=String(name).trim().split(/\s+/).filter(Boolean);
  let s=(p[0]||"?")[0];
  if(p.length>1) s+=p[p.length-1][0];
  return s.toUpperCase();
}
function avColor(name){
  let h=0; const s=String(name); for(let i=0;i<s.length;i++) h=(h*31+s.charCodeAt(i))>>>0;
  return `hsl(${h%360} 62% 44%)`;
}
function avatar(name,cls){
  return `<span class="${cls} avi" style="background:${avColor(name)}" aria-label="${esc(name)}">${esc(initials(name))}</span>`;
}

$("#group").textContent=DATA.group;
$("#week").textContent=`Weekly digest · ${DATA.week}`;

// lede
const topTopic=(DATA.topics[0]||{}).n||"—";
$("#lede").innerHTML=`<em>${fmt(DATA.stats.messages)} messages</em> this week — mostly <em>${esc(topTopic)}</em>, busiest on <em>${esc(DATA.stats.busiestDay)}</em>.`;

// stat tiles
$("#stats").innerHTML=[
  [fmt(DATA.stats.messages),"messages",false],
  [fmt(DATA.stats.people),"people active",false],
  [esc(DATA.stats.busiestDay),"busiest day",false],
  [fmt(DATA.stats.needYou),"need you",true]
].map(([v,k,hl])=>`<div class="tile stat${hl?' hl':''}"><div class="v num">${v}</div><div class="k">${k}</div></div>`).join("");

// while you were away
const C={do:'var(--c-todo)',ask:'var(--c-ask)',at:'var(--c-at)',ok:'var(--c-decided)'};
const LAB={do:'To do',ask:'Open question',at:'You were mentioned',ok:'Decided'};
const renderItem=f=>{
  const icp=f.type==='ok'?I.ok:f.type==='do'?I.do:f.type==='at'?I.at:I.ask;
  // person items lead with an initials avatar; group decisions lead with a category icon
  const lead=f.who
    ? avatar(f.who,'av')
    : `<span class="ico" style="--c:${C[f.type]}">${ic(icp)}</span>`;
  return `<li>
    ${lead}
    <div class="body">
      <div class="lab" style="--c:${C[f.type]}">${LAB[f.type]}</div>
      <div class="tx">${f.tx}</div>
      ${f.mt?`<div class="mt">${esc(f.mt)}</div>`:''}
    </div></li>`;
};
const needFeed=DATA.needsYou.map(n=>({type:n.type,tx:n.tx,mt:n.who?`From ${n.who}`:'',who:n.who}));
const doneFeed=DATA.decided.map(d=>({type:'ok',tx:d.tx,mt:d.mt}));
$("#feed-need").innerHTML=needFeed.map(renderItem).join("");
$("#feed-done").innerHTML=doneFeed.map(renderItem).join("");
$("#need-n").textContent=DATA.needsYou.length;
$("#done-n").textContent=DATA.decided.length;
$("#away-sub").textContent=`${DATA.decided.length} decided · ${DATA.needsYou.length} for you`;
$("#restline").innerHTML=`<span>Also quietly handled:</span>`+DATA.restline
  .map(r=>`<span class="pill" style="--c:${C[r.type]||'var(--muted)'}"><span class="d"></span>${esc(r.x)}</span>`).join("");

// topics
const tdata=DATA.topics.slice(0,6);
const tMax=Math.max(1,...tdata.map(t=>t.v));
$("#topics-sub").textContent=`top ${tdata.length}`;
$("#topics").innerHTML=tdata.map((t,i)=>`<div class="bar">
  <span class="bn">${esc(t.n)}</span><span class="bc num">${fmt(t.v)}</span>
  <span class="tr"><i style="width:${t.v/tMax*100}%;background:${t.c||PAL[i%PAL.length]}"></i></span></div>`).join("");

// people
const pdata=DATA.people.slice(0,5);
const pMax=Math.max(1,...pdata.map(p=>p.c));
$("#people-sub").textContent=`top ${pdata.length} of ${fmt(DATA.stats.people)}`;
$("#people").innerHTML=pdata.map((p,i)=>`<div class="prow">
  <span class="rank num">${i+1}</span>
  ${avatar(p.n,'av')}
  <div class="pm">
    <span class="pn">${esc(p.n)}${p.n==='me'?'<span class="me">you</span>':''}</span>
    <span class="tr"><i style="width:${p.c/pMax*100}%"></i></span>
  </div>
  <span class="pc num">${fmt(p.c)}</span>
</div>`).join("");

$("#foot").textContent=DATA.footer;
</script>
</body></html>
