diff --git a/library/packet/packet-render.js b/library/packet/packet-render.js index 8188ae75d..f5bd72c07 100644 --- a/library/packet/packet-render.js +++ b/library/packet/packet-render.js @@ -34,13 +34,16 @@ const RTL = new Set(['ar', 'he', 'fa', 'ur', 'ps', 'sd', 'yi']); // ⚠ A width heuristic got this exactly backwards — it reported Arabic and Chinese // broken and Hindi fine, because Devanagari tofu boxes happen to match real glyph // advance. Never infer glyph coverage from measurements; look at the pixels. +const DEVANAGARI_ALSO = "'Noto Sans Devanagari','Mangal','Nirmala UI','Kohinoor Devanagari'"; const SCRIPT_FONT = { + // `also`: the Devanagari faces a device commonly has, named after the vendored one, so a print whose caller + // supplies no fontData still lands on a real Devanagari face rather than on whatever the browser falls to. hi: { family: 'Noto Serif Devanagari', dir: 'noto-serif-devanagari', - file: 'noto-serif-devanagari-400-devanagari.woff2' }, + file: 'noto-serif-devanagari-400-devanagari.woff2', also: DEVANAGARI_ALSO }, mr: { family: 'Noto Serif Devanagari', dir: 'noto-serif-devanagari', - file: 'noto-serif-devanagari-400-devanagari.woff2' }, // Marathi, same script + file: 'noto-serif-devanagari-400-devanagari.woff2', also: DEVANAGARI_ALSO }, // Marathi, same script ne: { family: 'Noto Serif Devanagari', dir: 'noto-serif-devanagari', - file: 'noto-serif-devanagari-400-devanagari.woff2' }, // Nepali, same script + file: 'noto-serif-devanagari-400-devanagari.woff2', also: DEVANAGARI_ALSO }, // Nepali, same script }; // The set LAYOUTS (gospel's figures, promoted to library/ by regions). Imported rather than injected @@ -173,7 +176,7 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de // editing 22 hardcoded Georgia declarations. The browser falls through per // CHARACTER, so Latin text in a Hindi packet still renders in Georgia. const scriptStack = SF - ? `.sheet,.sheet *{font-family:'${SF.family}',Georgia,'Palatino Linotype',serif !important}` + ? `.sheet,.sheet *{font-family:'${SF.family}',${SF.also ? SF.also + ',' : ''}Georgia,'Palatino Linotype',serif !important}` : ''; function css() { @@ -256,7 +259,7 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de font:400 ${WS_DESC_PX}px/1.3 Georgia,serif;margin-top:2px} /* A TALLY cell: room for several groups of five marks, not a box for one tick. */ .ws-box{justify-self:center;width:${WS_TALLY_W - 10}px;height:${WS_ROW - 22}px;box-sizing:border-box;border:1.5px solid #b0a993;border-radius:6px;background:#fff} - .ws-foot{position:absolute;left:0;right:0;bottom:22px;text-align:center;font:400 12px Georgia,serif;color:#a89f8c} + .ws-foot{position:absolute;left:0;right:0;bottom:50px;text-align:center;font:400 12px Georgia,serif;color:#a89f8c} /* The first page's description and pace table: quiet type, one rule per section, nothing boxed. */ .ws-sec{margin:0 0 6px;font:700 14px Georgia,serif;letter-spacing:.14em;text-transform:uppercase;color:#8a8577} /* THE EXPLANATION BAND (explainBand): ruled above and below like the poster's header band, three columns @@ -284,12 +287,12 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de .xb-ex-note{margin-top:4px;font-size:14px;color:#6f6a5c} /* The prayer themes and scenes above the twelve points: a thin numbered list, ruled off below. */ .pt-themes{margin:0 0 10px;padding:0 0 6px;border-bottom:1.5px solid #c9bfa4} - .pt-th-h{font:400 19px/1.3 Georgia,serif;color:#413d35} - .pt-th-h b,.pt-sc-h b{font:700 20px Georgia,serif;color:#1b1a17;letter-spacing:.02em} + .pt-th-h{font:400 21px/1.3 Georgia,serif;color:#413d35} + .pt-th-h b,.pt-sc-h b{font:700 22px Georgia,serif;color:#1b1a17;letter-spacing:.02em} .pt-th-i{font-style:italic;color:#6d766e} - .pt-th-list{display:flex;flex-wrap:wrap;gap:1px 20px;margin:2px 0 0;padding:0;list-style:none;font:400 19px/1.3 Georgia,serif;color:#3b3226} + .pt-th-list{display:flex;flex-wrap:wrap;gap:1px 20px;margin:2px 0 0;padding:0;list-style:none;font:400 21px/1.3 Georgia,serif;color:#3b3226} .pt-n{display:inline-block;min-width:1.3em;font-weight:700;color:#7a3b2e} - .pt-sc-r{font:600 18px Georgia,serif;color:#7a3b2e} + .pt-sc-r{font:600 19px Georgia,serif;color:#7a3b2e} .ws-cols{margin:0;padding:0;list-style:none} .ws-cols li{margin:0 0 6px;font:400 19px/1.45 Georgia,serif;color:#413d35} .ws-cols li b{color:#1b1a17} @@ -396,7 +399,9 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de .d-fb{font:400 13px Georgia,serif;color:#6d766e;margin-top:2px} .mt{font:400 17px Georgia,serif;color:#6d766e} /* FINE PRINT — product decision: attribution minimal, fine print small. */ - .fine{position:absolute;left:0;right:0;bottom:22px;text-align:center; + /* ≥ 0.25in above the sheet's bottom edge (44px on letter): at 22px the credit line sat 0.14in from the edge, + inside the band a printer cannot ink. */ + .fine{position:absolute;left:0;right:0;bottom:50px;text-align:center; font:400 13px Georgia,serif;color:#a89f8c} /* THE MAP IS MISSING, and this says so where the map would have been. ⚠ Centred in the SAME region the map occupies, not tucked into the fine print: a reader @@ -1347,10 +1352,11 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de // Mark 5:18-20 and the Father's-heart list share this ONE sheet, in every locale: the sizes below are the // largest that fit the longest locale. class="points-body" is a TEST HOOK: the page must fit ONE sheet in // every locale (its scrollHeight within its clientHeight). - // ★ 2026-10-02: the prayer themes now head the page at a size that reads on paper (19px, ~7.7pt), so the - // points give back a little: 20 → 18.5px text and 10 → 6px between points (the heading stays 22). Measured in - // all 11 locales: the tightest (fr) keeps 43px under the last point. - const PT = { head: 22, sub: 19, text: 18.5, refs: 16, gap: 6, passage: 17 }; + // ★ 2026-10-02: the prayer themes now head the page at a size that reads on paper (21px, ~8.6pt on letter) and + // the credit line sits 0.28in above the sheet's edge, so the points give back a little: 20 → 18px text, 10 → 5px + // between points, the Mark 5 passage 18 → 16px, and the body starts 14px higher (the heading stays 22). Measured + // in all 11 locales: the tightest (fr, hi) keep 46px under the last point; check:packet-render fails overflow. + const PT = { head: 22, sub: 19, text: 18, refs: 16, gap: 5, passage: 16 }; // ⚠ ISOLATE EACH REFERENCE FOR BIDI. Scripture references stay in English // (a reader looks them up in their own Bible), so on an RTL page they are // LTR runs inside an RTL paragraph. Without isolation the Unicode bidi @@ -1405,7 +1411,7 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de