diff --git a/library/packet/packet-render.js b/library/packet/packet-render.js index f59687465..9f25f15d2 100644 --- a/library/packet/packet-render.js +++ b/library/packet/packet-render.js @@ -11,11 +11,13 @@ // strings, language, the zone, its groups, photos, and the map SVG. That is what // lets the same code run under Node and in a browser tab. // -// PAGE ORDER IS THE PRODUCT SPEC, do not reorder: +// PAGE ORDER IS THE PRODUCT SPEC — change it only when the spec does, and update THIS comment in +// the same commit (it has gone stale twice; buildPacket's own comment is the authoritative copy): // 1 the map one-pager -// 2..n the people groups, 20 per page, with photos -// n+1 the 12 prayer points -// n+2 the prayer wheel +// 2 the inverted triangle (funnel) +// 3 the life calendar 4 the %-evangelical grid (full detail only) +// 5..n the people groups, 20 per page, with photos +// then the bounded/centered sets (full only), the prayer WHEEL, the 12 prayer POINTS // // I18N: every human-readable string comes from packet-strings.json. A new language // is a NEW BLOCK there, never a code change, and fallback is PER KEY so a @@ -1005,15 +1007,18 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de // is already at the edge of readable. A ninth belongs in an options object; flagged here so the // next person adding a page makes that change rather than extending the line again. function buildPacket(zone, groups, photos, mapSvg, funnel = null, christian = null, variant = 'full', sets = null) { - // ★ PAGE ORDER IS THE DRIVER'S, 2026-09-27, and it is an argument rather than a layout: + // ★ PAGE ORDER IS THE PRODUCT SPEC (A1, superseding the 2026-09-27 order this comment used to + // record — the reorder is the spec's own deliberate change, confirmed via the shepherd, and the + // stale "do not reorder" note updates in the SAME commit that reorders, as the plan card required): // 1 map — where this zone is - // 2 life calendar — 100 years x 52 weeks, a whole human life on one page - // 3 the SAME grid — shaded by the evangelical share of these groups' POPULATION - // 4 funnel — 12,379 -> 7,341 -> 4,754 -> 2,107 -> this list, 1 of N + // 2 funnel — the inverted triangle: 12,379 narrowing to THIS list, the argument first + // 3 life calendar — 100 years x 52 weeks, a whole human life on one page + // 4 the SAME grid — shaded by the evangelical share of these groups' POPULATION // 5..n people groups with photos and the three prayer columns - // then the 12 prayer points and the prayer wheel - // Pages 2 and 3 are deliberately adjacent: the reader learns to read 5,200 boxes as their own - // life, and then sees the same 5,200 boxes answer "how many of these people know Christ". + // then the bounded/centered sets (full only), the prayer WHEEL, and the 12 prayer POINTS — + // wheel before points, so the packet closes on what to pray rather than how long. + // Pages 3 and 4 stay adjacent: the reader learns to read 5,200 boxes as their own life, then + // sees the same 5,200 boxes answer "how many of these people know Christ". // ⚠ KEYED, NOT INDEXED. The omit-set names pages; it never carries positions. An index-based // filter reads identically today and silently drops the WRONG page the first time this order // changes — and the order above is the Driver's, so it is expected to change again. @@ -1023,15 +1028,15 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de const keep = (key) => !(omit && omit.has(key)); const pages = [ keep('map') && mapPage(zone, groups, mapSvg), + keep('funnel') && funnelPage(zone, groups, funnel), keep('life') && lifePage(zone), keep('christian') && christianPage(zone, christian), - keep('funnel') && funnelPage(zone, groups, funnel), // NOT behind keep() — see the VARIANTS comment: dropping list pages drops people. ...listPages(zone, groups, photos), - // BACK MATTER: after the profiles, before the wheel (brief A1). Full-detail only. + // BACK MATTER: after the profiles (brief A1). Full-detail only. keep('sets') && setsPage(zone, sets), - keep('points') && pointsPage(), keep('wheel') && wheelPage(), + keep('points') && pointsPage(), ].filter(Boolean); // ⚠ dir MUST be set for right-to-left languages or the packet renders Arabic // left-aligned — readable glyphs in the wrong place, which looks like a