#!/usr/bin/env python3
# Book 30 (InterGlobe Aviation / IndiGo) — THE BLUE BIRD THAT NEVER WAITS. Science->business: a curved wing
# is curved and tilted so it pushes the air DOWNWARD, so the air pushes the wing UP (lift); engines push forward
# (thrust) and the air pushes back (drag) -> a plane only earns while flying, so turn it around FAST and fly
# ONE kind of plane -> the airline that is never late.
import os
ART="/root/omahaindia.com/comics/site/book/indigo/art"
OUT="/root/omahaindia.com/comics/site/book/indigo/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"
SKYE=("Skye, a warm friendly Western WOMAN airline pilot, FEMALE with a clearly feminine face and kind smile, NOT Indian, navy blue uniform with "
"gold stripes on the sleeves, a captain's cap over neat shoulder-length blonde hair, a flight bag 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,1600,f"{STYLE}. BOOK COVER, {CHARLOTTE} standing with {SKYE} on a sunny airport apron beside the nose of a bright blue-and-white airliner, holding up a paper plane that trails a ribbon of glowing air over its curved wing, a big clock and a golden dawn sky behind them, wonder, cinematic","charlotte"),
 "_ref_skye":(1024,1024,1601,f"{STYLE}. clean friendly character portrait, {SKYE}, plain soft warm background, calm confident smile, head and shoulders",None),
 # Ch1
 "ig_c1_coin":(1024,720,1610,f"{STYLE}. {CHARLOTTE} at home, Grandpa Ben's glowing brass compass twitching between a small paper plane and a ticking wall clock, EXPRESSION puzzled and intrigued, cozy lamp light","charlotte"),
 "ig_c1_diary":(1024,720,1611,f"{STYLE}. an open magical diary glowing warm gold on a desk, a faint ribbon of blue air rising from the page and curling over a tiny paper wing, no people",None),
 "ig_c1_swirl":(1024,720,1612,f"{STYLE}. {CHARLOTTE} pulled into a swirling spiral of golden light and rushing blue air from a glowing diary, EXPRESSION thrilled, magical","charlotte"),
 # Ch2 — arrive at the airport, meet Skye
 "ig_c2_arrive":(1024,720,1613,f"{STYLE}. {CHARLOTTE} landing wide-eyed on a busy airport apron, an enormous blue-and-white airliner towering over her, baggage carts and fuel trucks bustling, EXPRESSION awe and delight, bright morning daylight","charlotte"),
 "ig_c2_skye":(1024,720,1614,f"{STYLE}. {SKYE} warmly welcoming {CHARLOTTE} beside the airliner, touching the brim of her captain's cap, EXPRESSION Charlotte shy happy smile; keep the SAME pilot from the reference, same navy uniform with gold stripes, same captain's cap and flight bag","skye"),
 "ig_c2_apron":(1024,720,1615,f"{STYLE}. a huge airport apron seen from above, rows of identical blue-tailed airliners parked at gates, tiny trucks and ground crew scurrying between them for scale, busy and awe-inspiring, no faces close up",None),
 # Ch3 — the wing pushes air down, so the air pushes it up
 "ig_c3_hand":(1024,720,1616,f"{STYLE}. {SKYE} kneeling to hold {CHARLOTTE}'s open hand flat out into a rushing stream of glowing blue air, the hand tilting and lifting upward, EXPRESSION Charlotte surprised and giggling; SAME pilot, navy uniform with gold stripes, captain's cap","skye"),
 "ig_c3_curve":(1024,720,1617,f"{STYLE}. a beautiful close up of a curved tilted airplane wing slicing forward and sweeping a broad stream of glowing blue air steeply DOWNWARD behind and below it, a big soft glowing arrow pointing DOWN for the air and a smaller arrow pointing UP for the wing, clean simple science, no people",None),
 "ig_c3_press":(1024,720,1618,f"{STYLE}. a friendly diagram-like scene of a curved wing flinging a stream of glowing blue air steeply downward while one big bright arrow lifts the wing upward, happy simple physics, no people",None),
 # Ch4 — lift, and thrust vs drag
 "ig_c4_lift":(1024,720,1619,f"{STYLE}. {CHARLOTTE} standing proudly on the broad WING of a big blue-and-white AIRLINER soaring high in a bright sunrise sky, the whole plane climbing upward, her twin ponytails streaming, EXPRESSION exhilarated and laughing; clearly a real airplane wing NOT a float or tube, cinematic","charlotte"),
 "ig_c4_thrust":(1024,720,1620,f"{STYLE}. a close up of a jet engine blowing a powerful stream of air backward while the whole plane surges forward, glowing motion arrows, energetic, no people",None),
 "ig_c4_drag":(1024,720,1621,f"{STYLE}. a playful scene of invisible air hands pushing back against a speeding plane like a strong wind against an open umbrella, blue swirls of resistance, no people",None),
 # Ch5 — a plane only earns while flying
 "ig_c5_parked":(1024,720,1622,f"{STYLE}. a lonely bright BLUE-AND-WHITE airliner parked at an empty gate under a big plain clock (clock has NO numbers), still and quiet, dust motes in a pale beam of light, gently sad, no people, no text",None),
 "ig_c5_clock":(1024,720,1623,f"{STYLE}. {SKYE} showing {CHARLOTTE} a big airport clock beside the parked plane, gesturing at the empty gate, EXPRESSION Charlotte thoughtful frowning 'oh!'; SAME pilot, navy uniform with gold stripes, captain's cap","skye"),
 # Ch6 — the fast turnaround
 "ig_c6_turn":(1024,720,1624,f"{STYLE}. {CHARLOTTE} watching a whirlwind of ground crew swarm a plane at once — cleaning, refuelling, loading bags, passengers boarding — everything happening in minutes, EXPRESSION astonished and dizzy, bright busy apron","charlotte"),
 "ig_c6_dance":(1024,720,1625,f"{STYLE}. a joyful choreographed scene like a pit stop dance, a fuel hose, a bag belt, a cleaning cart and a boarding stair all moving in perfect rhythm around one airliner, glowing motion trails, no faces close up",None),
 # Ch7 — one kind of plane
 "ig_c7_same":(1024,720,1626,f"{STYLE}. a long neat row of identical blue-and-white airliners lined up nose to tail like matching toy models, tidy and satisfying, warm evening light, no people",None),
 "ig_c7_toolbox":(1024,720,1627,f"{STYLE}. a friendly comparison scene, one tidy toolbox with a single set of spare parts beside one plane, versus a messy jumble of many different mismatched toolboxes beside many different planes, playful storybook style, no people",None),
 # Ch8 — reveal IndiGo
 "ig_c8_reveal":(1024,720,1628,f"{STYLE}. {CHARLOTTE} and {SKYE} standing proudly before a great blue-and-white airliner and a busy terminal glowing against a blue sky, EXPRESSION proud recognition; SAME pilot, navy uniform with gold stripes, captain's cap","charlotte"),
 "ig_c8_2006":(1024,720,1629,f"{STYLE}. warm sepia-tinted 2000s scene, a single brand new airliner rolling out of a hangar while a small hopeful team watches, the beginning of something big, inspiring, no text",None),
 "ig_c8_scale":(1024,720,1630,f"{STYLE}. a mighty fleet of matching blue-tailed airliners filling a golden-hour sky and apron, the biggest airline in the country, proud and grand, no people",None),
 # Ch10 (ch9 uses ritual castle/invert/verdict; ch10 uses ritual wake/diary)
 "ig_c10_look":(1024,720,1631,f"{STYLE}. {CHARLOTTE} outside at dusk gazing up as a tiny plane draws a glowing white line across the pink sky, a paper plane in her hand, 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 Paper Plane and the Clock","pages 1-8",[
   P("ig_c1_coin","Back home, Grandpa Ben's compass twitched again — pointing between a little paper plane and the ticking wall clock.","A paper plane… and a clock? What's the link?",None,"twitch"),
   P("ig_c1_diary","The old diary fell open. A new line shimmered in Grandpa Ben's hand.",None,'"Find out why the air pushes UP — and why waiting costs money."'),
   WOW("A plane is heavier than a bus, yet it floats in thin air. And a clock has nothing to do with flying… or does it? Two puzzles, one adventure: what holds a plane UP, and why is being late so very expensive?"),
   P("ig_c1_swirl","Golden light swirled up and pulled Charlotte in.","Here we GO!",None,"WHOOSH","#1f6fc8"),
   NOTE("Charlotte's Secret Notebook","Two BIG questions:<br>➊ How does something so heavy stay up in the sky?<br>➋ Why is Grandpa Ben's compass pointing at a CLOCK? ✈️"),
 ]),
 ("c2","CHAPTER 2","The Field of Blue Birds","pages 9-16",[
   P("ig_c2_arrive","One blink, and she stood on a windy apron, a blue-and-white giant towering over her head.","It's a bird as big as a BUILDING!"),
   P("ig_c2_skye","A woman in a navy uniform with gold stripes waved. \"I'm Skye. I fly these. Want to know how the air holds them up?\"","The air… HOLDS it up?!"),
   P("ig_c2_apron","All around, matching blue-tailed planes waited at their gates while tiny trucks scurried between them.","They all look exactly the SAME!","Good eye, kiddo. That's a clue."),
   NOTE("Charlotte's Secret Notebook","Skye is a pilot, and she grins like she has a secret — just like the other guides did. She says the AIR holds the plane up. And every plane here looks the same. Curious. ✨"),
 ]),
 ("c3","CHAPTER 3","How the Air Holds Us Up","pages 17-26",[
   P("ig_c3_hand","Skye held Charlotte's flat hand out into the rushing air and tilted it. The hand jumped upward all by itself.","Something PUSHED my hand up!"),
   P("ig_c3_curve","\"Look at a wing,\" said Skye. \"It's gently curved and tilted just so. As it slices through the sky, it flings the air DOWNWARD.\"","So it pushes the air DOWN!"),
   P("ig_c3_press","\"And here's the trick,\" she smiled. \"Push the air DOWN — and the air pushes right back, shoving the wing UP just as hard.\"","Down for the air, UP for the wing!",None,"push","#1f6fc8"),
   WOW("Here's the first secret! 💡 A wing is <b>curved and tilted</b>. As it flies it <b>pushes the air downward</b> — and the air pushes back just as hard, lifting the wing <b>UP</b>. Push down on the air, and the air lifts you up. That's how air can hold up a plane."),
   ("diagram",),
   NOTE("Charlotte's Secret Notebook","A wing is curved and tilted, so as it flies it flings the air DOWNWARD. The air pushes back and shoves the wing UP. Push the air down → the wing goes up. ☁️⬆️"),
 ]),
 ("c4","CHAPTER 4","Lift, Thrust and the Pushing-Back Air","pages 27-36",[
   P("ig_c4_lift","\"That upward push has a name,\" said Skye. \"We call it LIFT — and it's what carries us into the sky.\"","LIFT! It's lifting the whole plane!"),
   P("ig_c4_thrust","\"But air only hurries if we go fast. The engines blow air backwards, and that shoves us forwards — that's THRUST.\"","Push the air back, and it pushes YOU forward!",None,"ROAAR","#c8621f"),
   P("ig_c4_drag","\"And the air pushes back on us too — like a wind against an umbrella. We call that DRAG.\"","The air fights back a bit!"),
   WOW("Three words to keep forever: <b>THRUST</b> is the engines shoving air backward so the plane surges forward. <b>DRAG</b> is the air pushing back. And when the plane goes fast, the tilted wing flings air down, so the air pushes it <b>UP</b> — that's <b>LIFT</b>."),
   NOTE("Charlotte's Secret Notebook · SOLVED (part 1)","Engines push air back → the plane goes forward (THRUST). Air pushes back on the plane (DRAG). A fast wing flinging air downward pushes the plane up (LIFT). That's how something heavy flies! 🛫"),
 ]),
 ("c5","CHAPTER 5","A Plane Only Earns in the Sky","pages 37-44",[
   P("ig_c5_parked","Round the corner sat a plane at an empty gate. Silent. Still. The big clock above it ticked on.","Why is that one just… sitting there?"),
   P("ig_c5_clock","\"Here's the second secret,\" said Skye quietly. \"A plane only earns while it's FLYING. Sitting on the ground, it costs money every single minute.\"","So waiting is EXPENSIVE?"),
   WOW("A plane is enormously expensive whether it flies or naps. But it only <b>earns</b> when it's up in the air with people aboard. Every minute parked at a gate is a minute of cost with <b>no</b> money coming in. That's why the compass pointed at a <b>clock.</b>"),
   NOTE("Charlotte's Secret Notebook","A parked plane costs money and earns NOTHING. A flying plane earns. So the clock matters as much as the wing! ⏰"),
 ]),
 ("c6","CHAPTER 6","The Minutes Dance","pages 45-52",[
   P("ig_c6_turn","The moment a plane rolled in, everything happened at once — bags out, bags in, cleaning, fuel, passengers boarding — a blur.","It's like a whirlwind!"),
   P("ig_c6_dance","\"We call it the turnaround,\" grinned Skye. \"Clean it, fuel it, board it — and back in the sky in minutes. Every minute saved is a minute earning.\"","So being FAST is the whole point!"),
   WOW("If a plane only earns in the sky, the trick is to <b>turn it around fast</b> — clean, fuel, load and board in <b>minutes</b>, not hours. Do that and each plane makes more flights every day, which makes each seat <b>cheaper</b> — and gets everyone there <b>on time.</b>"),
   NOTE("Charlotte's Secret Notebook · SOLVED!","The whole chain: fast turnaround → more flights per plane per day → cheaper tickets AND on-time flights. The clock IS the business. ⚡"),
 ]),
 ("c7","CHAPTER 7","One Kind of Bird","pages 53-60",[
   P("ig_c7_same","Charlotte looked down the row again. Every plane. Exactly. The same.","That's why they're all identical!"),
   P("ig_c7_toolbox","\"One kind of plane,\" said Skye, \"means one set of spare parts, one training, one checklist. Simple is cheap — and simple is fast.\"","Same plane = fewer muddles!"),
   WOW("Fly <b>one kind of plane</b> and every mechanic knows it, every pilot is trained for it, and one shelf of spare parts fits them all. Many different planes means many toolboxes, many trainings, many muddles. <b>Same is simple. Simple is cheap and quick.</b>"),
   NOTE("Charlotte's Secret Notebook","One kind of plane = one set of parts, one training, one checklist. That keeps costs low and turnarounds fast. Boring on purpose! 🔧"),
 ]),
 ("c8","CHAPTER 8 · THE BIG DISCOVERY","The Blue Bird That Never Waits","pages 61-70",[
   P("ig_c8_reveal","Skye led Charlotte to a viewpoint over the busy terminal and its blue-tailed fleet.","Who flies ALL of these?"),
   P("ig_c8_2006","\"In 2006,\" said Skye, \"this airline began with a single plane and one stubborn promise: be cheap, and be on time.\"","One plane… that's all?"),
   P("ig_c8_scale","\"It kept that promise, over and over — until it became the biggest airline in the country.\"","From one bird to a whole SKY of them!"),
   WOW("A \"company\" can be a giant shared promise. <b>IndiGo</b> began in 2006 with one plane and one idea: fly <b>one kind of plane</b>, turn it around <b>fast</b>, keep fares low and be <b>on time</b> — and it grew into India's <b>largest airline.</b>"),
   TL([("2006","One airline begins, with one plane and a promise: cheap, and on time."),
       ("Over the years","One kind of plane, fast turnarounds — flight after flight, on time."),
       ("Today","It is the biggest airline in India, carrying most of the country's flyers."),
       ("Tomorrow","Farther flights and bigger skies — if fuel and weather allow. ✈️")]),
   NOTE("Charlotte's Secret Notebook","IndiGo (2006) started with ONE plane. One kind of plane + lightning turnarounds + low fares + on time = India's biggest airline. 🏆"),
 ]),
 ("c9","CHAPTER 9","The Castle in the Sky","pages 71-80",[
   P("ig_c9_castle","Two kind old men appeared with a glow. Warren pointed at a great castle above a deep moat. \"What keeps rivals out, Charlotte?\"","Walls! But what kind?"),
   MOAT([("⏱️","Wall One: The On-Time Habit","Being on time isn't luck — it's thousands of tiny habits, practised daily for years. A rival can copy the planes, but not the habit.",False),
         ("✈️","Wall Two: One Kind of Plane","One fleet means one set of parts, one training, one checklist. Costs stay low, so fares stay low — and nobody can undercut you easily.",False),
         ("🌐","Wall Three: Giant Scale","The most planes, the most gates, the most flights every day. More flights means more choice for flyers, which brings more flyers still.",False),
         ("⚠️","The Crack in the Wall","Fuel prices and weather are NEVER in your control. A fuel spike or a storm season can hurt even the best-run airline — so it must stay strong and thrifty.",True)]),
   P("ig_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 airline strong, imagine how it could FALL — planes idling at gates, a jumble of different aircraft, flights running late, or debts too heavy when fuel jumps — then carefully avoid each one."),
   P("ig_c9_verdict","Warren nodded. \"Cheap, simple and never late — a fine castle. Just remember: nobody owns the price of fuel, and nobody owns the weather.\"","I SEE the whole picture!"),
   NOTE("Charlotte's Secret Notebook · The Big Secret","IndiGo is hard to copy: the ON-TIME habit, ONE kind of plane, and giant SCALE. But fuel prices and weather are never in its control. Charlie's trick: picture how you'd lose (idle planes, late flights, a fuel shock), then never do it. 🏰"),
 ]),
 ("c10","CHAPTER 10","The Sky Above Our Heads","pages 81-88",[
   P("ig_c10_wake","Charlotte woke in her own bed. The great apron was gone… but the little paper plane on her desk shimmered softly.","Was it real? It FELT real…"),
   P("ig_c10_diary","On the diary's page, a new line glowed — as if Grandpa Ben wrote it just for her.",None,'"Now you know why the air pushes up — and why minutes are money. Well done."'),
   P("ig_c10_look","She ran outside at dusk. High above, a tiny plane drew a glowing white line across the pink sky — right on time.","The air is holding it up — and somebody's counting the minutes!"),
   WOW("Next time a plane crosses the sky, you'll know both secrets: the <b>tilted wing</b> pushes the air downward, so the air pushes it <b>UP</b>. And down below, a whole team is racing the clock — because a plane only earns while <b>flying.</b> That's <b>the blue bird that never waits.</b> ✈️⏱️"),
   NOTE("Charlotte's Secret Notebook · What I Learned","➊ A wing is curved and tilted; it pushes air DOWN, so the air pushes the wing UP. That's LIFT.<br>➋ Engines push air back (THRUST); the air pushes back on us (DRAG).<br>➌ A plane only earns while flying — parked, it just costs.<br>➍ So: turn it around FAST, and fly ONE kind of plane. Cheap, simple, on time.<br>➎ IndiGo's moat is the on-time habit + scale — but fuel and weather are never in your control. Charlie's trick: picture how you'd lose, then don't. 💛"),
 ]),
]

HOOK=("ig_c1_swirl","EVERY ORDINARY THING HIDES A SECRET.",
 "Charlotte learned why the air pushes a wing up, and why every minute on the ground costs money. But the compass is twitching again — toward the little glass rectangle in her pocket that somehow knows the whole world. What's really inside it?",
 "NEXT ADVENTURE · The Glass That Thinks →")

DIAGRAM='''<div class="panel wide" style="background:#eef4fb;">
<svg viewBox="0 0 900 700"><rect width="900" height="700" fill="#eef4fb"/>
<text x="450" y="72" text-anchor="middle" font-family="Bangers" font-size="48" fill="#1f6fc8" letter-spacing="1">HOW A WING MAKES LIFT</text>
<text x="150" y="176" text-anchor="middle" font-family="Baloo 2" font-size="23" font-weight="700" fill="#1f6fc8">THE WING</text>
<rect x="38" y="196" width="224" height="150" rx="18" fill="#fff" stroke="#171717" stroke-width="5"/>
<text x="150" y="262" text-anchor="middle" font-family="Bangers" font-size="30" fill="#1f6fc8">CURVED &amp; TILTED</text>
<text x="150" y="305" text-anchor="middle" font-family="Nunito" font-size="20" font-weight="700" fill="#555">it flies forward</text>
<g stroke="#1f6fc8" stroke-width="8" fill="#1f6fc8"><line x1="272" y1="271" x2="336" y2="271" stroke-dasharray="13 10"/><path d="M330 256 L360 271 L330 286Z"/></g>
<text x="470" y="176" text-anchor="middle" font-family="Baloo 2" font-size="23" font-weight="700" fill="#1f6fc8">IT PUSHES THE AIR</text>
<rect x="358" y="196" width="224" height="150" rx="18" fill="#fff" stroke="#171717" stroke-width="5"/>
<text x="470" y="298" text-anchor="middle" font-family="Bangers" font-size="66" fill="#2aa15a">DOWN</text>
<g stroke="#2aa15a" stroke-width="10" fill="#2aa15a"><line x1="470" y1="356" x2="470" y2="440"/><path d="M453 433 L470 466 L487 433Z"/></g>
<g stroke="#e08a1f" stroke-width="8" fill="#e08a1f"><line x1="590" y1="271" x2="654" y2="271" stroke-dasharray="13 10"/><path d="M648 256 L678 271 L648 286Z"/></g>
<text x="790" y="176" text-anchor="middle" font-family="Baloo 2" font-size="23" font-weight="700" fill="#e08a1f">LIFT</text>
<rect x="678" y="196" width="224" height="150" rx="18" fill="#1f6fc8" stroke="#171717" stroke-width="5"/>
<text x="790" y="290" text-anchor="middle" font-family="Bangers" font-size="46" fill="#ffcf4a">PUSHED UP</text>
<g stroke="#f2b134" stroke-width="10" fill="#f2b134"><line x1="790" y1="446" x2="790" y2="360"/><path d="M773 366 L790 333 L807 366Z"/></g>
<rect x="70" y="520" width="760" height="104" rx="16" fill="#fff" stroke="#171717" stroke-width="5"/>
<text x="450" y="585" text-anchor="middle" font-family="Baloo 2" font-size="34" font-weight="700" fill="#123">Push the air <tspan fill="#2aa15a">DOWN</tspan> &#8594; the wing goes <tspan fill="#e08a1f">UP</tspan>.</text>
</svg><div class="figcap">The wing pushes air down, so the air pushes the wing up.</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_skye"); 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/indigo/_head.html").read()
    tail=open("/root/omahaindia.com/comics/site/book/indigo/_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()
