// Africa landing — composer + sections.
// Section markup is keyed to africa.css class names. Don't rename without
// updating both. Data lives in africa-data.jsx.

const slugify = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");

const AfHero = () => (
  <section className="af-hero">
    <div className="af-hero-bg" />
    <div className="af-hero-collage" aria-hidden="true">
      {AF_HERO_COLLAGE.map((f, i) => (
        <div key={i} className={`frame f${i + 1}`} style={{ backgroundImage: `url('${f.src}')` }} data-cap={f.cap} />
      ))}
    </div>
    <div className="af-hero-grid">
      <div>
        <div className="af-hero-trail">
          <a href="/" className="crumb">HowTo: Travel</a>
          <span className="sep">/</span>
          <span>Regions</span>
          <span className="sep">/</span>
          <span>Africa</span>
        </div>
        <h1>A field guide to <em>Africa.</em></h1>
        <p className="lede"><strong>548 guides. 54 countries. 1,400 contributors who actually went.</strong> An editorial atlas to the slow side, the bush side, the medina side, and the side most travel writing still gets wrong. Region by region, season by season — the way Africa actually works.</p>
      </div>
      <aside className="af-hero-side">
        <div className="af-hero-stats">
          {AF_HERO_STATS.map((s, i) => (
            <div key={i} className="af-hero-stat">
              <div className="n">{s.n}</div>
              <div className="l">{s.label}</div>
            </div>
          ))}
        </div>
        <div className="af-hero-meta">
          {AF_HERO_META.map((m, i) => (
            <div key={i} className="row"><span>{m.k}</span><b>{m.v}</b></div>
          ))}
        </div>
      </aside>
    </div>
    <div className="af-hero-foot">
      <p className="af-hero-quote">"Africa is fifty-four countries, two thousand languages, and one of the worst-served continents in travel writing. The point of this issue is to fix that."<span className="by">— Amani Okafor, Editor at Large</span></p>
      <form className="af-hero-search" onSubmit={(e) => e.preventDefault()}>
        <Icon name="search" size={16} />
        <input placeholder="Search 548 Africa guides — 'Tanzania safari', 'Marrakech riad'..." />
        <button>Search</button>
      </form>
    </div>
  </section>
);

const AfPills = () => (
  <nav className="af-pills" aria-label="Regions">
    <div className="af-pills-inner">
      <span className="lbl">Regions</span>
      {AF_REGIONS.map((r) => (
        <a key={r.id} href={r.href} className={r.current ? "current" : ""}>{r.name}</a>
      ))}
    </div>
  </nav>
);

const AfAnchor = () => (
  <nav className="af-anchor" aria-label="On this page">
    <div className="af-anchor-inner">
      <span className="lbl">In this issue</span>
      {AF_ANCHOR.map((a) => <a key={a.href} href={a.href}>{a.label}</a>)}
    </div>
  </nav>
);

const AfIntro = () => (
  <section className="af-sec af-intro" id="intro">
    <div className="container af-intro-grid">
      <div className="from">
        <div className="lbl">From the Plan Desk</div>
        <div className="name">Amani Okafor</div>
        <div className="role">Senior Editor · Africa</div>
        <div className="stamp">Issue<em>Nº 15</em>Spring '26</div>
      </div>
      <div className="body">
        <p><strong>Africa is large.</strong> Which is the secret almost every guidebook gets wrong. Fifty-four countries, two thousand languages, and a landmass that swallows the United States, China, India and most of Europe with room to spare. The temptation is to treat that scale like a sampler — three countries in two weeks, a continent in three. Don't.</p>
        <p>The Africa worth writing about is the patient one. The medina you walk for two days before you even try to find your way out. The fly-camp you stay long enough at to know the elephants by ear. <strong>One country at a time</strong>, or one circuit at a time. The continent does not reward sprinting.</p>
        <p>This page is the manual we wished existed when we started. Everything we'd send a friend before their first African trip — and a few things only useful on the fifth.</p>
        <div className="sig">— Amani</div>
      </div>
      <aside className="toc">
        <div className="lbl">Table of contents</div>
        <ol>
          {AF_TOC.map((t, i) => (
            <li key={i}>
              <a href={`#${["intro","countries","regions","when","itineraries","food","trains","budget","language","festivals","neighborhoods","packing"][i] || ""}`}>{t.t}</a>
              <span className="pg">{t.pg}</span>
            </li>
          ))}
        </ol>
      </aside>
    </div>
  </section>
);

const AfCountries = () => (
  <section className="af-sec af-countries" id="countries">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 01</div>
          <h2>12 countries, the <em>honest atlas.</em></h2>
          <p>The continent's most-travelled twelve, sorted by guide depth not GDP or alphabet. Featured below: the country we have written about for the longest. Click any tile for the full sub-atlas.</p>
        </div>
        <div className="right"><a className="view-all" href="/en/plan/itineraries/africa">View all 54 <Icon name="arrow" size={14} /></a></div>
      </header>
      <div className="af-countries-grid">
        {AF_COUNTRIES.map((c, i) => (
          <a key={i} className={`af-country${c.featured ? " featured" : ""}`} href={`/africa/${slugify(c.name)}/`}>
            <div className="country-img" style={{ backgroundImage: `url('${c.img}')` }} />
            <div className="top">
              <div className="flag" style={{ backgroundImage: `url('${c.flag}')`, backgroundSize: "cover" }} aria-hidden="true" />
              <div className="num">{String(i + 1).padStart(2, "0")}</div>
            </div>
            <div className="body">
              <div>
                <h3 className="name">{c.name}</h3>
                <div className="cap">{c.cap}</div>
                {c.featured && <p className="lede">{c.lede}</p>}
              </div>
              <div className="stats">
                <span><b>{c.guides}</b> guides</span>
                <span><b>{c.days}</b> days</span>
              </div>
            </div>
            <span className="arrow">Read →</span>
          </a>
        ))}
      </div>
    </div>
  </section>
);

const AfClusters = () => (
  <section className="af-sec af-clusters" id="regions">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 02</div>
          <h2>The continent in <em>five clusters.</em></h2>
          <p>Borders are political; weather, food, and the road conditions are not. We group Africa the way travelers actually move through it — by climate, by season, by table.</p>
        </div>
      </header>
      {AF_CLUSTERS.map((cl, i) => (
        <div key={i} className="af-cluster-row">
          <div className="lead">
            <div className="num">{cl.num} · Cluster</div>
            <h3>The <em>{cl.titleEm}</em></h3>
            <p>{cl.blurb}</p>
          </div>
          {cl.cards.map((card, j) => (
            <article key={j} className="af-cluster-card">
              <div className="top">
                <span className="when">{card.when}</span>
                <span className="pin">{card.pin}</span>
              </div>
              <h4>{card.h4}</h4>
              <p>{card.p}</p>
              <div className="tags">{card.tags.map((t) => <span key={t} className="tag">{t}</span>)}</div>
            </article>
          ))}
        </div>
      ))}
    </div>
  </section>
);

const AfWhen = () => (
  <section className="af-sec af-when" id="when">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 03</div>
          <h2>When to go — <em>dry vs wet.</em></h2>
          <p>Africa runs on rain, not temperature. The continent has two seasons in most places, and they sit at opposite ends of the calendar depending where you stand. Here is the year, region by region.</p>
        </div>
      </header>
      <div className="af-when-grid">
        <div className="af-when-cal">
          <table>
            <thead>
              <tr>
                <th>Region</th>
                {AF_WHEN_HEAD.map((m) => <th key={m}>{m}</th>)}
              </tr>
            </thead>
            <tbody>
              {AF_WHEN_ROWS.map((r) => (
                <tr key={r.region}>
                  <td className="region">{r.region}</td>
                  {r.months.map((m, k) => (
                    <td key={k}><span className={`pill ${m === "P" ? "peak" : m === "S" ? "shoulder" : m === "F" ? "fest" : "low"}`}>{m}</span></td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
          <div className="af-when-cal-legend">
            {AF_WHEN_LEGEND.map((l) => <span key={l.cls}><i className={`pill ${l.cls}`} />{l.label}</span>)}
          </div>
        </div>
        <div className="af-when-notes">
          {AF_WHEN_NOTES.map((n, i) => (
            <article key={i} className="af-when-note">
              <h4>{n.h4}</h4>
              <p>{n.p}</p>
              <div className="meta">{n.meta.map((m, k) => <span key={k}>{m}</span>)}</div>
            </article>
          ))}
        </div>
      </div>
    </div>
  </section>
);

const AfItineraries = () => (
  <section className="af-sec af-iti" id="itineraries">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 04</div>
          <h2>Four itineraries worth <em>stealing.</em></h2>
          <p>The plans we'd send to a friend, road-tested and updated each spring. Click for day-by-day.</p>
        </div>
        <div className="right"><a className="view-all" href="/en/plan/itineraries/africa">All 28 itineraries <Icon name="arrow" size={14} /></a></div>
      </header>
      <div className="af-iti-grid" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))" }}>
        {AF_ITIS.map((it, i) => (
          <a key={i} className="af-iti-card" href={`/en/plan/itineraries/africa/${slugify(it.h3)}`}>
            <div className="head">
              <div className="days">{it.days}<span>days · nights</span></div>
              <span className="pill">{it.pill}</span>
            </div>
            <h3>{it.h3.includes(",") ? <>{it.h3.split(",")[0]},<br /><em>{it.h3.split(",").slice(1).join(",").trim()}</em></> : it.h3}</h3>
            <p className="lede">{it.lede}</p>
            <ol className="stops">
              {it.stops.map((s, j) => (
                <li key={j}><span className="n">{s.n}</span><span className="place">{s.place}</span><span className="nights">{s.nights}</span></li>
              ))}
            </ol>
            <div className="foot">
              <span className="cost">{it.cost}</span>
              <span>{it.by}</span>
            </div>
          </a>
        ))}
      </div>
    </div>
  </section>
);

const AfFood = () => (
  <section className="af-sec af-food" id="food">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 05</div>
          <h2>Food &amp; drink, country <em>by country.</em></h2>
          <p>One immutable rule per kitchen. Order this, drink that, never make the obvious mistake.</p>
        </div>
      </header>
      <div className="af-food-grid">
        {AF_FOOD.map((f, i) => (
          <article key={i} className={`af-food-card ${f.span}`}>
            <div className="top">
              <span className="country">{f.country}</span>
              <span className="glyph" aria-hidden="true">{f.glyph}</span>
            </div>
            <div>
              <h4>{f.h4}</h4>
              <p>{f.p}</p>
            </div>
            <div className="pair"><b>{f.pair.a}</b> · with {f.pair.b}</div>
          </article>
        ))}
      </div>
    </div>
  </section>
);

const AfTransport = () => (
  <section className="af-sec af-trains" id="trains">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 06</div>
          <h2>Bush flights, overland trucks, <em>occasional rails.</em></h2>
          <p>Africa moves on small planes, 4×4s, and shared minibuses. Trains exist in Morocco, Egypt, Kenya and South Africa — and almost nowhere else. Plan accordingly.</p>
        </div>
      </header>
      <div className="af-trains-grid">
        <div className="blurb">
          <p><strong>Bush planes are the safari taxi.</strong> Cessna Caravans are noisy, hot, and the only sensible way to move between Tanzania, Kenya and Botswana camps. Soft duffels only — hard cases get refused at the strip. 15kg is the per-person limit.</p>
          <p>Overland trucks (Acacia, Intrepid, Dragoman) work for younger budgets and longer trips. Public transport works fine in Morocco, Egypt and South Africa. <strong>Self-drive is excellent in Namibia and South Africa</strong> and almost nowhere else — even Kenyan roads are punishing.</p>
          <div className="compare">
            <h5>Train vs. plane — door to door</h5>
            <div className="compare-row h"><span>Route</span><span className="train">Train</span><span className="plane">Plane</span></div>
            {AF_TRAIN_COMPARE.map((c, i) => (
              <div key={i} className="compare-row"><span>{c.route}</span><span className="train">{c.train}</span><span className="plane">{c.plane}</span></div>
            ))}
          </div>
        </div>
        <div className="af-routes">
          {AF_ROUTES.map((r, i) => (
            <article key={i} className="af-route">
              <div className="from"><span className="city">{r.from}</span><span className="code">{r.fromCode}</span></div>
              <div className="line">
                <span className="lbl"><b>{r.t}</b></span>
                <span className="lbl">{r.trains}</span>
              </div>
              <div className="to"><span className="city">{r.to}</span><span className="code">{r.toCode}</span></div>
            </article>
          ))}
        </div>
      </div>
    </div>
  </section>
);

const AfBudget = () => (
  <section className="af-sec af-budget" id="budget">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 07</div>
          <h2>Three Africas, <em>three budgets.</em></h2>
          <p>The continent doesn't share a price list. North Africa is the cheapest in the world. East Africa safaris are among the most expensive on Earth. Plan for the actual region you're visiting, not an average.</p>
        </div>
      </header>
      <div className="af-budget-grid">
        {AF_BUDGETS.map((b, i) => (
          <article key={i} className={`af-budget-card ${b.middle ? "middle" : ""}`}>
            <div className="h">
              <span className="lvl">{b.lvl}</span>
              <span className="day"><em>${b.day}</em><span className="u">/day</span></span>
            </div>
            <h4>{b.title}</h4>
            <ul className="lines">
              {b.lines.map((l, k) => (
                <li key={k}><span>{l[0]}</span><span>{l[1]}</span></li>
              ))}
            </ul>
            <p className="note">{b.note}</p>
          </article>
        ))}
      </div>
    </div>
  </section>
);

const AfLang = () => (
  <section className="af-sec af-lang" id="language">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 08</div>
          <h2>Five phrases per <em>country.</em></h2>
          <p>Two thousand languages live on the continent; nobody is going to learn them in advance. The four words that move every meal forward, and the one that opens every door.</p>
        </div>
      </header>
      <div className="af-lang-grid">
        {AF_LANG.map((l, i) => (
          <article key={i} className="af-lang-card">
            <div className="country">{l.country}</div>
            <dl>
              {l.phrases.map((p, k) => (
                <React.Fragment key={k}>
                  <dt>{p.dt}</dt>
                  <dd>{p.dd}</dd>
                </React.Fragment>
              ))}
            </dl>
          </article>
        ))}
      </div>
    </div>
  </section>
);

const AfFestivals = () => (
  <section className="af-sec af-fest" id="festivals">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 09</div>
          <h2>Festivals worth a <em>detour.</em></h2>
          <p>Six dates that bend an itinerary. Book early; some sell out a year ahead, and the desert ones move location for safety.</p>
        </div>
      </header>
      <div className="af-fest-grid">
        {AF_FESTS.map((f, i) => (
          <article key={i} className="af-fest-card">
            <span className="num">{f.num}</span>
            <div>
              <div className="when">{f.when}</div>
              <div className="where">{f.where}</div>
              <h4>{f.h4}</h4>
              <p>{f.p}</p>
            </div>
            <div className="stars">{f.stars}</div>
          </article>
        ))}
      </div>
    </div>
  </section>
);

const AfNbhd = () => (
  <section className="af-sec af-nbhd" id="neighborhoods">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 10</div>
          <h2>Six neighborhoods we <em>trust.</em></h2>
          <p>Stay here. Eat here. Walk for two days before you do anything else.</p>
        </div>
      </header>
      <div className="af-nbhd-grid">
        {AF_NEIGHBORHOODS.map((n, i) => (
          <article key={i} className="af-nbhd-row">
            <div className="num">{n.num}</div>
            <div>
              <h3 className="name"><em>{n.em}</em></h3>
              <div className="city">{n.city}</div>
              <p>{n.p}</p>
              <div className="why">Why · {n.why}</div>
            </div>
          </article>
        ))}
      </div>
    </div>
  </section>
);

const AfPack = () => (
  <section className="af-sec af-pack" id="packing">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 11</div>
          <h2>Pack for sun, dust, <em>and bush.</em></h2>
          <p>The packing list that fits in a 15kg soft duffel — bush flights ban hard cases. Trade the bright t-shirts for two long linen shirts you actually like.</p>
        </div>
      </header>
      <div className="af-pack-grid">
        {AF_PACK_LISTS.map((p, i) => (
          <article key={i} className="af-pack-list">
            <h4>{p.h4.split(p.em).map((part, j, arr) => j < arr.length - 1 ? <React.Fragment key={j}>{part}<em>{p.em}</em></React.Fragment> : part)}</h4>
            <div className="sub">{p.sub}</div>
            <ul>
              {p.items.map((it, k) => (
                <li key={k} className={it.startsWith("Tip") ? "tip" : undefined}>{it}</li>
              ))}
            </ul>
          </article>
        ))}
      </div>
    </div>
  </section>
);

const AfFAQ = () => (
  <section className="af-sec af-faq" id="faq">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Chapter 12</div>
          <h2>The questions, <em>answered.</em></h2>
          <p>The eight questions every reader sends before a first African trip. Updated April 2026.</p>
        </div>
      </header>
      <div className="af-faq-grid">
        <aside className="aside">
          <p>If your question isn't here, the team answers reader mail every Thursday — write us at <strong>letters@howtotraveledition.com</strong> and we'll point you at the right guide, or write a new one.</p>
          <p>For visa, vaccination, and yellow-fever questions: the visas page is updated monthly with the latest from each country's foreign-affairs ministry and the WHO.</p>
        </aside>
        <div>
          {AF_FAQS.map((f, i) => (
            <details key={i} className="af-faq-item" open={i === 0 || undefined}>
              <summary>{f.q}</summary>
              <div className="a" dangerouslySetInnerHTML={{ __html: f.a }} />
            </details>
          ))}
        </div>
      </div>
    </div>
  </section>
);

const AfRelated = () => (
  <section className="af-sec af-related" id="related">
    <div className="container">
      <header className="af-sec-head">
        <div className="ttl">
          <div className="kicker">Keep reading</div>
          <h2>Four more <em>dispatches.</em></h2>
          <p>From the Plan Desk and the field — recent pieces worth a slow morning.</p>
        </div>
      </header>
      <div className="af-related-grid">
        {AF_RELATED.map((r, i) => (
          <a key={i} className="af-related-card" href={r.href}>
            <span className="lbl">{r.lbl}</span>
            <h4 dangerouslySetInnerHTML={{ __html: r.h4 }} />
            <span className="by">{r.by}</span>
          </a>
        ))}
      </div>
    </div>
  </section>
);

const AfSignoff = () => (
  <section className="af-signoff">
    <div className="af-signoff-inner container">
      <span className="kicker">— End of Issue Nº 15 · Africa —</span>
      <Marquee
        items={["Dry season", "Bush flights", "Two long lunches", "One country at a time", "Soft bag only", "Don't rush the medina"]}
        variant="giant"
        separator="✦"
        speed={50}
      />
      <div className="af-signoff-meta">
        <span>HowTo: Travel Edition</span>
        <span className="dash">—</span>
        <span>Issue Nº 015</span>
        <span className="dash">—</span>
        <span>Spring 2026</span>
        <span className="dash">—</span>
        <span>Field desk Marrakech</span>
        <span className="dash">—</span>
        <span>1,400 contributors strong</span>
      </div>
    </div>
  </section>
);

const AfricaApp = () => (
  <div data-screen-label="Africa Landing">
    <Nav />
    <AfHero />
    <AfPills />
    <AfAnchor />
    <AfIntro />
    <AfCountries />
    <AfClusters />
    <AfWhen />
    <AfItineraries />
    <AfFood />
    <AfTransport />
    <AfBudget />
    <AfLang />
    <AfFestivals />
    <AfNbhd />
    <AfPack />
    <AfFAQ />
    <AfRelated />
    <AfSignoff />
    <Footer />
  </div>
);

ReactDOM.createRoot(document.getElementById("root")).render(<AfricaApp />);
