#!/usr/bin/env python3
# Book 27 (Wipro) — FROM SOAP TO SOFTWARE. Science->business: metamorphosis (a caterpillar becomes a
# butterfly) -> a company that pressed cooking oil and cut soap learned a new skill and became a
# software company writing and running the programs the world's companies live on.
import os
ART="/root/omahaindia.com/comics/site/book/wipro/art"
OUT="/root/omahaindia.com/comics/site/book/wipro/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"
FELIX=("Felix, a warm friendly Western SOFTWARE ENGINEER, NOT Indian, round glasses, tousled brown hair, "
"a mustard yellow cardigan over a collared shirt, a slim laptop under one arm, curious smile")

# name -> (w,h,seed,prompt,ref). ref set -> Seedream character; None -> flux scene. Ritual panels copied by mkbook.
NEW={
 "00_cover":(1024,1180,2700,f"{STYLE}. BOOK COVER, {CHARLOTTE} standing with {FELIX} in a bright glass office, holding up a plain bar of soap that is dissolving into a shower of glowing blue-green code sparks, a huge butterfly made of light unfolding its wings behind them, wonder, cinematic","charlotte"),
 "_ref_felix":(1024,1024,2701,f"{STYLE}. clean friendly character portrait, {FELIX}, plain soft warm background, curious smile, head and shoulders",None),
 # Ch1
 "wi_c1_coin":(1024,720,2710,f"{STYLE}. {CHARLOTTE} at home, Grandpa Ben's glowing brass compass twitching between a plain bar of soap and a softly glowing laptop screen on the table, EXPRESSION puzzled and intrigued, cozy lamp light","charlotte"),
 "wi_c1_diary":(1024,720,2711,f"{STYLE}. an open magical diary glowing warm gold on a desk, a faint ribbon of soap bubbles rising from the page and turning into tiny sparks of blue-green light, no people",None),
 "wi_c1_swirl":(1024,720,2712,f"{STYLE}. {CHARLOTTE} pulled into a swirling spiral of golden light, soap bubbles and glowing green sparks from a glowing diary, EXPRESSION thrilled, magical","charlotte"),
 # Ch2 — arrive at the old oil mill, meet Felix
 "wi_c2_arrive":(1024,720,2713,f"{STYLE}. {CHARLOTTE} landing wide-eyed inside a warm old-fashioned cooking oil mill, wooden presses, sacks of seeds, golden oil trickling into tins, dusty sunbeams, EXPRESSION surprised and amused, warm daylight","charlotte"),
 "wi_c2_felix":(1024,720,2714,f"{STYLE}. {FELIX} warmly welcoming {CHARLOTTE} in the old oil mill, holding his laptop and gesturing at the wooden presses, EXPRESSION Charlotte shy happy smile; keep the SAME engineer from the reference, same round glasses, same mustard cardigan, same laptop","felix"),
 "wi_c2_soap":(1024,720,2715,f"{STYLE}. a friendly close up of plain cream-coloured soap bars being cut from a long slab and stacked in neat rows on a wooden bench, homely and warm, no faces close up",None),
 # Ch3 — the caterpillar: one body, one job
 "wi_c3_cat":(1024,720,2716,f"{STYLE}. {FELIX} kneeling to show {CHARLOTTE} a plump green caterpillar munching a leaf on a twig, EXPRESSION Charlotte fascinated leaning in; SAME engineer, round glasses, mustard cardigan, laptop","felix"),
 "wi_c3_munch":(1024,720,2717,f"{STYLE}. a cheerful close up of a green caterpillar steadily eating its way along a big leaf, one simple job done very well, playful nature study, no people",None),
 "wi_c3_crawl":(1024,720,2718,f"{STYLE}. a caterpillar crawling slowly along a branch while bright butterflies flutter high above out of reach, gentle wistful mood, no people",None),
 # Ch4 — the chrysalis: the hidden rebuild
 "wi_c4_wrap":(1024,720,2719,f"{STYLE}. {CHARLOTTE} watching in hushed wonder as a caterpillar spins itself into a smooth jade-green chrysalis hanging from a twig, EXPRESSION quiet awe and tenderness, soft dusk light","charlotte"),
 "wi_c4_inside":(1024,720,2720,f"{STYLE}. a magical glowing cutaway of a chrysalis, the old caterpillar shape dissolving into swirling golden soup while faint new wing shapes begin to form inside, mysterious and beautiful, no people",None),
 "wi_c4_patience":(1024,720,2721,f"{STYLE}. a single jade chrysalis hanging very still on a twig under gentle rain and then moonlight, time quietly passing, patient and calm, no people",None),
 # Ch5 — the butterfly: same creature, new powers
 "wi_c5_open":(1024,720,2722,f"{STYLE}. a brand new butterfly slowly unfolding its damp crumpled wings out of a split chrysalis, morning light shining through the wings, triumphant and delicate, no people",None),
 "wi_c5_fly":(1024,720,2723,f"{STYLE}. {FELIX} and {CHARLOTTE} laughing as the new butterfly lifts off from her fingertip into the bright sky, EXPRESSION Charlotte joyful open-mouthed cheer; SAME engineer, round glasses, mustard cardigan, laptop","felix"),
 # Ch6 — the company's own metamorphosis: soap -> software
 "wi_c6_switch":(1024,720,2724,f"{STYLE}. {CHARLOTTE} watching a magical transformation as a stack of soap bars dissolves into a rising swarm of glowing blue-green code sparks that reassemble into a laptop, EXPRESSION astonished and delighted, dramatic glow","charlotte"),
 "wi_c6_desks":(1024,720,2725,f"{STYLE}. a bright cheerful office of engineers at glowing screens building software together, warm lamps, plants, whiteboards covered in friendly diagrams, hopeful and busy, no faces close up",None),
 # Ch7 — what software actually does for the world
 "wi_c7_world":(1024,720,2726,f"{STYLE}. a warm storybook globe with glowing threads of light running from one bright office out to banks, airports, hospitals and shops all around the world, quietly keeping them running, no people",None),
 "wi_c7_help":(1024,720,2727,f"{STYLE}. {FELIX} showing {CHARLOTTE} a big friendly screen where a tangled knot of messy lines is being combed neatly into tidy glowing rows, EXPRESSION Charlotte satisfied grin, bright office; SAME engineer, round glasses, mustard cardigan, laptop","felix"),
 # Ch8 — reveal Wipro
 "wi_c8_reveal":(1024,720,2728,f"{STYLE}. {CHARLOTTE} and {FELIX} standing proudly before a huge modern glass campus with green lawns and a butterfly-shaped fountain of light, EXPRESSION proud recognition; SAME engineer, round glasses, mustard cardigan, laptop","charlotte"),
 "wi_c8_1945":(1024,720,2729,f"{STYLE}. warm sepia 1940s scene, a small vegetable oil mill with wooden presses and tin cans, hopeful workers, humble beginnings, inspiring, no text",None),
 "wi_c8_scale":(1024,720,2730,f"{STYLE}. a mighty modern technology campus at golden hour, glass towers, walkways, thousands of lit windows, a glowing butterfly of light arcing over it, proud and grand, no people",None),
 # Ch10 (ch9 uses ritual castle/invert/verdict; ch10 uses ritual wake/diary)
 "wi_c10_look":(1024,720,2731,f"{STYLE}. {CHARLOTTE} outside at dusk looking with wonder as faint glowing threads of code drift out of every ordinary thing around her — a bus ticket machine, a shop till, a hospital sign — 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 Soap and the Screen","pages 1-8",[
   P("wi_c1_coin","Back home, Grandpa Ben's compass twitched again — pointing between a plain bar of soap and a glowing laptop screen.","Soap… and a computer? Those aren't even cousins!",None,"twitch"),
   P("wi_c1_diary","The old diary fell open. A new line shimmered in Grandpa Ben's hand.",None,'"Find the creature that threw away its old body and grew wings."'),
   WOW("A bar of soap and a computer screen have nothing in common — yet one company began by making soap and today writes software for the whole world. How does a thing become something completely different… and stay itself? That's the puzzle of this whole adventure."),
   P("wi_c1_swirl","Golden light and soap bubbles swirled up and pulled Charlotte in.","Here we GO!",None,"WHOOSH","#c8621f"),
   NOTE("Charlotte's Secret Notebook","Two BIG questions:<br>➊ How can a soap-maker turn into a software company?<br>➋ Grandpa Ben says something must <i>grow wings</i>. What kind of creature throws away its old body on purpose? 🦋"),
 ]),
 ("c2","CHAPTER 2","The Mill That Smelled of Oil","pages 9-16",[
   P("wi_c2_arrive","One blink, and she stood in a warm old mill. Wooden presses groaned, and golden cooking oil trickled into tins.","This is a KITCHEN factory — where's the computer?"),
   P("wi_c2_felix","A cheerful man in a mustard cardigan waved, laptop under one arm. \"I'm Felix, a software engineer. Funny place to find me, isn't it?\"","A computer person… in an OIL MILL?!"),
   P("wi_c2_soap","On a bench nearby, long slabs of soap were being cut into plain cream-coloured bars.","Oil and soap. Is that ALL this company did?","Once upon a time, yes."),
   NOTE("Charlotte's Secret Notebook","Felix builds software — but he brought me to a cooking-oil mill that also cuts soap. He grins like he has a secret, just like the other guides did. Okay Felix… explain! ✨"),
 ]),
 ("c3","CHAPTER 3","The Creature With One Job","pages 17-26",[
   P("wi_c3_cat","Felix pointed to a twig. \"Meet a caterpillar. It has one job in the whole world: eat leaves. And it's very good at it.\"","One job, done really well!"),
   P("wi_c3_munch","\"Munch, munch, munch, all day long. That's its whole life. Nothing wrong with it — it's how it grows.\"","Like the mill pressing oil, every single day."),
   P("wi_c3_crawl","\"But look up,\" said Felix. High above, butterflies danced where a crawling caterpillar could never go.","It can only CRAWL. The sky isn't for it… is it?",None,"sigh","#2aa15a"),
   WOW("Here's the first secret! 🐛 A caterpillar is brilliant at <b>one job</b> — eating leaves. But its body can only crawl. The sky belongs to creatures with wings. Being very good at today's job doesn't give you tomorrow's sky."),
   ("diagram",),
   NOTE("Charlotte's Secret Notebook","A caterpillar has ONE body and ONE job. It's good at it! But it can only crawl, and the sky stays out of reach. Being good at today isn't the same as being ready for tomorrow. 🐛"),
 ]),
 ("c4","CHAPTER 4","The Hidden Rebuild","pages 27-36",[
   P("wi_c4_wrap","\"Then one day,\" whispered Felix, \"it does the bravest thing.\" The caterpillar wrapped itself into a smooth jade case and went still.","It's… closing the door on itself!"),
   P("wi_c4_inside","\"Inside, it doesn't just grow wings. It melts down almost everything it used to be — and builds again.\"","It takes itself APART?!",None,"hush","#37414d"),
   P("wi_c4_patience","\"And it waits. Rain, night, morning. You can't rush a rebuild.\"","Nothing's happening… but EVERYTHING is."),
   WOW("Inside the chrysalis, the caterpillar <b>dissolves most of its old body</b> and rebuilds into a new shape. It is scary, slow and quiet — and it is the only way the crawler ever reaches the sky. That's called <b>metamorphosis:</b> becoming something new while still being you."),
   NOTE("Charlotte's Secret Notebook · SOLVED (part 1)","Inside the case, the caterpillar melts down its old body and builds a NEW one. It's called metamorphosis. It's slow and it's brave — you can't rush it. 🫧"),
 ]),
 ("c5","CHAPTER 5","Wings","pages 37-44",[
   P("wi_c5_open","The case split. Out climbed something new, wings damp and crumpled, drying in the morning light.","It's the SAME creature — with a whole new shape!",None,"crack","#c8621f"),
   P("wi_c5_fly","It stepped onto Charlotte's finger, opened its wings — and the sky was suddenly its.","GO ON! FLY!"),
   WOW("The butterfly is <b>the same creature</b> as the caterpillar. Same life, new body, new powers. What it <i>was</i> changed completely — but the one thing it never lost was the ability to <b>keep growing.</b> That's the part worth keeping."),
   NOTE("Charlotte's Secret Notebook","Same creature. New body. New sky. What a thing IS can change — the skill of growing is what carries across. 🦋"),
 ]),
 ("c6","CHAPTER 6","The Company That Grew Wings","pages 45-52",[
   P("wi_c6_switch","Felix tapped the soap. It dissolved into a swarm of glowing sparks — and the sparks became a laptop.","The soap company turned into a COMPUTER company?!"),
   P("wi_c6_desks","\"Same company,\" he said. \"It stopped pressing oil and learned to write software. Its chrysalis was years of learning.\"","It went into a case… and came out with wings!"),
   WOW("This company really did it. It began making <b>cooking oil and soap</b>, then slowly, deliberately learned a brand-new skill — <b>writing software</b> — and became a technology company. A caterpillar became a butterfly. Oil → soap → chrysalis of learning → software."),
   NOTE("Charlotte's Secret Notebook · SOLVED!","The soap company didn't die — it REBUILT. It kept learning until it could do a completely different job. What a company IS can change! 💻"),
 ]),
 ("c7","CHAPTER 7","What Software Actually Does","pages 53-60",[
   P("wi_c7_world","Felix spun a globe. Threads of light ran from one office out to banks, airports, hospitals and shops everywhere.","All those places need SOFTWARE?"),
   P("wi_c7_help","\"Companies have messy tangles of work,\" he said, combing a knot of lines into tidy glowing rows. \"We write and run the programs that untangle them.\"","So you tidy up the whole world's work!"),
   WOW("Here's the business: big companies everywhere need <b>software written and looked after</b> — the programs that run their money, their flights, their hospitals, their shops. This company does that job <b>for them</b>, all over the world, every day."),
   NOTE("Charlotte's Secret Notebook","The business = writing and running software for the world's companies. Banks, airports, hospitals, shops — someone has to build and mind their programs. That's the job. 🌍"),
 ]),
 ("c8","CHAPTER 8 · THE BIG DISCOVERY","From Soap to Software","pages 61-70",[
   P("wi_c8_reveal","Felix led Charlotte out to a huge glass campus with lawns and a fountain of light.","Wait — is THIS what the little oil mill became?"),
   P("wi_c8_1945","\"It started in 1945,\" said Felix, \"as a small vegetable oil mill. Tins and presses. Nothing more.\"","From THAT to all this!"),
   P("wi_c8_scale","\"Then it learned, and learned, and learned — until it wrote software for companies across the whole world.\"","The caterpillar was a company all along!"),
   WOW("A \"company\" is a group of people who share a job — and the job itself can change. <b>Wipro</b> began in 1945 pressing vegetable oil, added soap, then reinvented itself into one of India's great <b>software companies</b>, serving clients around the world."),
   TL([("1945","A small vegetable oil mill begins. Later it makes soap too."),
       ("1980s","The chrysalis: it starts learning computers — a brand-new skill."),
       ("Today","It writes and runs software for big companies all over the world."),
       ("Tomorrow","It must keep learning — new tools arrive every year. 🦋")]),
   NOTE("Charlotte's Secret Notebook","Wipro (1945) started as an OIL MILL, made soap, then reinvented itself into a software company for the world. Same company. Completely new wings. 🏆"),
 ]),
 ("c9","CHAPTER 9","The Castle Made of People","pages 71-80",[
   P("wi_c9_castle","Two kind old men appeared with a glow. Warren pointed at a castle built on a hill of glowing screens. \"What keeps rivals out, Charlotte?\"","Walls! But what kind?"),
   MOAT([("🧠","Wall One: Trained People","Thousands of engineers, trained for years. You can't buy that in a shop — you have to grow it, one person at a time.",False),
         ("🤝","Wall Two: Long Client Trust","When a bank lets you run its software for ten years, it doesn't swap you out lightly. Trust is slow to build and precious to keep.",False),
         ("🔁","Wall Three: The Habit of Reinventing","A company that has already grown wings once knows how it's done. That courage is itself a wall.",False),
         ("⚠️","The Crack in the Wall","Reinvention is rare and HARD. Tools change every year. Stop learning for even a little while, and a faster butterfly flies past you.",True)]),
   P("wi_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 a software company strong, imagine how it could FADE — its people stop learning new tools, or a client's trust is broken by sloppy work — then carefully avoid each one, and never stop training."),
   P("wi_c9_verdict","Warren nodded. \"Trained people and long trust — a fine castle, so long as it keeps learning faster than the world changes.\"","I SEE the whole picture!"),
   NOTE("Charlotte's Secret Notebook · The Big Secret","Wipro's walls: TRAINED PEOPLE and LONG CLIENT TRUST — both slow to build, hard to copy. But reinvention is rare and hard; you must keep learning or fall behind. Charlie's trick: picture how you'd lose (stop learning, break trust), then never do it. Invert! 🏰"),
 ]),
 ("c10","CHAPTER 10","Everything Can Become","pages 81-88",[
   P("wi_c10_wake","Charlotte woke in her own bed. The glass campus was gone… but the little soap bar on her desk shimmered softly.","Was it real? It FELT real…"),
   P("wi_c10_diary","On the diary's page, a new line glowed — as if Grandpa Ben wrote it just for her.",None,'"Now you know: what a thing IS can change. Well done."'),
   P("wi_c10_look","She ran outside at dusk. The ticket machine, the shop till, the hospital sign — quietly, invisibly, someone's software was running them all.","It's everywhere — I just couldn't see it!"),
   WOW("Next time someone tells you what they <i>are</i>, remember the caterpillar. A soap-maker became a software company. What matters isn't what you are today — it's the <b>skill you keep learning.</b> That's <b>from soap to software.</b> 🧼💻🦋"),
   NOTE("Charlotte's Secret Notebook · What I Learned","➊ A caterpillar is great at ONE job, but can only crawl.<br>➋ In the chrysalis it melts down its old body and rebuilds — metamorphosis.<br>➌ Wipro did the same: cooking oil and soap (1945) → learning → SOFTWARE.<br>➍ The business: writing and running software for the world's companies.<br>➎ Its walls are trained people and long client trust — but Charlie's trick: picture how you'd lose (stop learning), then never do it. 💛"),
 ]),
]

HOOK=("wi_c1_swirl","EVERY ORDINARY THING HIDES A SECRET.",
 "Charlotte watched a soap-maker grow wings. But the compass is twitching again — this time toward a tiny grain of sand that somehow knows how to think. How can a stone do arithmetic?",
 "NEXT ADVENTURE · The Thinking Sand →")

DIAGRAM='''<div class="panel wide" style="background:#fbf3ec;">
<svg viewBox="0 0 820 380"><rect width="820" height="380" fill="#fbf3ec"/>
<text x="410" y="38" text-anchor="middle" font-family="Bangers" font-size="24" fill="#c8621f">A COMPANY CAN CHANGE WHAT IT IS</text>
<g><rect x="60" y="112" width="150" height="90" rx="12" fill="#fff" stroke="#171717" stroke-width="4"/><text x="135" y="102" text-anchor="middle" font-family="Baloo 2" font-size="14" fill="#2aa15a">CATERPILLAR</text><text x="135" y="165" text-anchor="middle" font-family="Bangers" font-size="24" fill="#2aa15a">one job</text><text x="135" y="235" text-anchor="middle" font-family="Nunito" font-size="13" fill="#555">it eats leaves, and crawls</text></g>
<g stroke="#37414d" stroke-width="5" fill="#37414d"><line x1="220" y1="150" x2="320" y2="150" stroke-dasharray="10 8"/><path d="M316 141 L334 150 L316 159Z"/></g>
<text x="270" y="135" text-anchor="middle" font-family="Baloo 2" font-size="12" fill="#37414d">chrysalis</text>
<text x="270" y="182" text-anchor="middle" font-family="Nunito" font-size="12" fill="#555">rebuild inside</text>
<g><rect x="340" y="112" width="150" height="90" rx="12" fill="#fff" stroke="#171717" stroke-width="4"/><text x="415" y="102" text-anchor="middle" font-family="Baloo 2" font-size="14" fill="#c8621f">BUTTERFLY</text><text x="415" y="165" text-anchor="middle" font-family="Bangers" font-size="24" fill="#c8621f">new wings</text><text x="415" y="235" text-anchor="middle" font-family="Nunito" font-size="13" fill="#555">same creature, new sky</text></g>
<g stroke="#2aa15a" stroke-width="5" fill="#2aa15a"><line x1="500" y1="150" x2="600" y2="150" stroke-dasharray="10 8"/><path d="M596 141 L614 150 L596 159Z"/></g>
<text x="550" y="135" text-anchor="middle" font-family="Baloo 2" font-size="12" fill="#2aa15a">same idea</text>
<g><rect x="620" y="112" width="150" height="90" rx="12" fill="#37414d" stroke="#171717" stroke-width="4"/><text x="695" y="102" text-anchor="middle" font-family="Baloo 2" font-size="14" fill="#c8621f">SOAP &#8594; SOFTWARE</text><text x="695" y="165" text-anchor="middle" font-family="Bangers" font-size="22" fill="#f6b53f">reinvented</text><text x="695" y="235" text-anchor="middle" font-family="Nunito" font-size="13" fill="#555">an oil mill that learned to code</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">Caterpillar &#8594; chrysalis &#8594; butterfly. Cooking oil and soap &#8594; years of learning &#8594; software for the world.</text>
<text x="410" y="343" text-anchor="middle" font-family="Nunito" font-size="13" fill="#555">What a company IS can change. The skill it keeps learning is what really matters.</text>
</svg><div class="figcap">A caterpillar rebuilds itself into a butterfly; a soap-maker rebuilt itself into a software company.</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_felix"); 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/wipro/_head.html").read()
    tail=open("/root/omahaindia.com/comics/site/book/wipro/_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()
