// ── ACTIVITIES PAGE ─────────────────────────────────────────
// Includes needs-tag filtering, age + duration filters, and a
// WiseTip+ "tailor my feed" mode where the member's selected tags
// surface a personalised activity stream.

// Shared family profile (persisted in localStorage). Profile page can
// toggle "Special Needs" — when on, sensitive tags become available
// inside the user's saved tags but never appear in the public chip strip.
const PROFILE_KEY = "wisetip_profile_v1";
const PROFILE_DEFAULTS = { specialNeeds: false, tags: ["adhd","calm","sibling"] };
function readProfile() {
  try {
    const raw = localStorage.getItem(PROFILE_KEY);
    if (!raw) return { ...PROFILE_DEFAULTS };
    return { ...PROFILE_DEFAULTS, ...JSON.parse(raw) };
  } catch (e) { return { ...PROFILE_DEFAULTS }; }
}
function writeProfile(p) {
  try { localStorage.setItem(PROFILE_KEY, JSON.stringify(p)); } catch (e) {}
  window.dispatchEvent(new CustomEvent("wisetip-profile", { detail: p }));
}
function useProfile() {
  const [p, setP] = useState(readProfile);
  useEffect(() => {
    const on = (e) => setP(e.detail);
    window.addEventListener("wisetip-profile", on);
    return () => window.removeEventListener("wisetip-profile", on);
  }, []);
  return [p, (next) => { writeProfile(next); setP(next); }];
}
window.useProfile = useProfile;
window.WS_PROFILE_DEFAULTS = PROFILE_DEFAULTS;

function Activities({ theme, dark, lang, isMember, setIsMember, nav }) {
  const [profile, setProfile] = useProfile();
  const myTags = profile.tags;
  const [tailorOn, setTailorOn] = useState(isMember);
  const [activeNeed, setActiveNeed] = useState("all");
  const [activeSeason, setActiveSeason] = useState("all");
  const [seasonGroup, setSeasonGroup] = useState("all");
  const [ageBand, setAgeBand] = useState("all");
  const [maxDur, setMaxDur] = useState(120);

  // Catalog data — fetched from JSON feed; falls back to hardcoded globals
  const [activities, setActivities] = useState(WS_ACTIVITIES || []);
  const [seasonTags, setSeasonTags] = useState(WS_SEASON_TAGS || []);
  const [needsTags, setNeedsTags] = useState(WS_NEEDS_TAGS || []);
  const [catalogLoaded, setCatalogLoaded] = useState(false);

  useEffect(() => {
    let alive = true;
    Promise.all([
      fetch("/data/activities/catalog.json").then(r => r.json()),
      fetch("/data/activities/tags.json").then(r => r.json()),
    ]).then(([cat, tags]) => {
      if (!alive) return;
      if (cat.activities && cat.activities.length > 0) setActivities(cat.activities);
      if (tags.season_tags && tags.season_tags.length > 0) setSeasonTags(tags.season_tags);
      if (tags.needs_tags  && tags.needs_tags.length  > 0) setNeedsTags(tags.needs_tags);
      setCatalogLoaded(true);
    }).catch(() => setCatalogLoaded(true)); // silently fall back to globals
    return () => { alive = false; };
  }, []);

  useEffect(() => { if (!isMember) setTailorOn(false); }, [isMember]);

  const coveredSeasons = new Set(activities.flatMap(a => a.seasons || []));
  const coveredNeeds   = new Set(activities.flatMap(a => a.needs   || []));
  const PUBLIC_NEEDS   = needsTags.filter(t => !t.sensitive && coveredNeeds.has(t.id));
  const PUBLIC_SEASONS = seasonTags.filter(t => !t.hidden && coveredSeasons.has(t.id));

  const visibleNeeds = (profile.specialNeeds && isMember)
    ? [...PUBLIC_NEEDS, ...needsTags.filter(t => t.sensitive && profile.tags.includes(t.id))]
    : PUBLIC_NEEDS;

  const matches = (a) => {
    if (activeNeed !== "all" && !a.needs.includes(activeNeed)) return false;
    if (activeSeason !== "all" && !(a.seasons || []).includes(activeSeason)) return false;
    if (ageBand !== "all") {
      const [lo, hi] = ageBand.split("-").map(Number);
      if (a.ages[1] < lo || a.ages[0] > hi) return false;
    }
    if (a.duration > maxDur) return false;
    return true;
  };
  const score = (a) => tailorOn ? a.needs.filter(n => myTags.includes(n)).length : 0;
  const curSeason = window.WS_CUR_SEASON || 'autumn';
  const seasonBoost = (a) => (a.seasons || []).includes(curSeason) ? 1 : 0;
  const list = activities.filter(matches).sort((a, b) => {
    var sd = score(b) - score(a);
    if (sd !== 0) return sd;
    return seasonBoost(b) - seasonBoost(a);
  });

  return (
    <div style={{ background: theme.bg, color: theme.text, paddingTop: "5rem" }}>
      {/* HEADER */}
      <div style={{
        background: dark
          ? `radial-gradient(ellipse 60% 50% at 20% 100%, #1A4A20 0%, transparent 55%), linear-gradient(180deg, #0A1A10 0%, ${theme.bg} 100%)`
          : `radial-gradient(ellipse 60% 50% at 20% 100%, #C8DAB8 0%, transparent 55%), linear-gradient(180deg, ${theme.bg2} 0%, ${theme.bg} 100%)`,
        padding: "5rem clamp(1.5rem, 5vw, 5vw) 3rem", position: "relative", overflow:"hidden",
      }}>
        <div className="wrap" style={{ position:"relative" }}>
          <Eyebrow theme={theme}>{lang==="en"?`Activities · ${activities.length} in archive`:`Actividades · ${activities.length} en archivo`}</Eyebrow>
          <h1 className="serif" style={{
            fontStyle:"italic", fontWeight:300, fontSize:"clamp(2.4rem, 5.5vw, 4.6rem)",
            color: theme.text, lineHeight: 1.02, letterSpacing:"-.02em",
            marginTop: ".75rem", marginBottom:"1rem", maxWidth: 900,
          }}>{lang==="en"
            ? <>Screen-free. Built for the family <em>you actually have.</em></>
            : <>Sin pantallas. Hecho para la familia <em>que realmente tienes.</em></>}</h1>
          <p style={{ color: theme.text2, fontSize:"1.05rem", lineHeight: 1.7, fontWeight: 300, maxWidth: 640 }}>
            {lang==="en"
              ? "Two parallel ways to filter: by the time of year (a season, a holiday, a moment) and/or by what your family needs (accessibility, sensory load, sibling dynamics). Combine them freely."
              : "Dos formas de filtrar en paralelo: por momento del año (estación, fiesta, instante) y/o por lo que tu familia necesita (accesibilidad, carga sensorial, hermanos). Combínalas a tu ritmo."}
          </p>
          <div style={{ display:"flex", gap:"1rem", marginTop:"1.5rem", flexWrap:"wrap" }}>
            <DiffBadge n={"01"} label={lang==="en"?"By season & moment":"Por estación y momento"} theme={theme}/>
            <DiffBadge n={"02"} label={lang==="en"?"By accessibility & needs":"Por accesibilidad y necesidad"} theme={theme}/>
          </div>
        </div>
      </div>

      {/* TAILOR FEED BAR (WiseTip+ feature) */}
      <div style={{
        background: tailorOn ? theme.sage4 : theme.sage3,
        borderTop: `1px solid ${theme.border}`, borderBottom: `1px solid ${theme.border}`,
        padding: "1.25rem clamp(1.5rem, 5vw, 5vw)", transition:"background .3s",
      }}>
        <div className="wrap" style={{ display:"flex", gap:"1.5rem", alignItems:"center", justifyContent:"space-between", flexWrap:"wrap" }}>
          <div style={{ display:"flex", alignItems:"center", gap:14, flex: 1, minWidth: 280 }}>
            <div style={{
              width: 38, height: 38, borderRadius:"50%",
              background: tailorOn ? theme.sage : theme.sage3,
              color: tailorOn ? (dark?"#050F07":"#fff") : theme.sage,
              display:"flex", alignItems:"center", justifyContent:"center",
              fontFamily:"'Cormorant Garamond',serif", fontSize:"1.15rem",
              border: `1px solid ${theme.border2}`,
            }}>✦</div>
            <div>
              <div className="label-tiny" style={{ color: theme.gold, marginBottom: 3 }}>
                {lang==="en"?"WiseTip+ · Tailor my feed":"WiseTip+ · Personaliza mi feed"}
              </div>
              <div style={{ fontSize:".88rem", color: theme.text, fontWeight: 500 }}>
                {isMember
                  ? (tailorOn
                      ? (lang==="en"?`Showing activities that match ${myTags.length} of your family's tags first.`:`Mostrando primero las actividades que coinciden con ${myTags.length} de tus etiquetas.`)
                      : (lang==="en"?"Tailored ordering is paused.":"Orden personalizado en pausa."))
                  : (lang==="en"?"Become a member to surface activities for your family's specific needs.":"Hazte miembro para resaltar actividades para las necesidades específicas de tu familia.")}
              </div>
            </div>
          </div>
          {isMember ? (
            <div style={{ display:"flex", gap: 8, alignItems:"center" }}>
              <button onClick={() => setTailorOn(!tailorOn)} style={{
                background: tailorOn ? theme.sage : "transparent",
                color: tailorOn ? (dark?"#050F07":"#fff") : theme.text2,
                border: `1px solid ${tailorOn ? theme.sage : theme.border2}`,
                padding:"8px 16px", borderRadius: 22,
                fontSize:".78rem", fontWeight: 500, cursor:"pointer",
              }}>{tailorOn ? (lang==="en"?"Tailored · on":"Personalizado · activo") : (lang==="en"?"Turn on":"Activar")}</button>
            </div>
          ) : (
            <button onClick={() => setIsMember(true)} style={{
              background: theme.sage, color: dark?"#050F07":"#fff",
              border:"none", padding:"8px 16px", borderRadius: 22,
              fontSize:".78rem", fontWeight: 600, cursor:"pointer",
            }}>{lang==="en"?"Preview as member":"Ver como miembro"} →</button>
          )}
        </div>
      </div>

      {/* ── DIFFERENTIATION 01 · SEASON & MOMENT ── */}
      <div className="section" style={{ padding:"2.5rem clamp(1.5rem, 5vw, 5vw) .5rem" }}>
        <div className="wrap">
          <div style={{ display:"flex", justifyContent:"space-between", alignItems:"baseline", marginBottom:".75rem", flexWrap:"wrap", gap: 8 }}>
            <div style={{ display:"flex", alignItems:"baseline", gap: 12 }}>
              <span className="mono" style={{ fontSize:".66rem", color: theme.sage, letterSpacing:".18em" }}>01 ·</span>
              <Eyebrow theme={theme}>{lang==="en"?"By season & moment":"Por estación y momento"}</Eyebrow>
            </div>
            <div style={{ display:"flex", gap: 4 }}>
              {[["all",lang==="en"?"All":"Todo"],["season",lang==="en"?"Seasons":"Estaciones"],["holiday",lang==="en"?"Holidays":"Fiestas"],["moment",lang==="en"?"Moments":"Momentos"]].map(([g,l])=>(
                <button key={g} onClick={()=>setSeasonGroup(g)} style={{
                  padding:"4px 10px", borderRadius: 12,
                  background: seasonGroup === g ? theme.sage3 : "transparent",
                  border:`1px solid ${seasonGroup === g ? theme.border2 : "transparent"}`,
                  color: seasonGroup === g ? theme.text : theme.text3,
                  fontSize:".7rem", cursor:"pointer",
                }}>{l}</button>
              ))}
            </div>
          </div>
          <div style={{ display:"flex", flexWrap:"wrap", gap: 6 }}>
            <SeasonChip active={activeSeason === "all"} onClick={() => setActiveSeason("all")} theme={theme}
              glyph="◯" label={lang==="en"?"Any time":"Cualquier momento"} hue={theme.sage}/>
            {PUBLIC_SEASONS.filter(t => t.id !== "any" && (seasonGroup === "all" || t.group === seasonGroup)).map(t => (
              <SeasonChip key={t.id} theme={theme}
                active={activeSeason === t.id}
                glyph={t.glyph} label={t.label[lang]} hue={t.hue}
                onClick={() => setActiveSeason(activeSeason === t.id ? "all" : t.id)}
              />
            ))}
          </div>
        </div>
      </div>

      {/* ── DIFFERENTIATION 02 · ACCESSIBILITY & NEEDS ── */}
      <div className="section" style={{ padding:"1.75rem clamp(1.5rem, 5vw, 5vw) 1rem" }}>
        <div className="wrap">
          <div style={{ display:"flex", justifyContent:"space-between", alignItems:"baseline", marginBottom:".75rem", flexWrap:"wrap", gap: 8 }}>
            <div style={{ display:"flex", alignItems:"baseline", gap: 12 }}>
              <span className="mono" style={{ fontSize:".66rem", color: theme.sage, letterSpacing:".18em" }}>02 ·</span>
              <Eyebrow theme={theme}>{lang==="en"?"By accessibility & needs":"Por accesibilidad y necesidad"}</Eyebrow>
            </div>
            {isMember && (
              <span style={{ fontSize:".74rem", color: theme.text3 }}>
                {lang==="en"?"Click + to save a tag to your family profile":"Toca + para guardar la etiqueta en tu perfil"}
              </span>
            )}
          </div>
          <div style={{ display:"flex", flexWrap:"wrap", gap: 8 }}>
            <NeedsChip active={activeNeed === "all"} onClick={() => setActiveNeed("all")} theme={theme}
              glyph="◯" label={lang==="en"?"Any need":"Cualquier necesidad"} hue={theme.sage}/>
            {visibleNeeds.map(t => {
              const saved = myTags.includes(t.id);
              return (
                <NeedsChip key={t.id} theme={theme}
                  active={activeNeed === t.id}
                  saved={isMember && saved && tailorOn}
                  glyph={t.glyph} label={t.label[lang]} hue={t.hue}
                  onClick={() => setActiveNeed(activeNeed === t.id ? "all" : t.id)}
                  onSave={isMember && !t.sensitive ? () => {
                    const nextTags = saved ? myTags.filter(x => x !== t.id) : [...myTags, t.id];
                    setProfile({ ...profile, tags: nextTags });
                  } : null}
                />
              );
            })}
          </div>
          {/* Combined-filter readout */}
          {(activeSeason !== "all" || activeNeed !== "all") && (
            <div style={{
              marginTop:"1.25rem", padding:"10px 14px",
              background: theme.sage3, border:`1px dashed ${theme.border2}`, borderRadius: 6,
              fontSize:".78rem", color: theme.text2, display:"flex", gap: 8, alignItems:"center", flexWrap:"wrap",
            }}>
              <span className="label-tiny" style={{ color: theme.sage }}>{lang==="en"?"Filtering by":"Filtrando por"}</span>
              {activeSeason !== "all" && (() => { const t = seasonTags.find(x=>x.id===activeSeason); return t ? <span style={{ color: t.hue }}>{t.glyph} {t.label[lang]}</span> : null; })()}
              {activeSeason !== "all" && activeNeed !== "all" && <span style={{ color: theme.text3 }}>{lang==="en"?"AND":"Y"}</span>}
              {activeNeed !== "all" && (() => { const t = needsTags.find(x=>x.id===activeNeed); return t ? <span style={{ color: t.hue }}>{t.glyph} {t.label[lang]}</span> : null; })()}
              <button onClick={() => { setActiveSeason("all"); setActiveNeed("all"); }} style={{
                marginLeft:"auto", background:"transparent", border:"none", color: theme.text3,
                fontSize:".74rem", cursor:"pointer", textDecoration:"underline",
              }}>{lang==="en"?"Clear":"Limpiar"}</button>
            </div>
          )}

        </div>
      </div>

      {/* AGE + DURATION */}
      <div style={{ padding:"0 clamp(1.5rem, 5vw, 5vw) 2.5rem" }}>
        <div className="wrap" style={{ display:"flex", gap:"2rem", flexWrap:"wrap", alignItems:"center" }}>
          <FilterGroup label={lang==="en"?"Age":"Edad"} theme={theme}>
            {[["all","Any"],["3-5","3–5"],["6-9","6–9"],["10-13","10–13"],["14-17","14–17"]].map(([v,l]) => (
              <FilterBtn key={v} active={ageBand === v} onClick={() => setAgeBand(v)} theme={theme} dark={dark}>{l}</FilterBtn>
            ))}
          </FilterGroup>
          <FilterGroup label={lang==="en"?"Duration · up to":"Duración · hasta"} theme={theme}>
            <div style={{ display:"flex", alignItems:"center", gap: 12 }}>
              <input type="range" min={15} max={120} step={15} value={maxDur}
                onChange={e => setMaxDur(+e.target.value)}
                style={{ width: 160, accentColor: theme.sage }}/>
              <span className="mono" style={{ fontSize:".82rem", color: theme.text2 }}>{maxDur} min</span>
            </div>
          </FilterGroup>
          <div style={{ marginLeft:"auto", fontSize:".82rem", color: theme.text2 }}>
            {list.length} {lang==="en"?"activities":"actividades"}
          </div>
        </div>
      </div>

      {/* ACTIVITY GRID */}
      <div style={{ padding:"0 clamp(1.5rem, 5vw, 5vw) 5rem" }}>
        <div className="wrap">
          <div className="grid-3" style={{ gap: "1rem" }}>
            {list.map(a => (
              <ActivityCard key={a.id} a={a} theme={theme} dark={dark} lang={lang} nav={nav} myTags={myTags} tailorOn={tailorOn && isMember} isMember={isMember} showSensitive={profile.specialNeeds && isMember} seasonTags={seasonTags} needsTags={needsTags}/>
            ))}
            {list.length === 0 && (
              <div style={{ gridColumn:"1/-1", padding:"3rem 1.5rem", textAlign:"center", color: theme.text3 }}>
                <div className="serif italic" style={{ fontSize:"1.5rem", marginBottom: ".5rem" }}>
                  {lang==="en"?"Nothing matches all those filters.":"Nada coincide con todos los filtros."}
                </div>
                <div style={{ fontSize:".88rem" }}>{lang==="en"?"Try loosening one.":"Prueba a aflojar alguno."}</div>
              </div>
            )}
          </div>
        </div>
      </div>

      {/* PACKS CTA */}
      <div style={{
        background: dark ? theme.bg2 : theme.bg2, padding:"4rem clamp(1.5rem, 5vw, 5vw)",
      }}>
        <div className="wrap" style={{
          display:"grid", gridTemplateColumns:"1.4fr 1fr", gap:"3rem", alignItems:"center",
        }} className="grid-2">
          <div>
            <Eyebrow theme={theme}>{lang==="en"?"Want them all printed?":"¿Las quieres impresas?"}</Eyebrow>
            <h3 className="serif" style={{
              fontStyle:"italic", fontWeight: 300, fontSize:"clamp(1.6rem, 3.5vw, 2.4rem)",
              color: theme.text, marginTop:".5rem", marginBottom:".75rem", lineHeight: 1.1,
            }}>{lang==="en"
              ? <>Activity packs · <em>themed PDFs you can print.</em></>
              : <>Packs de actividades · <em>PDFs temáticos para imprimir.</em></>}</h3>
            <p style={{ color: theme.text2, fontSize:".95rem", lineHeight: 1.7, fontWeight: 300, maxWidth: 480 }}>
              {lang==="en"
                ? "Winter, Summer, Calm, Movement, Rainy day. Twelve+ activities per pack, sized for a fridge and tested by the editors' households."
                : "Invierno, Verano, Calma, Movimiento, Día de lluvia. 12+ actividades por pack, del tamaño de una nevera y probados por las familias de los editores."}
            </p>
          </div>
          <button onClick={() => nav("packs")} style={{
            justifySelf:"flex-end", background: theme.sage, color: dark ? "#050F07" : "#fff",
            border:"none", padding:"14px 26px", borderRadius: 30,
            fontSize:".88rem", fontWeight: 600, cursor:"pointer",
          }}>{lang==="en"?"Browse packs":"Ver packs"} →</button>
        </div>
      </div>
    </div>
  );
}

// ── helpers ─────────────────────────────────────────────────
function NeedsChip({ active, saved, glyph, label, hue, onClick, onSave, theme }) {
  return (
    <span style={{ display:"inline-flex", position:"relative" }}>
      <button onClick={onClick} style={{
        display:"inline-flex", alignItems:"center", gap: 8,
        padding:"7px 14px", paddingRight: onSave ? 32 : 14,
        borderRadius: 20,
        background: active ? hue : (saved ? `${hue}24` : theme.sage3),
        border: `1px solid ${active ? hue : (saved ? hue : theme.border2)}`,
        color: active ? "#050F07" : (saved ? hue : theme.text2),
        fontSize:".76rem", fontWeight: active || saved ? 500 : 400,
        cursor:"pointer", letterSpacing:".02em",
      }}>
        <span style={{ fontSize:".88rem", lineHeight: 1, fontFamily: "'Cormorant Garamond', serif" }}>{glyph}</span>
        {label}
      </button>
      {onSave && (
        <button onClick={onSave} title="Save to my profile" style={{
          position:"absolute", right: 4, top:"50%", transform:"translateY(-50%)",
          width: 22, height: 22, borderRadius:"50%",
          background: saved ? hue : "transparent",
          border: `1px solid ${saved ? hue : theme.border2}`,
          color: saved ? "#050F07" : theme.text3,
          display:"flex", alignItems:"center", justifyContent:"center",
          fontSize:".7rem", cursor:"pointer",
        }}>{saved ? "✓" : "+"}</button>
      )}
    </span>
  );
}

function FilterGroup({ label, theme, children }) {
  return (
    <div style={{ display:"flex", alignItems:"center", gap: 14 }}>
      <span className="label-tiny" style={{ color: theme.text3 }}>{label}</span>
      <div style={{ display:"flex", gap: 6, flexWrap:"wrap" }}>{children}</div>
    </div>
  );
}
function FilterBtn({ active, onClick, theme, dark, children }) {
  return (
    <button onClick={onClick} style={{
      padding:"6px 12px", borderRadius: 18,
      background: active ? theme.sage : theme.sage3,
      color: active ? (dark?"#050F07":"#fff") : theme.text2,
      border: `1px solid ${active ? theme.sage : theme.border2}`,
      fontSize:".76rem", fontWeight: active ? 500 : 400, cursor:"pointer",
    }}>{children}</button>
  );
}

function ActivityCard({ a, theme, dark, lang, nav, myTags, tailorOn, isMember, showSensitive, seasonTags, needsTags }) {
  const _seasonTags = seasonTags || WS_SEASON_TAGS || [];
  const _needsTags  = needsTags  || WS_NEEDS_TAGS  || [];
  const matched = a.needs.filter(n => myTags.includes(n));
  const isLocked = a.tier === "premium" && !isMember;
  return (
    <article onClick={() => nav && nav("activitydetail", { id: a.id })} style={{
      background: dark ? theme.panel : "#fff",
      border: `1px solid ${tailorOn && matched.length > 0 ? theme.sage : theme.border}`,
      borderRadius: 6, padding:"1.4rem 1.3rem",
      display:"flex", flexDirection:"column", gap:".85rem",
      position:"relative", overflow:"hidden", cursor:"pointer",
    }}>
      {tailorOn && matched.length > 0 && (
        <div style={{
          position:"absolute", top: 10, right: 10,
          background: theme.sage, color: dark?"#050F07":"#fff",
          fontSize:".58rem", letterSpacing:".16em", textTransform:"uppercase",
          padding:"3px 8px", borderRadius: 10, fontWeight: 700,
        }}>✦ matches {matched.length}</div>
      )}

      <div style={{ display:"flex", justifyContent:"space-between", alignItems:"baseline" }}>
        <span className="mono" style={{ fontSize:".68rem", color: theme.text3 }}>
          A.{String(a.id).padStart(3,"0")} · ed.{a.edition}
        </span>
        <span style={{ fontSize:".7rem", color: theme.text2 }}>
          {a.ages[0]}–{a.ages[1]}y · {a.duration} min
        </span>
      </div>

      <h3 className="serif" style={{
        fontStyle:"italic", fontWeight: 400, fontSize:"1.4rem",
        color: theme.text, lineHeight: 1.15,
      }}>{a.title[lang]}</h3>

      <p style={{ fontSize:".88rem", color: theme.text2, fontWeight: 300, lineHeight: 1.6, flex: 1 }}>
        {a.summary[lang]}
      </p>

      {/* season tags */}
      {a.seasons && a.seasons.length > 0 && (
        <div style={{ display:"flex", flexWrap:"wrap", gap: 4 }}>
          {a.seasons.filter(s => {
            if (s === "any") return false;
            const t = _seasonTags.find(x => x.id === s);
            return t && !t.hidden;
          }).slice(0, 4).map(sid => {
            const tag = _seasonTags.find(t => t.id === sid);
            if (!tag) return null;
            return (
              <span key={sid} style={{
                fontSize:".62rem", padding:"1px 7px", borderRadius: 9,
                background: `${tag.hue}18`, color: tag.hue,
                border: `1px solid ${tag.hue}40`, letterSpacing:".04em",
              }}>{tag.glyph} {tag.label[lang]}</span>
            );
          })}
        </div>
      )}

      {/* needs tags */}
      <div style={{ display:"flex", flexWrap:"wrap", gap: 4, paddingTop:".5rem", borderTop:`1px solid ${theme.divider}` }}>
        {a.needs
          .filter(nid => {
            const t = _needsTags.find(x => x.id === nid);
            return t && (!t.sensitive || showSensitive);
          })
          .slice(0, 5).map(nid => {
          const tag = _needsTags.find(t => t.id === nid);
          if (!tag) return null;
          const isMatch = tailorOn && myTags.includes(nid);
          return (
            <span key={nid} style={{
              fontSize:".64rem", padding:"2px 8px", borderRadius: 10,
              background: isMatch ? `${tag.hue}24` : theme.sage3,
              color: isMatch ? tag.hue : theme.text3,
              border: isMatch ? `1px solid ${tag.hue}` : `1px solid transparent`,
              letterSpacing:".06em",
            }}>{tag.glyph} {tag.label[lang]}</span>
          );
        })}
      </div>

      <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", marginTop:".25rem" }}>
        <Pill color={a.tier === "premium" ? theme.gold : theme.sage}
              bd={`${a.tier === "premium" ? theme.gold : theme.sage}55`}>
          {a.tier === "premium" ? "WiseTip+" : "Free"}
        </Pill>
        <button style={{
          fontSize:".78rem", color: isLocked ? theme.gold : theme.sage,
          background:"transparent", border:"none", cursor:"pointer", fontWeight: 500,
        }}>
          {isLocked ? (lang==="en"?"Unlock →":"Desbloquear →") : (lang==="en"?"Open →":"Abrir →")}
        </button>
      </div>
    </article>
  );
}

function SeasonChip({ active, glyph, label, hue, onClick, theme }) {
  return (
    <button onClick={onClick} style={{
      display:"inline-flex", alignItems:"center", gap: 7,
      padding:"6px 12px", borderRadius: 16,
      background: active ? hue : theme.sage3,
      border: `1px solid ${active ? hue : theme.border2}`,
      color: active ? "#050F07" : theme.text2,
      fontSize:".74rem", fontWeight: active ? 500 : 400,
      cursor:"pointer", letterSpacing:".02em",
    }}>
      <span style={{ fontSize:".86rem", lineHeight: 1, fontFamily:"'Cormorant Garamond', serif" }}>{glyph}</span>
      {label}
    </button>
  );
}

function DiffBadge({ n, label, theme }) {
  return (
    <div style={{
      display:"inline-flex", alignItems:"baseline", gap: 8,
      padding:"4px 12px 4px 4px", borderRadius: 18,
      background: theme.sage3, border:`1px solid ${theme.border2}`,
    }}>
      <span style={{
        background: theme.sage, color:"#050F07",
        fontFamily:"'JetBrains Mono', monospace", fontSize:".66rem",
        padding:"3px 8px", borderRadius: 14, fontWeight: 700,
      }}>{n}</span>
      <span style={{ fontSize:".76rem", color: theme.text2 }}>{label}</span>
    </div>
  );
}

Object.assign(window, { Activities });
