#!/usr/bin/env python3
# Book 32 (Bharat Electronics) — THE EYES AND EARS OF THE NATION. Science->business: radar is a SHOUT
# and an ECHO (shout a radio wave at the sky, listen for the echo, the TIME it takes tells you how far)
# -> the company that builds the sensing and talking gear a whole nation leans on.
import os
ART="/root/omahaindia.com/comics/site/book/bel/art"
OUT="/root/omahaindia.com/comics/site/book/bel/index.html"
STYLE=("children's storybook manga illustration, warm painted animation style, soft cinematic light, "
"clean linework, NO text NO letters NO words")
CHARLOTTE=("Charlotte, the SAME young Indian CHILD girl from the reference, round young face, warm tan skin, "
"freckles, glossy black hair in two low twin ponytails, big curious dark eyes, bright TEAL t-shirt, NO facial hair")
GRAHAM="Ben, a kind scholarly elderly American gentleman, round wire spectacles, tweed suit and bow tie"
BUFFETT="Warren, a folksy cheerful elderly American man, thinning white hair, big friendly glasses, grey suit"
MUNGER="Charlie, a stocky wise elderly American man, very thick black-framed glasses, dark suit"
VANCE=("Vance, a warm friendly Western RADAR ENGINEER, NOT Indian, close-cropped grey hair, steady kind smile, "
"olive technician's jacket, a headset resting around his neck, a green circuit board in one hand")

# name -> (w,h,seed,prompt,ref). ref set -> Seedream character; None -> flux scene. Ritual panels copied by mkbook.
NEW={
 "00_cover":(1024,1180,3200,f"{STYLE}. BOOK COVER, {CHARLOTTE} standing with {VANCE} on a windy hilltop beside a huge white rotating radar dish, a glowing blue ripple of radio waves sweeping out over mountains and coast and coming back as a soft echo, tall antennas and a calm dawn sky, wonder, cinematic","charlotte"),
 "_ref_vance":(1024,1024,3201,f"{STYLE}. clean friendly character portrait, {VANCE}, plain soft warm background, kind smile, head and shoulders",None),
 # Ch1
 "be_c1_coin":(1024,720,3210,f"{STYLE}. {CHARLOTTE} at home, Grandpa Ben's glowing brass compass twitching between a little toy bat hanging over the desk and a tall antenna blinking on the rooftop outside the window, EXPRESSION puzzled and intrigued, cozy lamp light","charlotte"),
 "be_c1_diary":(1024,720,3211,f"{STYLE}. an open magical diary glowing warm gold on a desk, a faint blue ripple of sound rising from the page, bouncing off an invisible wall and curling back to the paper, no people",None),
 "be_c1_swirl":(1024,720,3212,f"{STYLE}. {CHARLOTTE} pulled into a swirling spiral of golden light and blue humming ripples from a glowing diary, EXPRESSION thrilled, magical","charlotte"),
 # Ch2 — arrive at the radar station, meet Vance
 "be_c2_arrive":(1024,720,3213,f"{STYLE}. {CHARLOTTE} landing wide-eyed on a windy hilltop radar station, an enormous white dish turning slowly above her and a forest of antennas around, EXPRESSION awe and delight, bright morning light","charlotte"),
 "be_c2_vance":(1024,720,3214,f"{STYLE}. {VANCE} warmly welcoming {CHARLOTTE} at the radar station, offering her his headset, EXPRESSION Charlotte shy happy smile; keep the SAME engineer from the reference, same olive jacket, same headset, same circuit board","vance"),
 "be_c2_dish":(1024,720,3215,f"{STYLE}. a giant white radar dish turning against a wide dawn sky, soft blue ripples fanning out from it across distant mountains, tiny figures below for scale, powerful and awe-inspiring, no faces close up",None),
 # Ch3 — the shout and the echo
 "be_c3_shout":(1024,720,3216,f"{STYLE}. {CHARLOTTE} cupping her hands and shouting across a wide canyon, a bright ripple of sound flying out from her mouth toward the far cliff, EXPRESSION playful and gleeful; {VANCE} beside her grinning encouragement, SAME engineer, olive jacket, headset, circuit board","vance"),
 "be_c3_echo":(1024,720,3217,f"{STYLE}. a magical canyon scene, a glowing ripple of sound striking a far cliff wall and bouncing back as a softer returning ripple, arrows curving out and back, playful science, no people",None),
 "be_c3_bat":(1024,720,3218,f"{STYLE}. a friendly little bat at dusk squeaking tiny glowing ripples into the dark, the ripples bouncing off a moth and returning to its ears, cute and magical, no people",None),
 # Ch4 — the TIME of the echo is the distance
 "be_c4_clock":(1024,720,3219,f"{STYLE}. {CHARLOTTE} watching a big friendly stopwatch tick as a glowing ripple travels out to a far cliff and back, the hand measuring the return, EXPRESSION concentrating hard and working it out, warm light","charlotte"),
 "be_c4_near":(1024,720,3220,f"{STYLE}. a playful split scene, a near cliff sending a glowing ripple back quickly with a small stopwatch, and a far cliff sending it back slowly with a big stopwatch, showing near equals quick and far equals slow, no people",None),
 "be_c4_ruler":(1024,720,3221,f"{STYLE}. a magical glowing ripple flying across a starry sky with a long shining measuring ruler drawn underneath it, turning travel time into distance, playful science, no people",None),
 # Ch5 — radio waves: shouting at the sky
 "be_c5_radio":(1024,720,3222,f"{STYLE}. a giant radar dish flinging an invisible blue radio ripple far out over clouds and sea, the ripple drawn as glowing rings racing away, dramatic and beautiful, no people",None),
 "be_c5_ping":(1024,720,3223,f"{STYLE}. {VANCE} showing {CHARLOTTE} a round glowing radar screen where a soft returning echo blooms as a bright dot, EXPRESSION Charlotte delighted 'aha'; SAME engineer, olive jacket, headset, circuit board","vance"),
 # Ch6 — sonar: the same trick with sound, underwater
 "be_c6_sonar":(1024,720,3224,f"{STYLE}. {CHARLOTTE} in a cozy little submarine window watching glowing rings of sound spread through deep blue water and bounce off the seabed and a whale, EXPRESSION awed and excited, magical underwater light","charlotte"),
 "be_c6_ears":(1024,720,3225,f"{STYLE}. a ship on a calm sea sending glowing ripples of sound straight down, the ripples bouncing off a rocky seabed and returning, cutaway of blue water, playful science, no people",None),
 # Ch7 — sensing and talking together, for everyone
 "be_c7_network":(1024,720,3226,f"{STYLE}. a warm nighttime scene where radar towers, coastal antennas, ships and aircraft all trade glowing threads of light with one another, a gentle watching network over a sleeping land, no faces close up",None),
 "be_c7_calm":(1024,720,3227,f"{STYLE}. a warm storybook map of India at night ringed with soft glowing radar sweeps along its coasts and mountains, a quiet protective glow over homes and harbours, gentle and grand, no people",None),
 # Ch8 — reveal Bharat Electronics
 "be_c8_reveal":(1024,720,3228,f"{STYLE}. {CHARLOTTE} and {VANCE} standing proudly before a bright modern electronics factory with radar dishes and antennas on its roof against a blue sky, EXPRESSION proud recognition; SAME engineer, olive jacket, headset, circuit board","charlotte"),
 "be_c8_1954":(1024,720,3229,f"{STYLE}. warm sepia 1950s scene, a small new electronics workshop where careful hands build the country's first radio sets and valves at long wooden benches, hopeful and inspiring, no text",None),
 "be_c8_scale":(1024,720,3230,f"{STYLE}. a mighty modern electronics plant at golden hour, clean rooms, rows of green circuit boards, giant radar dishes waiting outside, proud and hi-tech, no people",None),
 # Ch10 (ch9 uses ritual castle/invert/verdict; ch10 uses ritual wake/diary)
 "be_c10_look":(1024,720,3231,f"{STYLE}. {CHARLOTTE} outside at dusk looking up with wonder as soft invisible ripples sweep quietly over her town from a distant hilltop antenna, a plane blinking safely overhead, EXPRESSION delighted wonder","charlotte"),
}

def P(img,cap=None,b1=None,b2=None,sfx=None,sfxc="#e8425a",tall=False): return ("panel",img,cap,b1,b2,sfx,sfxc,tall)
def SUB(d,t): return ("sub",d,t)
def WOW(t): return ("wow",t)
def NOTE(t,b): return ("note",t,b)
def TL(r): return ("timeline",r)
def MOAT(c): return ("moat",c)

CHAPTERS=[
 ("c1","CHAPTER 1","The Bat and the Antenna","pages 1-8",[
   P("be_c1_coin","Back home, Grandpa Ben's compass twitched again — pointing between a little toy bat and a blinking antenna on the rooftop.","A bat… and an antenna? What's the link?",None,"twitch"),
   P("be_c1_diary","The old diary fell open. A new line shimmered in Grandpa Ben's hand.",None,'"Shout at the sky. Then listen for what comes back."'),
   WOW("A bat flies through pitch darkness and never bumps into anything. A tall antenna on a hill can spot a plane hundreds of kilometres away. They look nothing alike — yet they use the <b>very same trick</b>. What is it? That's the puzzle of this whole adventure."),
   P("be_c1_swirl","Golden light swirled up and pulled Charlotte in.","Here we GO!",None,"WHOOSH","#2f6fb2"),
   NOTE("Charlotte's Secret Notebook","Two BIG questions:<br>➊ How does a bat 'see' in the dark without any light?<br>➋ Grandpa Ben says you should <i>shout</i> at the sky and <i>listen</i>. Listen for WHAT? 🦇"),
 ]),
 ("c2","CHAPTER 2","The Dish on the Windy Hill","pages 9-16",[
   P("be_c2_arrive","One blink, and she stood on a windy hilltop under a great white dish, slowly turning, turning.","It's listening to something up there!"),
   P("be_c2_vance","A cheerful man with a headset waved. \"I'm Vance, a radar engineer. Up here we shout at the sky — and the sky answers.\"","The sky… ANSWERS?!"),
   P("be_c2_dish","The dish swept round, and something invisible fanned out from it, all the way to the far mountains.","I can't see a thing — but something is definitely going out there!","Stick with me, kiddo."),
   NOTE("Charlotte's Secret Notebook","Vance is a radar engineer, and he grins like he has a secret — just like the other guides did. He says the sky ANSWERS when you shout at it. Okay Vance… show me! ✨"),
 ]),
 ("c3","CHAPTER 3","Shout, and Wait","pages 17-26",[
   P("be_c3_shout","Vance walked her to a canyon. \"Go on,\" he grinned. \"Shout as loud as you like.\"","HELLOOOOO!",None,"HELLO!","#2f6fb2"),
   P("be_c3_echo","One… two… and back it came, softer, from the far cliff. Her own voice, returning.","My shout BOUNCED off the cliff and came home!"),
   P("be_c3_bat","\"A bat does this all night,\" said Vance. \"It squeaks into the dark and listens for the squeak coming back.\"","It's not seeing — it's LISTENING to the bounce!",None,"squeak","#7a4ea8"),
   WOW("Here's the first secret! 🦇 Send out a shout, and whatever it hits <b>bounces it back</b> to you. That returning shout is an <b>echo</b>. A bat can fly in total darkness because it squeaks and listens to its own echoes — that's called <b>echo-location</b>."),
   ("diagram",),
   NOTE("Charlotte's Secret Notebook","Shout → it hits something → it bounces back = an ECHO. A bat squeaks in the dark and listens to the echo to know what's ahead. That's echo-location! 🔊"),
 ]),
 ("c4","CHAPTER 4","The Clock Tells You How Far","pages 27-36",[
   P("be_c4_clock","\"Now the clever bit,\" said Vance. \"Don't just listen to the echo. TIME it.\"","Time my own shout?"),
   P("be_c4_near","A near cliff answered almost at once. A far cliff took ages. Same shout — different wait.","Quick echo means NEAR. Slow echo means FAR!"),
   P("be_c4_ruler","\"The shout always travels at the same speed,\" he said. \"So the TIME it takes is a ruler.\"","The waiting IS the measuring!",None,"tick tick","#2f6fb2"),
   WOW("This is the whole idea. 🕐 Your shout travels at a <b>steady speed</b>. So a long wait means the echo went a long way, and a short wait means it didn't. <b>The time the echo takes tells you how far away the thing is</b> — without touching it, and without seeing it."),
   NOTE("Charlotte's Secret Notebook · SOLVED (part 1)","The shout goes at the same speed always. So: slow echo = far away, fast echo = close. TIME becomes DISTANCE. The bat isn't guessing — it's measuring! ⏱️"),
 ]),
 ("c5","CHAPTER 5","Shouting With Radio","pages 37-44",[
   P("be_c5_radio","\"Now,\" said Vance, \"swap the squeak for a radio wave — an invisible shout that goes unbelievably fast and unbelievably far.\"","An invisible shout!",None,"FWOOM","#2f6fb2"),
   P("be_c5_ping","The dish flung it out. Seconds later a tiny echo bloomed on the round screen — a plane, far out past the clouds.","There it is — I'm SEEING it with an echo!"),
   WOW("That's <b>radar</b>: a radio shout at the sky, and a listen for the echo. The dish sends an invisible radio wave, something out there bounces it back, and the <b>time</b> it took says exactly how far away it is. A bat's trick — made enormous."),
   NOTE("Charlotte's Secret Notebook","RADAR = shout with radio waves, listen for the echo, time it. That's how one dish on a hill can find a plane hundreds of kilometres away, at night, in fog. 📡"),
 ]),
 ("c6","CHAPTER 6","The Same Trick, Underwater","pages 45-52",[
   P("be_c6_sonar","Down in the blue, rings of sound spread out and came back off the seabed — and off a passing whale.","The ocean has echoes too!"),
   P("be_c6_ears","\"Radio waves don't like water,\" said Vance, \"so under the sea we shout with SOUND instead. That's sonar.\"","Same trick — different shout!"),
   WOW("<b>Sonar</b> is the same idea wearing a swimsuit: shout with <b>sound</b> through the water, listen for the echo, time it. Radar for the sky, sonar for the sea — one simple trick, two whole worlds. (And whales and dolphins figured it out first!) 🐋"),
   NOTE("Charlotte's Secret Notebook · SOLVED!","Radar = radio echoes in the air. Sonar = sound echoes in water. Both: SHOUT → ECHO → TIME → DISTANCE. Bats and whales knew it before we did! 🌊"),
 ]),
 ("c7","CHAPTER 7","The Eyes and Ears of Everyone","pages 53-60",[
   P("be_c7_network","Vance swept his arm across the night. Towers, ships, aircraft — all quietly trading little threads of light.","They're all TALKING to each other!"),
   P("be_c7_calm","\"Sensing is only half of it,\" he said. \"Once you've spotted something, you must be able to TELL someone — safely, instantly.\"","Eyes AND ears… AND a voice!"),
   WOW("A country needs <b>eyes</b> (radars that see far), <b>ears</b> (sonars that listen deep) and a <b>voice</b> (radios that carry the message safely). Together, that's how coasts stay watched, planes land safely and help arrives fast. Most nights nobody notices — which means it's working."),
   NOTE("Charlotte's Secret Notebook","Sensing gear + talking gear = a country's eyes, ears and voice. Radars watch the sky, sonars listen to the sea, radios carry the word. Quiet, but everywhere. 🌏📡"),
 ]),
 ("c8","CHAPTER 8 · THE BIG DISCOVERY","The Maker of the Eyes and Ears","pages 61-70",[
   P("be_c8_reveal","Vance led Charlotte to a viewpoint over a bright factory, dishes and antennas crowded on its roof.","Who BUILDS all of this?"),
   P("be_c8_1954","\"In 1954,\" said Vance, \"the country started a workshop to build its own radios and valves, instead of buying them from far away.\"","Make our own listening gear!"),
   P("be_c8_scale","\"It grew and grew — radars, sonars, radio sets, whole systems. The nation's eyes and ears.\"","From little radios… to giant radars!"),
   WOW("A \"company\" can be a giant shared job. <b>Bharat Electronics</b> began in 1954 making radios, and grew into the maker of the <b>radars, sonars and secure radios</b> a whole nation leans on — the eyes and ears of the country."),
   TL([("1954","A small workshop starts making the country's own radio sets and valves."),
       ("Over decades","It learns radar, sonar and secure communication — harder and harder gear."),
       ("Today","Its systems watch the coasts and skies and carry the nation's messages."),
       ("Tomorrow","New eyes and ears: smarter sensors, and more customers beyond just one. 📡")]),
   NOTE("Charlotte's Secret Notebook","Bharat Electronics (1954) started with radios and grew into the maker of the country's radars, sonars and secure radio gear. The eyes and ears of the nation! 🏆"),
 ]),
 ("c9","CHAPTER 9","The Castle on the Hilltop","pages 71-80",[
   P("be_c9_castle","Two kind old men appeared with a glow. Warren pointed at a castle standing among tall antennas. \"What keeps rivals out, Charlotte?\"","Walls! But what kind?"),
   MOAT([("🤝","Wall One: Decades of Trust","When gear must never, ever fail, nobody buys from a stranger. Trust like that takes decades to earn — and a newcomer simply doesn't have the years.",False),
         ("🧠","Wall Two: Secret Know-How","How to make a radar that truly works is knowledge built up slowly, kept close, and learned from thousands of tries. You cannot buy that in a shop.",False),
         ("🛡️","Wall Three: A Customer Who Can't Shop Casually","This gear is bought carefully, slowly, and only from a maker who has proved itself for years. Rivals can't just turn up and offer a discount.",False),
         ("⚠️","The Crack in the Wall","Almost all the orders come from ONE big customer. If that customer buys less this year, the whole company feels it. Leaning on one buyer is a wobbly leg.",True)]),
   P("be_c9_munger","Charlie tapped his head. \"Don't just ask how to WIN. Ask how you'd LOSE — then don't do that. Invert!\"","Think backwards?"),
   WOW("<b>Charlie's Inversion:</b> to keep an eyes-and-ears maker strong, imagine how it could FADE — one customer goes quiet, or the gear stops being the best while newer sensors race ahead — then carefully avoid each one, and find more customers early."),
   P("be_c9_verdict","Warren nodded. \"Decades of trust and know-how a rival can't copy — a mighty castle, so long as it isn't waiting by one door for one knock.\"","I SEE the whole picture!"),
   NOTE("Charlotte's Secret Notebook · The Big Secret","Bharat Electronics is hard to copy: DECADES of trust, SECRET know-how, and a customer who cannot shop casually. But it leans on ONE big customer's orders. Charlie's trick: picture how you'd lose (one buyer goes quiet), then never do it. Invert! 🏰"),
 ]),
 ("c10","CHAPTER 10","The Quiet Ripples","pages 81-88",[
   P("be_c10_wake","Charlotte woke in her own bed. The great dish was gone… but her toy bat swung gently over the desk.","Was it real? It FELT real…"),
   P("be_c10_diary","On the diary's page, a new line glowed — as if Grandpa Ben wrote it just for her.",None,'"Now you can hear what comes back. Well done."'),
   P("be_c10_look","She ran outside at dusk. A plane blinked safely overhead, and somewhere on a hill a dish was turning — shouting, listening, keeping watch.","The whole sky is full of echoes — I just couldn't hear them!"),
   WOW("Next time a plane crosses the dark sky, you'll know the secret: something <b>shouted</b> at it, and something <b>listened</b> for the echo, and the <b>time</b> told them exactly where it was. That's how a country grows <b>the eyes and ears of the nation.</b> 📡🦇"),
   NOTE("Charlotte's Secret Notebook · What I Learned","➊ Shout, and it bounces back — that's an ECHO.<br>➋ The TIME the echo takes tells you how FAR — bats do it, and so do we.<br>➌ RADAR = the echo trick with radio waves in the air; SONAR = with sound in water.<br>➍ A nation needs eyes, ears and a safe voice — sensing gear plus talking gear.<br>➎ Bharat Electronics builds them; its moat is decades of trust and know-how — but Charlie's trick: picture how you'd lose (one big customer goes quiet), then don't. 💛"),
 ]),
]

HOOK=("be_c1_swirl","EVERY ORDINARY THING HIDES A SECRET.",
 "Charlotte learned to hear what comes back. But the compass is twitching again — toward the little glass window in her hand that somehow knows exactly where she is standing on the whole round Earth. Who is whispering to it, and from how far away?",
 "NEXT ADVENTURE · The Voice From the Sky →")

DIAGRAM='''<div class="panel wide" style="background:#eef4fb;">
<svg viewBox="0 0 820 380"><rect width="820" height="380" fill="#eef4fb"/>
<text x="410" y="38" text-anchor="middle" font-family="Bangers" font-size="24" fill="#2f6fb2">THE ECHO TELLS YOU HOW FAR</text>
<g><circle cx="120" cy="150" r="34" fill="#f6b53f" stroke="#c8621f" stroke-width="4"/><text x="120" y="112" text-anchor="middle" font-family="Baloo 2" font-size="15" fill="#c8621f">THE SHOUT</text><text x="120" y="235" text-anchor="middle" font-family="Nunito" font-size="13" fill="#555">a wave goes out</text></g>
<g stroke="#2f6fb2" stroke-width="5" fill="#2f6fb2"><line x1="160" y1="150" x2="300" y2="150" stroke-dasharray="10 8"/><path d="M296 141 L314 150 L296 159Z"/></g>
<g><rect x="320" y="112" width="150" height="90" rx="12" fill="#fff" stroke="#171717" stroke-width="4"/><text x="395" y="102" text-anchor="middle" font-family="Baloo 2" font-size="14" fill="#2aa15a">THE THING OUT THERE</text><text x="395" y="165" text-anchor="middle" font-family="Bangers" font-size="26" fill="#2aa15a">bounces it</text><text x="395" y="235" text-anchor="middle" font-family="Nunito" font-size="13" fill="#555">a cliff, a plane, a seabed</text></g>
<g stroke="#7a4ea8" stroke-width="5" fill="#7a4ea8"><line x1="480" y1="150" x2="600" y2="150" stroke-dasharray="10 8"/><path d="M596 141 L614 150 L596 159Z"/></g>
<text x="540" y="135" text-anchor="middle" font-family="Baloo 2" font-size="12" fill="#7a4ea8">the echo returns</text>
<text x="540" y="182" text-anchor="middle" font-family="Nunito" font-size="12" fill="#555">softer, but the same shout</text>
<g><rect x="620" y="112" width="150" height="90" rx="12" fill="#2f6fb2" stroke="#171717" stroke-width="4"/><text x="695" y="102" text-anchor="middle" font-family="Baloo 2" font-size="16" fill="#c8621f">TIME IT</text><text x="695" y="165" text-anchor="middle" font-family="Bangers" font-size="24" fill="#f6b53f">= how far</text><text x="695" y="235" text-anchor="middle" font-family="Nunito" font-size="13" fill="#555">a clock becomes a ruler</text></g>
<rect x="70" y="300" width="680" height="52" rx="9" fill="#fff" stroke="#171717" stroke-width="3"/>
<text x="410" y="322" text-anchor="middle" font-family="Nunito" font-size="14" fill="#123">Quick echo &#8594; the thing is NEAR. Slow echo &#8594; the thing is FAR. Radio in the air = RADAR; sound in water = SONAR.</text>
<text x="410" y="343" text-anchor="middle" font-family="Nunito" font-size="13" fill="#555">A bat has done this in the dark for millions of years. We just built a very big one.</text>
</svg><div class="figcap">Send a wave out, wait for the echo, and time it — the waiting itself measures the distance.</div></div>'''

try:
    from book_extra import EXTRA, NEW2
    NEW.update(NEW2)
except Exception:
    EXTRA={}

def render_panel(pn,pageno=None):
    _,img,cap,b1,b2,sfx,sfxc,tall=pn
    pg=f'<div class="pageno">{pageno}</div>' if pageno else ''
    p=[f'<div class="panel wide">{pg}<img src="art/{img}.jpg" alt="" loading="lazy">']
    if cap: p.append(f'<div class="cap tl tilt">{cap}</div>')
    if b1: p.append(f'<div class="bubble dl" style="left:12px;bottom:12px;">{b1}</div>')
    if b2: p.append(f'<div class="bubble dr" style="right:12px;top:12px;">{b2}</div>')
    if sfx: p.append(f'<div class="sfx" style="left:40%;top:14px;font-size:32px;color:{sfxc};">{sfx}</div>')
    p.append('</div>'); return "".join(p)

def render_item(it,pageno=None):
    t=it[0]
    if t=="panel": return render_panel(it,pageno)
    if t=="diagram": return DIAGRAM
    if t=="sub": return f'<div class="sub"><span class="dot">{it[1]}</span><b>{it[2]}</b></div>'
    if t=="wow": return f'<div class="wow">{it[1]}</div>'
    if t=="note": return f'<div class="note"><div class="nt">{it[1]}</div><p>{it[2]}</p></div>'
    if t=="timeline":
        rows="".join(f'<div class="tl"><div class="yr">{y}</div><p>{x}</p></div>' for y,x in it[1])
        return f'<div class="timeline">{rows}</div>'
    if t=="moat":
        cards="".join(f'<div class="mc{" bad" if bad else ""}"><h4>{ic} {ti}</h4><p>{tx}</p></div>' for ic,ti,tx,bad in it[1])
        return f'<div class="moat">{cards}</div>'
    return ""

def referenced_images():
    imgs=set()
    for cls,_,_,_,items in CHAPTERS:
        for it in items:
            if it[0]=="panel": imgs.add(it[1])
        for it in EXTRA.get(cls,[]):
            if it[0]=="panel": imgs.add(it[1])
    imgs.add(HOOK[0]); imgs.add("00_cover"); imgs.add("_ref_vance"); return imgs

def build():
    body=[]; pageno=0
    for cls,num,title,pglabel,items in CHAPTERS:
        items=list(items); extra=EXTRA.get(cls,[])
        if extra:
            idx=[i for i,it in enumerate(items) if it[0]=="panel"]
            at=(idx[-1]+1) if idx else len(items)
            for ex in reversed(extra): items.insert(at,ex)
        start=pageno+1
        inner=[f'<div class="chapbar {cls}"><div class="n">{num}</div><h2>{title}</h2></div>']
        for it in items:
            if it[0]=="panel": pageno+=1; inner.append(render_item(it,pageno))
            else: inner.append(render_item(it))
        lbl=f"pages {start}-{pageno}" if pageno>=start else pglabel
        body.append(f'<div class="sheet" data-pg="{lbl}">{"".join(inner)}</div>')
    hook=f'''<div class="sheet" data-pg="the end… for now"><div class="hook"><img src="art/{HOOK[0]}.jpg" alt="">
<div class="hc"><h3>{HOOK[1]}</h3><p>{HOOK[2]}</p><div class="b2">{HOOK[3]}</div></div></div></div>'''
    head=open("/root/omahaindia.com/comics/site/book/bel/_head.html").read()
    tail=open("/root/omahaindia.com/comics/site/book/bel/_tail.html").read()
    open(OUT,"w").write(head+"".join(body)+hook+tail)
    print("built",OUT,"| chapters:",len(CHAPTERS),"| images:",len(referenced_images()))

if __name__=="__main__":
    build()
