Merge branch 'main' of https://git.nuxtbase.app/doxa-life/doxa-maps into bundler-1/work

This commit is contained in:
doxa-maps-88655c70 2026-09-24 04:02:02 +00:00
commit b5f831701e
8 changed files with 1052 additions and 99 deletions

View file

@ -53,6 +53,11 @@ await page.goto(pathToFileURL(file).href, { waitUntil: 'networkidle' })
// Resolve the rhythm words for THIS packet's language from the shared catalog.
// Per-key fallback to English, the same contract the renderer honours.
const lang = await page.evaluate(() => document.documentElement.lang || 'en')
// RTL languages must actually be laid out RTL. Without dir="rtl" an Arabic packet
// renders readable glyphs LEFT-aligned — it looks like a styling quirk rather than
// the bug it is, and no other assertion here would notice.
const RTL = new Set(['ar', 'he', 'fa', 'ur', 'ps', 'sd', 'yi'])
const dir = await page.evaluate(() => document.documentElement.dir || 'ltr')
// The catalog sits beside the generator that produced this packet, so derive it
// from the packet's own path rather than hardcoding a machine-specific location.
const catalogPath = process.env.PACKET_STRINGS
@ -140,6 +145,8 @@ if (r.rhythms !== r.rhythmsTotal) fails.push(`only ${r.rhythms}/${r.rhythmsTotal
if (!r.hasMark5) fails.push('Mark 5:1-20 is NOT printed in full (Driver requirement for point 4)')
if (r.metacamp !== 2) fails.push(`${r.metacamp} metacamp.org attributions, expected exactly 2`)
if (r.mapFaults.length) fails.push(`map: ${r.mapFaults.join('; ')}`)
if (RTL.has(lang) && dir !== 'rtl') fails.push(`lang="${lang}" is right-to-left but dir="${dir}"`)
if (!RTL.has(lang) && dir === 'rtl') fails.push(`lang="${lang}" is not RTL but dir="rtl"`)
if (translated === 0) {
fails.push(`lang="${lang}" but no string differs from English — `
+ 'the language block is missing, mis-keyed, or the renderer ignored it')
@ -155,7 +162,7 @@ console.log(` Mark 5 in full : ${r.hasMark5}`)
console.log(` metacamp.org : ${r.metacamp}`)
console.log(` map : ${r.mapFaults.length ? r.mapFaults.join('; ') : 'palette resolves, not black'}`)
console.log(` page size : ${boxes[0] ? boxes[0].join(' x ') : '?'} pt`)
console.log(` language : ${lang} (${r.rhythms}/${r.rhythmsTotal} rhythms in ${lang}`
console.log(` language : ${lang} (dir=${dir}) (${r.rhythms}/${r.rhythmsTotal} rhythms in ${lang}`
+ `${translated === null ? '' : `, ${translated} strings translated`})`)
if (fails.length) {

View file

@ -0,0 +1,95 @@
// check-print-geometry — the THREE print paths must each produce their OWN page
// geometry, from the UPG-100 page, in JavaScript.
//
// Driver: "make sure poster generation works and the aspect ratio of the print
// dialog can be custom based on your print point, so print dialog works for
// poster, for vertical packet, and for horizontal cards... not using python but
// all working in the jamstack maps."
//
// One gate over all three because the failure they share is the same: a print
// path silently falling back to letter. Chromium does that SILENTLY for any
// @page size it does not recognise ('A6 portrait' -> 612x792pt, no error), so
// every assertion here is on the MEASURED MediaBox, never on the stylesheet.
//
// Usage: node internal/check-print-geometry.mjs
// PACKET_ORIGIN (default http://127.0.0.1:4898) — a static server over the repo root
import { chromium } from 'playwright'
const ORIGIN = process.env.PACKET_ORIGIN || 'http://127.0.0.1:4898'
const API = process.env.PACKET_API || 'https://pray.doxa.life'
const ISO3 = process.env.PACKET_ISO3 || 'LAO'
// Each path, its expected page in POINTS (72pt = 1in), and its orientation.
const PATHS = [
{ id: 'packet (vertical)', w: 612, h: 792, orient: 'portrait' },
{ id: 'cards (poker)', w: 180, h: 252, orient: 'portrait', stock: 'poker' },
{ id: 'cards (landscape)', w: 252, h: 180, orient: 'landscape', stock: 'pokerLandscape' },
{ id: 'poster', w: null, h: null, orient: 'portrait' }, // raster, not paginated
]
const b = await chromium.launch()
const pg = await b.newPage({ viewport: { width: 1200, height: 900 } })
const errs = []; pg.on('pageerror', (e) => errs.push(String(e).slice(0, 120)))
await pg.goto(ORIGIN + '/')
const fails = []
const line = (id, got, want) => console.log(` ${id.padEnd(20)} ${got}${want ? ` (want ${want})` : ''}`)
// ── 1 + 2: the paginated paths, measured through page.pdf ────────────────────
for (const p of PATHS.filter((x) => x.w)) {
const html = await pg.evaluate(async ({ ORIGIN, API, ISO3, stock }) => {
const norm = await import(`${ORIGIN}/plugin-designs/my-upg-100-list/data/normalize.js`)
const strings = await fetch(`${ORIGIN}/library/scripts/posters/packet-strings.json`).then((r) => r.json())
const recs = norm.normalizeRecords(norm.extractRecords(await (await fetch(
`${API}/api/people-groups/list?fields=slug,name,country_code,population,religion,image_url,primary_language&lang=en`)).json()))
const groups = recs.filter((r) => String(r.country_code) === ISO3).slice(0, 6)
if (stock) {
const { createCardRenderer } = await import(`${ORIGIN}/library/packet/card-render.js`)
return createCardRenderer({ strings, lang: 'en', stock }).buildDeck({ id: 'x', label: 'X' }, groups)
}
const { createPacketRenderer } = await import(`${ORIGIN}/library/packet/packet-render.js`)
return createPacketRenderer({ strings, lang: 'en' }).buildPacket({ id: 'x', label: 'X' }, groups, new Map(), '')
}, { ORIGIN, API, ISO3, stock: p.stock })
await pg.setContent(html, { waitUntil: 'load' })
await pg.waitForTimeout(1200)
const pdf = await pg.pdf({ preferCSSPageSize: true })
const raw = pdf.toString('latin1')
const box = [...raw.matchAll(/MediaBox\s*\[\s*0\s+0\s+([\d.]+)\s+([\d.]+)\s*\]/g)].map((m) => [+m[1], +m[2]])[0] || [0, 0]
const [w, h] = box.map((v) => Math.round(v))
line(p.id, `${w} x ${h} pt`, `${p.w} x ${p.h}`)
if (Math.abs(w - p.w) > 2 || Math.abs(h - p.h) > 2) {
fails.push(`${p.id}: page is ${w}x${h}pt, expected ${p.w}x${p.h}pt`
+ (Math.abs(w - 612) < 2 && Math.abs(h - 792) < 2 && p.w !== 612
? ' — this is LETTER: the @page size silently fell back' : ''))
}
const landscape = w > h
if ((p.orient === 'landscape') !== landscape) {
fails.push(`${p.id}: orientation is ${landscape ? 'landscape' : 'portrait'}, expected ${p.orient}`)
}
}
// ── 3: the poster, which rasterises rather than paginating ───────────────────
const poster = await pg.evaluate(async ({ ORIGIN }) => {
const { rasterPoster, looksRendered } = await import(`${ORIGIN}/library/packet/poster-raster.js`)
const res = await fetch(`${ORIGIN}/library/scripts/posters/out/posters/laos.html`)
if (!res.ok) return { error: `poster HTML ${res.status}` }
const blob = await rasterPoster(await res.text(), { scale: 1 })
const bmp = await createImageBitmap(blob)
return { w: bmp.width, h: bmp.height, ok: await looksRendered(blob), bytes: blob.size }
}, { ORIGIN })
if (poster.error) fails.push(`poster: ${poster.error}`)
else {
line('poster', `${poster.w} x ${poster.h} px`, 'portrait, painted')
if (poster.w >= poster.h) fails.push(`poster rasterised ${poster.w}x${poster.h} — expected portrait`)
if (!poster.ok) fails.push('poster rasterised blank/black')
}
await b.close()
if (errs.length) fails.push(`${errs.length} page error(s): ${errs[0]}`)
if (fails.length) {
console.error(`\nPRINT-GEOMETRY: FAIL — ${fails.length} problem(s)`)
for (const f of fails) console.error(' - ' + f)
process.exit(1)
}
console.log('\nPRINT-GEOMETRY: PASS — every print path produces its own page geometry.')

View file

@ -37,10 +37,17 @@ import { qrSvg } from './qr.js';
// sleeves and boxes are built around, and the one people already associate with a
// deck you hold and deal out. Bleed is included in the page so a trimmed card
// keeps its full-bleed portrait.
// ★ LANDSCAPE IS NOT JUST TRANSPOSED DIMENSIONS. The portrait card stacks the
// photo ABOVE the text (portrait occupies the top 46%); at 3.5 x 2.5in that same
// band is a strip too short to carry a face or leave room for the rows beneath it.
// A landscape card puts the photo BESIDE the text instead — so `side: true` is a
// LAYOUT switch the CSS reads, not a cosmetic flag.
export const STOCK = {
poker: { w: 2.5, h: 3.5, label: 'Poker (2.5 x 3.5 in)' },
postcard: { w: 4, h: 6, label: 'Postcard (4 x 6 in)' },
a6: { w: 4.13, h: 5.83, label: 'A6 (105 x 148 mm)' }, // explicit in, NOT "A6"
poker: { w: 2.5, h: 3.5, label: 'Card 2.5 × 3.5 in' },
pokerLandscape: { w: 3.5, h: 2.5, label: 'Card 3.5 × 2.5 in (landscape)', side: true },
postcard: { w: 4, h: 6, label: 'Postcard 4 × 6 in' },
postcardLandscape: { w: 6, h: 4, label: 'Postcard 6 × 4 in (landscape)', side: true },
a6: { w: 4.13, h: 5.83, label: 'A6 105 × 148 mm' }, // explicit in, NOT "A6"
};
const PX = 96; // CSS px per inch
@ -73,6 +80,10 @@ export function createCardRenderer({ strings, lang = 'en', stock = 'poker',
const S = STOCK[stock] || STOCK.poker;
const W = Math.round(S.w * PX); // card box in CSS px
const H = Math.round(S.h * PX);
// Photo BESIDE the text rather than above it. Driven by the stock, not by
// comparing W to H: a square stock would be ambiguous, and the choice is a
// deliberate property of the format rather than an inference from its numbers.
const SIDE = S.side === true;
// The live profile URL for this group, in this language. English has no prefix
// (the generator's own rule); every other language does.
@ -93,26 +104,36 @@ export function createCardRenderer({ strings, lang = 'en', stock = 'poker',
page-break-after:always;break-after:page}
.card:last-child{page-break-after:auto;break-after:auto}
/* PORTRAIT: full-bleed across the top. A face is what makes this a prayer card
rather than a data tile — it is the largest thing on the card by design. */
.ph{position:absolute;left:0;top:0;width:${W}px;height:${Math.round(H * 0.46)}px;
object-fit:cover;display:block;background:#ddd6c6}
.ph-none{position:absolute;left:0;top:0;width:${W}px;height:${Math.round(H * 0.46)}px;
background:linear-gradient(160deg,#e6dfcd,#cfc6ad);display:flex;
align-items:center;justify-content:center;
/* THE PHOTO. Portrait: full-bleed across the TOP, the largest thing on the card
by design — a face is what makes this a prayer card rather than a data tile.
Landscape: full-bleed down the LEFT instead, because a 46% band on a 2.5in-tall
card is a strip too short to carry a face AND leave room for the rows. */
.ph,.ph-none{position:absolute;left:0;top:0;display:block;
width:${SIDE ? Math.round(W * 0.42) : W}px;
height:${SIDE ? H : Math.round(H * 0.46)}px}
.ph{object-fit:cover;background:#ddd6c6}
.ph-none{background:linear-gradient(160deg,#e6dfcd,#cfc6ad);display:flex;
align-items:center;justify-content:center;text-align:center;padding:6px;
font:italic 11px Georgia,serif;color:#8c8170}
/* A soft scrim under the name so it stays legible over any photo. */
.scrim{position:absolute;left:0;top:${Math.round(H * 0.30)}px;width:${W}px;
height:${Math.round(H * 0.16)}px;
.scrim{position:absolute;left:0;
width:${SIDE ? Math.round(W * 0.42) : W}px;
top:${SIDE ? Math.round(H * 0.58) : Math.round(H * 0.30)}px;
height:${SIDE ? Math.round(H * 0.42) : Math.round(H * 0.16)}px;
background:linear-gradient(to bottom,rgba(24,22,18,0),rgba(24,22,18,.72))}
.nm{position:absolute;left:14px;right:14px;top:${Math.round(H * 0.355)}px;
font:700 19px Georgia,serif;color:#fff;line-height:1.05;
.nm{position:absolute;
left:${SIDE ? 10 : 14}px;
${SIDE ? `width:${Math.round(W * 0.42) - 20}px;` : `right:14px;`}
top:${SIDE ? Math.round(H * 0.74) : Math.round(H * 0.355)}px;
font:700 ${SIDE ? 15 : 19}px Georgia,serif;color:#fff;line-height:1.05;
text-shadow:0 1px 3px rgba(0,0,0,.5)}
.nm.long{font-size:15px}
.nm.long{font-size:${SIDE ? 12 : 15}px}
.body{position:absolute;left:14px;right:14px;top:${Math.round(H * 0.48)}px;
bottom:${Math.round(H * 0.20)}px;overflow:hidden}
.body{position:absolute;right:14px;overflow:hidden;
left:${SIDE ? Math.round(W * 0.42) + 12 : 14}px;
top:${SIDE ? 12 : Math.round(H * 0.48)}px;
bottom:${SIDE ? Math.round(H * 0.30) : Math.round(H * 0.20)}px}
.row{display:flex;gap:6px;font:400 9.5px Georgia,serif;line-height:1.5;margin-bottom:1px}
.k{color:#8c8170;min-width:52px;flex:0 0 auto}
.v{color:#3b3a34;font-weight:600}
@ -120,7 +141,8 @@ export function createCardRenderer({ strings, lang = 'en', stock = 'poker',
/* FOOTER: the QR is the card's whole reason to survive the day it is handed
over — it carries the reader to the live profile in their own language. */
.ft{position:absolute;left:14px;right:14px;bottom:10px;
.ft{position:absolute;right:14px;bottom:10px;
left:${SIDE ? Math.round(W * 0.42) + 12 : 14}px;
display:flex;align-items:flex-end;gap:8px}
.qr{flex:0 0 auto;line-height:0}
.ftx{flex:1 1 auto;min-width:0}

View file

@ -21,6 +21,11 @@
// is a NEW BLOCK there, never a code change, and fallback is PER KEY so a
// half-finished translation renders its finished keys instead of blanking.
// Right-to-left locales. Kept as data rather than a per-language flag in the
// catalog: script direction is a property of the LANGUAGE, not of a translation,
// so a new Arabic-script locale is one entry here and not a schema change.
const RTL = new Set(['ar', 'he', 'fa', 'ur', 'ps', 'sd', 'yi']);
export function createPacketRenderer({ strings, lang = 'en' }) {
const EN = strings.en;
const L = strings[lang] || {};
@ -185,7 +190,15 @@ export function createPacketRenderer({ strings, lang = 'en' }) {
// ── PAGE n+1: the 12 prayer points ──────────────────────────────────────────
function pointsPage() {
const rows = POINTS.map((p) => {
const refs = (p.refs || []).map((r) => esc(r)).join(' · ');
// ⚠ 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
// algorithm reorders a run that STARTS WITH A DIGIT: measured on the Arabic
// page, "1 Peter 5:6–11" rendered as "Peter 5:6-11 1". dir="ltr" on each
// reference pins its internal order without affecting the line's direction.
const refs = (p.refs || [])
.map((r) => `<span dir="ltr" style="unicode-bidi:isolate">${esc(r)}</span>`)
.join(' · ');
const sub = p.sub ? ` <span style="font:italic 17px Georgia,serif;color:#8c8170">— ${esc(p.sub)}</span>` : '';
const passage = p.print_passage
// Point 4 prints Mark 5:1-20 IN FULL. Driver: "it actually lists out the full
@ -267,7 +280,12 @@ export function createPacketRenderer({ strings, lang = 'en' }) {
pointsPage(),
wheelPage(),
];
return `<!DOCTYPE html><html lang="${esc(lang)}"><head><meta charset="utf-8">
// ⚠ 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
// styling quirk rather than the bug it is. Verified in a browser: with
// dir="rtl" the text right-aligns, shapes correctly, and a Latin scripture
// reference stays LTR inside the RTL line (correct bidi) with no extra work.
return `<!DOCTYPE html><html lang="${esc(lang)}" dir="${RTL.has(lang) ? 'rtl' : 'ltr'}"><head><meta charset="utf-8">
<title>${esc(zone.label || zone.id)}</title><style>${css()}</style></head>
<body>${pages.join('\n')}</body></html>`;
}

View file

@ -3,7 +3,9 @@
"purpose": "EVERY human-readable string in the UPG-100 prayer packet, in one file, so a new language is a new block here and NOT a code change. packet.mjs reads LANG (default 'en') and falls back to 'en' key-by-key, so a partial translation renders the translated keys and leaves the rest in English rather than blanking.",
"how_to_translate": "Copy the \"en\" block, change the key to the ISO code, translate the values. Keep {placeholders} exactly as they are — they are substituted at render time. Do not translate scripture REFERENCES (book names are resolved by the reader's own Bible); DO translate the prayer text.",
"note_on_scripture": "point4_passage is the ONLY full scripture text in the packet (Mark 5:1-20, printed in full at the Driver's instruction). A translation MUST supply its own rendering in a public-domain or properly-licensed version FOR THAT LANGUAGE. ⚠ Do NOT translate it yourself and do NOT leave a machine rendering in place: this is printed scripture in a prayer packet. A language block that omits point4_passage falls back to the English WEB text per-key, which is honest — an untrusted translation of Mark 5 is not.",
"note_on_references": "Scripture REFERENCES (Matthew 27:27, Mark 5:1-20) are deliberately left in English in every language block, so a reader can look them up in their own Bible regardless of the packet's language. ⚠ MEASURED TRADEOFF, not an oversight: on a rendered French page the English book names are visibly foreign next to fully-translated prayer text. If a language wants localised book names, add a `books` map to that block and teach the renderer to use it — do NOT translate the refs inline, because the same strings identify the passage for any future lookup."
"note_on_references": "Scripture REFERENCES (Matthew 27:27, Mark 5:1-20) are deliberately left in English in every language block, so a reader can look them up in their own Bible regardless of the packet's language. ⚠ MEASURED TRADEOFF, not an oversight: on a rendered French page the English book names are visibly foreign next to fully-translated prayer text. If a language wants localised book names, add a `books` map to that block and teach the renderer to use it — do NOT translate the refs inline, because the same strings identify the passage for any future lookup.",
"note_on_scripts": "MEASURED 2026-09-24 by rendering each script at 48px and READING THE PIXELS: Latin, Cyrillic (ru), Arabic (ar) and CJK (zh) all shape correctly in the packet's Georgia/serif stack. DEVANAGARI (hi) renders as TOFU BOXES — this box has zero Devanagari fonts installed (fc-list). So hi is BLOCKED on vendoring a Devanagari font (e.g. Noto Serif Devanagari) into public/assets/fonts and adding it to the packet's font stack; adding a hi block before then would ship a page of empty rectangles. ⚠ A WIDTH HEURISTIC GOT THIS BACKWARDS: comparing rendered advance against a missing-font baseline reported ar and zh as broken and hi as fine — the exact opposite of the truth, because Devanagari tofu boxes happen to match real glyph advance. Read the pixels.",
"note_on_rtl": "ar is right-to-left. The renderer emits dir on <html> from an RTL set (packet-render.js), and scripture REFERENCES are wrapped in dir=ltr + unicode-bidi:isolate. Without that isolation the bidi algorithm reorders a reference that STARTS WITH A DIGIT: '1 Peter 5:6-11' rendered as 'Peter 5:6-11 1'. Note the reference LIST then reads right-to-left on an RTL page (first item rightmost) — that is correct for an RTL reader, not a defect."
},
"en": {
"map_page_kicker": "UNENGAGED PEOPLE GROUPS",
@ -638,5 +640,795 @@
]
}
]
},
"de": {
"map_page_kicker": "UNERREICHTE VOLKSGRUPPEN",
"map_page_sub": "Eine Gebetsliste von {count} unerreichten Volksgruppen",
"list_header": "{from}–{to} von {count} · betet namentlich für sie",
"people_suffix": "Menschen",
"no_photo": "kein Foto verfügbar",
"deck_title": "Gebetskarten",
"card_country": "Land",
"card_population": "Menschen",
"card_language": "Sprache",
"card_religion": "Religion",
"card_cta": "Betet für sie",
"points_title": "12 Gebetsanliegen",
"points_intro": "Eine Stunde mit Gott, je fünf Minuten. Betet diese zwölf Anliegen für die Volksgruppen in diesem Heft.",
"points_attrib": "Gebetsrhythmen inspiriert von Metacamp · metacamp.org",
"wheel_title": "Gebetsrad",
"wheel_intro": "Eine Stunde mit Gott verbringen? Es ist leichter, als du denkst. Teile sie in 5-Minuten-Blöcke und konzentriere dich in jedem Abschnitt auf eines dieser Anliegen.",
"wheel_minutes": "Minuten",
"wheel_attrib": "Gebetsrad · Metacamp Modul 1 · metacamp.org",
"privacy_note": "Die Markerpositionen sind ungefähr · die Standorte der Volksgruppen werden an der Quelle aus Datenschutzgründen verallgemeinert",
"rhythms": {
"praise": "LOBPREIS",
"wait": "WARTEN",
"confess": "BEKENNEN",
"read": "DAS WORT LESEN",
"ask": "BITTEN",
"intercede": "FÜRBITTE",
"pray_word": "DAS WORT BETEN",
"thank": "DANKEN",
"sing": "SINGEN",
"meditate": "MEDITIEREN",
"listen": "HÖREN",
"praise_end": "LOBPREIS"
},
"points": [
{
"n": 1,
"rhythm": "praise",
"sub": "Evangelium der zwei Kreuze",
"text": "Dass sie Christus als König annehmen, vergeben durch Sein Kreuz — und ihr eigenes Kreuz auf sich nehmen, bereit, in einem Verfolgungsgebiet zu leiden. Möge das Lamm den Lohn Seines Leidens empfangen, angefangen bei mir.",
"refs": [
"Matthew 27:27",
"Matthew 16:24–25"
]
},
{
"n": 2,
"rhythm": "wait",
"sub": "Heiliger Geist und Befreiung",
"text": "Dass sie mit dem Geist erfüllt und zu mutigen Zeugen werden; dass sie nicht isoliert sind; getauft in Wasser und Geist; dass jeder Griff des Bösen gebrochen wird. Dass Gläubige in Nachbarvölkern als Arbeiter mobilisiert werden.",
"refs": [
"Acts 1:8",
"John 14:26"
]
},
{
"n": 3,
"rhythm": "confess",
"sub": "",
"text": "Wir bekennen den Unglauben, dass dies für Gott zu groß sei. Dass Er unsere Liebe und unseren Glauben für die weltweit Unerreichten neu belebt.",
"refs": [
"John 3:16",
"1 John 1:9"
]
},
{
"n": 4,
"rhythm": "read",
"sub": "die Liebe des Vaters",
"text": "Dass sie GERETTET werden und WISSEN, dass ihr himmlischer Vater sie liebt — und dass Er durch sie Rettung zu ihrer Familie, ihren Freunden, Nachbarn, Kollegen, Mitschülern bringt, zu allen, die sie persönlich kennen.",
"refs": [
"Mark 5:1–20",
"Acts 16:31"
],
"print_passage": true
},
{
"n": 5,
"rhythm": "ask",
"sub": "Taufen",
"text": "Neue Taufen unter den Einheimischen, und dass jeder Getaufte zugerüstet wird, andere zu taufen, sich vermehrend.",
"refs": [
"Acts 16",
"Acts 10"
]
},
{
"n": 6,
"rhythm": "intercede",
"sub": "Arbeiter und Hirten",
"text": "Arbeiter, gesandt, ein Volk zutiefst zu lieben, das sie nie getroffen haben; gute Hirten, von innen heraus erweckt.",
"refs": [
"Luke 10:2",
"John 10:11–15"
]
},
{
"n": 7,
"rhythm": "pray_word",
"sub": "Menschen und Häuser des Friedens",
"text": "Dass Arbeiter und lokale Leiter den empfänglichen Menschen und das Haus des Friedens finden und sie gut zu Jüngern machen.",
"refs": [
"Luke 10:5–7",
"Matthew 10:5–14"
]
},
{
"n": 8,
"rhythm": "thank",
"sub": "Ruhe",
"text": "Dank sei Gott für die Ruhe, die Er gegeben hat; dass sie in diese Ruhe in Christus eintreten und dass ihre geistliche Familie ein sicherer Ort ist.",
"refs": [
"Mark 4:26–29",
"Hebrews 4:9–11"
]
},
{
"n": 9,
"rhythm": "sing",
"sub": "",
"text": "Dass die Volksgruppe von Anbetern überflutet wird — Anbetung überall, in Freiheit und in Ketten.",
"refs": [
"Acts 16:25–26",
"Colossians 3:16"
]
},
{
"n": 10,
"rhythm": "meditate",
"sub": "Abendmahl",
"text": "Dass sie gemeinsam das Abendmahl nehmen und das Gewicht Seines Todes, Seiner Grablegung und Auferstehung erfassen.",
"refs": [
"Matthew 26:26–30",
"1 Corinthians 11:23–26"
]
},
{
"n": 11,
"rhythm": "listen",
"sub": "Rechenschaft",
"text": "Nicht nur, dass sie hören, sondern dass sie Menschen in ihrem Leben haben, die ihnen helfen, das Wort zu lesen, zu beten, sich der Gemeinschaft zu verpflichten und gut auf Leiden zu reagieren — dem Widersacher widerstehend, der Gläubige auf der ganzen Welt verfolgt.",
"refs": [
"1 Peter 5:6–11",
"Hebrews 10:24–25"
]
},
{
"n": 12,
"rhythm": "praise_end",
"sub": "groß · größer · am größten",
"text": "Lobpreis im Voraus — für Errettungen; GRÖSSER, für sich vermehrende geistliche Familien; AM GRÖSSTEN, für hingegebene Leben und erweckte einheimische Gemeindegründer, die gesunde Gemeinden in der ganzen Volksgruppe vermehren, koste es, was es wolle.",
"refs": [
"Acts 2:42–47",
"Matthew 28:19–20"
]
}
]
},
"it": {
"map_page_kicker": "GRUPPI ETNICI NON RAGGIUNTI",
"map_page_sub": "Una lista di preghiera di {count} gruppi etnici non raggiunti",
"list_header": "{from}–{to} di {count} · pregate per loro per nome",
"people_suffix": "persone",
"no_photo": "nessuna foto disponibile",
"deck_title": "Carte di Preghiera",
"card_country": "Paese",
"card_population": "Persone",
"card_language": "Lingua",
"card_religion": "Religione",
"card_cta": "Prega per loro",
"points_title": "12 Punti di Preghiera",
"points_intro": "Un'ora con Dio, cinque minuti ciascuno. Pregate questi dodici punti per i gruppi etnici di questo fascicolo.",
"points_attrib": "Ritmi di preghiera ispirati a Metacamp · metacamp.org",
"wheel_title": "Ruota di Preghiera",
"wheel_intro": "Passare un'ora con Dio? È più facile di quanto pensi. Dividila in blocchi di 5 minuti e concentrati su uno di questi in ogni segmento.",
"wheel_minutes": "minuti",
"wheel_attrib": "Ruota di Preghiera · Metacamp Modulo 1 · metacamp.org",
"privacy_note": "Le posizioni dei segnaposto sono approssimative · le localizzazioni dei gruppi etnici sono generalizzate alla fonte per riservatezza",
"rhythms": {
"praise": "LODE",
"wait": "ATTENDERE",
"confess": "CONFESSARE",
"read": "LEGGERE LA PAROLA",
"ask": "CHIEDERE",
"intercede": "INTERCESSIONE",
"pray_word": "PREGARE LA PAROLA",
"thank": "RINGRAZIARE",
"sing": "CANTARE",
"meditate": "MEDITARE",
"listen": "ASCOLTARE",
"praise_end": "LODE"
},
"points": [
{
"n": 1,
"rhythm": "praise",
"sub": "Vangelo delle due croci",
"text": "Che accolgano Cristo come Re, perdonati dalla Sua croce — e prendano la propria croce, disposti a soffrire in una zona di persecuzione. Che l'Agnello riceva la ricompensa della Sua sofferenza, a cominciare da me.",
"refs": [
"Matthew 27:27",
"Matthew 16:24–25"
]
},
{
"n": 2,
"rhythm": "wait",
"sub": "Spirito Santo e liberazione",
"text": "Che siano ripieni dello Spirito e resi testimoni coraggiosi; che non siano isolati; battezzati in acqua e Spirito; che ogni presa del male sia spezzata. Che i credenti dei popoli vicini siano mobilitati come operai.",
"refs": [
"Acts 1:8",
"John 14:26"
]
},
{
"n": 3,
"rhythm": "confess",
"sub": "",
"text": "Confessiamo l'incredulità di ritenere questo troppo grande per Dio. Che Egli ravvivi il nostro amore e la nostra fede per i non raggiunti del mondo.",
"refs": [
"John 3:16",
"1 John 1:9"
]
},
{
"n": 4,
"rhythm": "read",
"sub": "l'amore del Padre",
"text": "Che siano SALVATI e SAPPIANO che il loro Padre celeste li ama — e che attraverso di loro Egli porti salvezza alla loro famiglia, agli amici, ai vicini, ai colleghi, ai compagni di classe, a tutti coloro che conoscono personalmente.",
"refs": [
"Mark 5:1–20",
"Acts 16:31"
],
"print_passage": true
},
{
"n": 5,
"rhythm": "ask",
"sub": "battesimi",
"text": "Nuovi battesimi tra la gente del luogo, e che ogni battezzato sia formato per battezzarne altri, moltiplicandosi.",
"refs": [
"Acts 16",
"Acts 10"
]
},
{
"n": 6,
"rhythm": "intercede",
"sub": "operai e pastori",
"text": "Operai mandati ad amare profondamente un popolo che non hanno mai incontrato; buoni pastori suscitati dall'interno.",
"refs": [
"Luke 10:2",
"John 10:11–15"
]
},
{
"n": 7,
"rhythm": "pray_word",
"sub": "Persone e Case di Pace",
"text": "Che gli operai e i responsabili locali trovino la persona ricettiva e la casa di pace, e li discepolino bene.",
"refs": [
"Luke 10:5–7",
"Matthew 10:5–14"
]
},
{
"n": 8,
"rhythm": "thank",
"sub": "riposo",
"text": "Grazie a Dio per il riposo che ha dato; che entrino in quel riposo in Cristo, e che la loro famiglia spirituale sia un luogo sicuro.",
"refs": [
"Mark 4:26–29",
"Hebrews 4:9–11"
]
},
{
"n": 9,
"rhythm": "sing",
"sub": "",
"text": "Che il gruppo etnico sia inondato di adoratori — adorazione ovunque, nella libertà e nelle catene.",
"refs": [
"Acts 16:25–26",
"Colossians 3:16"
]
},
{
"n": 10,
"rhythm": "meditate",
"sub": "comunione",
"text": "Che prendano la comunione insieme e colgano il peso della Sua morte, sepoltura e risurrezione.",
"refs": [
"Matthew 26:26–30",
"1 Corinthians 11:23–26"
]
},
{
"n": 11,
"rhythm": "listen",
"sub": "responsabilità reciproca",
"text": "Non solo che ascoltino, ma che abbiano nella loro vita persone che li aiutino a leggere la Parola, a pregare, a impegnarsi nella comunità e a rispondere bene alla sofferenza — resistendo all'avversario che perseguita i credenti in tutto il mondo.",
"refs": [
"1 Peter 5:6–11",
"Hebrews 10:24–25"
]
},
{
"n": 12,
"rhythm": "praise_end",
"sub": "grande · più grande · il più grande",
"text": "Lode in anticipo — per le salvezze; PIÙ GRANDE, per le famiglie spirituali che si moltiplicano; IL PIÙ GRANDE, per vite donate e piantatori di chiese locali suscitati che moltiplicano chiese sane in tutto il gruppo etnico, a qualunque costo.",
"refs": [
"Acts 2:42–47",
"Matthew 28:19–20"
]
}
]
},
"ro": {
"map_page_kicker": "GRUPURI ETNICE NEATINSE",
"map_page_sub": "O listă de rugăciune pentru {count} grupuri etnice neatinse",
"list_header": "{from}–{to} din {count} · rugați-vă pentru ei pe nume",
"people_suffix": "persoane",
"no_photo": "nicio fotografie disponibilă",
"deck_title": "Cartonașe de Rugăciune",
"card_country": "Țară",
"card_population": "Persoane",
"card_language": "Limbă",
"card_religion": "Religie",
"card_cta": "Roagă-te pentru ei",
"points_title": "12 Puncte de Rugăciune",
"points_intro": "O oră cu Dumnezeu, câte cinci minute fiecare. Rugați-vă aceste douăsprezece puncte pentru grupurile etnice din acest pachet.",
"points_attrib": "Ritmuri de rugăciune inspirate de Metacamp · metacamp.org",
"wheel_title": "Roata Rugăciunii",
"wheel_intro": "O oră cu Dumnezeu? Este mai ușor decât crezi. Împarte-o în blocuri de 5 minute și concentrează-te pe unul dintre acestea în fiecare segment.",
"wheel_minutes": "minute",
"wheel_attrib": "Roata Rugăciunii · Metacamp Modulul 1 · metacamp.org",
"privacy_note": "Pozițiile marcajelor sunt aproximative · localizările grupurilor etnice sunt generalizate la sursă din motive de confidențialitate",
"rhythms": {
"praise": "LAUDĂ",
"wait": "AȘTEPTARE",
"confess": "MĂRTURISIRE",
"read": "CITIREA CUVÂNTULUI",
"ask": "CERERE",
"intercede": "MIJLOCIRE",
"pray_word": "RUGAREA CUVÂNTULUI",
"thank": "MULȚUMIRE",
"sing": "CÂNTARE",
"meditate": "MEDITAȚIE",
"listen": "ASCULTARE",
"praise_end": "LAUDĂ"
},
"points": [
{
"n": 1,
"rhythm": "praise",
"sub": "Evanghelia celor două cruci",
"text": "Să Îl primească pe Hristos ca Împărat, iertați prin crucea Lui — și să își ia propria cruce, gata să sufere într-o zonă de persecuție. Fie ca Mielul să primească răsplata suferinței Sale, începând cu mine.",
"refs": [
"Matthew 27:27",
"Matthew 16:24–25"
]
},
{
"n": 2,
"rhythm": "wait",
"sub": "Duhul Sfânt și eliberarea",
"text": "Să fie umpluți de Duhul și făcuți martori îndrăzneți; să nu fie izolați; botezați în apă și în Duh; orice stăpânire a răului să fie zdrobită. Credincioșii din popoarele vecine să fie mobilizați ca lucrători.",
"refs": [
"Acts 1:8",
"John 14:26"
]
},
{
"n": 3,
"rhythm": "confess",
"sub": "",
"text": "Mărturisim necredința că aceasta ar fi prea mare pentru Dumnezeu. Fie ca El să ne reînvie dragostea și credința pentru cei neatinși din toată lumea.",
"refs": [
"John 3:16",
"1 John 1:9"
]
},
{
"n": 4,
"rhythm": "read",
"sub": "dragostea Tatălui",
"text": "Să fie MÂNTUIȚI și să ȘTIE că Tatăl lor ceresc îi iubește — și ca prin ei El să aducă mântuire familiei lor, prietenilor, vecinilor, colegilor de muncă, colegilor de clasă, tuturor celor pe care îi cunosc personal.",
"refs": [
"Mark 5:1–20",
"Acts 16:31"
],
"print_passage": true
},
{
"n": 5,
"rhythm": "ask",
"sub": "botezuri",
"text": "Botezuri noi printre localnici, și fiecare botezat să fie instruit să boteze pe alții, multiplicându-se.",
"refs": [
"Acts 16",
"Acts 10"
]
},
{
"n": 6,
"rhythm": "intercede",
"sub": "lucrători și păstori",
"text": "Lucrători trimiși să iubească profund un popor pe care nu l-au întâlnit niciodată; păstori buni ridicați din interior.",
"refs": [
"Luke 10:2",
"John 10:11–15"
]
},
{
"n": 7,
"rhythm": "pray_word",
"sub": "Oameni și Case ale Păcii",
"text": "Lucrătorii și liderii locali să găsească persoana receptivă și casa păcii și să îi facă ucenici cu grijă.",
"refs": [
"Luke 10:5–7",
"Matthew 10:5–14"
]
},
{
"n": 8,
"rhythm": "thank",
"sub": "odihnă",
"text": "Mulțumim lui Dumnezeu pentru odihna pe care a dat-o; să intre în acea odihnă în Hristos, iar familia lor spirituală să fie un loc sigur.",
"refs": [
"Mark 4:26–29",
"Hebrews 4:9–11"
]
},
{
"n": 9,
"rhythm": "sing",
"sub": "",
"text": "Grupul etnic să fie inundat de închinători — închinare pretutindeni, în libertate și în lanțuri.",
"refs": [
"Acts 16:25–26",
"Colossians 3:16"
]
},
{
"n": 10,
"rhythm": "meditate",
"sub": "împărtășanie",
"text": "Să ia împărtășania împreună și să înțeleagă greutatea morții, îngropării și învierii Lui.",
"refs": [
"Matthew 26:26–30",
"1 Corinthians 11:23–26"
]
},
{
"n": 11,
"rhythm": "listen",
"sub": "responsabilitate",
"text": "Nu doar să asculte, ci să aibă în viața lor oameni care îi ajută să citească Cuvântul, să se roage, să se dedice comunității și să răspundă bine suferinței — rezistând vrăjmașului care urmărește credincioșii din toată lumea.",
"refs": [
"1 Peter 5:6–11",
"Hebrews 10:24–25"
]
},
{
"n": 12,
"rhythm": "praise_end",
"sub": "mare · mai mare · cel mai mare",
"text": "Laudă dinainte — pentru mântuiri; MAI MARE, pentru familii spirituale care se multiplică; CEL MAI MARE, pentru vieți predate și plantatori locali de biserici ridicați, care multiplică biserici sănătoase în tot grupul etnic, oricare ar fi prețul.",
"refs": [
"Acts 2:42–47",
"Matthew 28:19–20"
]
}
]
},
"ru": {
"map_page_kicker": "НЕОХВАЧЕННЫЕ НАРОДЫ",
"map_page_sub": "Молитвенный список из {count} неохваченных народов",
"list_header": "{from}–{to} из {count} · молитесь за них поимённо",
"people_suffix": "человек",
"no_photo": "фотография недоступна",
"deck_title": "Молитвенные карточки",
"card_country": "Страна",
"card_population": "Человек",
"card_language": "Язык",
"card_religion": "Религия",
"card_cta": "Молитесь за них",
"points_title": "12 молитвенных пунктов",
"points_intro": "Один час с Богом, по пять минут на каждый. Молитесь об этих двенадцати пунктах за народы из этого сборника.",
"points_attrib": "Молитвенные ритмы вдохновлены Metacamp · metacamp.org",
"wheel_title": "Молитвенное колесо",
"wheel_intro": "Провести час с Богом? Это проще, чем кажется. Разделите его на пятиминутные отрезки и в каждом сосредоточьтесь на одном из пунктов.",
"wheel_minutes": "минут",
"wheel_attrib": "Молитвенное колесо · Metacamp Модуль 1 · metacamp.org",
"privacy_note": "Положение меток приблизительное · расположение народов обобщено в источнике в целях конфиденциальности",
"rhythms": {
"praise": "ХВАЛА",
"wait": "ОЖИДАНИЕ",
"confess": "ИСПОВЕДАНИЕ",
"read": "ЧТЕНИЕ СЛОВА",
"ask": "ПРОШЕНИЕ",
"intercede": "ХОДАТАЙСТВО",
"pray_word": "МОЛИТВА СЛОВОМ",
"thank": "БЛАГОДАРЕНИЕ",
"sing": "ПЕНИЕ",
"meditate": "РАЗМЫШЛЕНИЕ",
"listen": "СЛУШАНИЕ",
"praise_end": "ХВАЛА"
},
"points": [
{
"n": 1,
"rhythm": "praise",
"sub": "Евангелие двух крестов",
"text": "Чтобы они приняли Христа как Царя, прощённые Его крестом — и взяли свой собственный крест, готовые страдать в зоне гонений. Да получит Агнец награду за Свои страдания, начиная с меня.",
"refs": [
"Matthew 27:27",
"Matthew 16:24–25"
]
},
{
"n": 2,
"rhythm": "wait",
"sub": "Святой Дух и освобождение",
"text": "Чтобы они исполнились Духом и стали смелыми свидетелями; чтобы не были одиноки; крещены водою и Духом; чтобы всякая власть зла была сокрушена. Чтобы верующие из соседних народов были подняты как работники.",
"refs": [
"Acts 1:8",
"John 14:26"
]
},
{
"n": 3,
"rhythm": "confess",
"sub": "",
"text": "Мы исповедуем неверие, будто это слишком велико для Бога. Да оживит Он нашу любовь и веру ради неохваченных по всему миру.",
"refs": [
"John 3:16",
"1 John 1:9"
]
},
{
"n": 4,
"rhythm": "read",
"sub": "любовь Отца",
"text": "Чтобы они были СПАСЕНЫ и ЗНАЛИ, что их Небесный Отец любит их — и чтобы через них Он принёс спасение их семье, друзьям, соседям, сослуживцам, одноклассникам, всем, кого они знают лично.",
"refs": [
"Mark 5:1–20",
"Acts 16:31"
],
"print_passage": true
},
{
"n": 5,
"rhythm": "ask",
"sub": "крещения",
"text": "Новые крещения среди местных, и чтобы каждый крещёный был научен крестить других, умножаясь.",
"refs": [
"Acts 16",
"Acts 10"
]
},
{
"n": 6,
"rhythm": "intercede",
"sub": "работники и пастыри",
"text": "Работники, посланные глубоко полюбить народ, которого они никогда не встречали; добрые пастыри, поднятые изнутри.",
"refs": [
"Luke 10:2",
"John 10:11–15"
]
},
{
"n": 7,
"rhythm": "pray_word",
"sub": "Люди и Дома мира",
"text": "Чтобы работники и местные руководители нашли человека мира и дом мира и хорошо наставили их.",
"refs": [
"Luke 10:5–7",
"Matthew 10:5–14"
]
},
{
"n": 8,
"rhythm": "thank",
"sub": "покой",
"text": "Благодарим Бога за покой, который Он дал; чтобы они вошли в этот покой во Христе и чтобы их духовная семья была безопасным местом.",
"refs": [
"Mark 4:26–29",
"Hebrews 4:9–11"
]
},
{
"n": 9,
"rhythm": "sing",
"sub": "",
"text": "Чтобы народ наполнился поклонниками — поклонение повсюду, в свободе и в цепях.",
"refs": [
"Acts 16:25–26",
"Colossians 3:16"
]
},
{
"n": 10,
"rhythm": "meditate",
"sub": "причастие",
"text": "Чтобы они вместе принимали причастие и постигали вес Его смерти, погребения и воскресения.",
"refs": [
"Matthew 26:26–30",
"1 Corinthians 11:23–26"
]
},
{
"n": 11,
"rhythm": "listen",
"sub": "подотчётность",
"text": "Не только чтобы они слушали, но чтобы рядом были люди, помогающие им читать Слово, молиться, быть верными общине и достойно отвечать на страдания — противостоя врагу, преследующему верующих по всему миру.",
"refs": [
"1 Peter 5:6–11",
"Hebrews 10:24–25"
]
},
{
"n": 12,
"rhythm": "praise_end",
"sub": "великое · большее · наибольшее",
"text": "Хвала наперёд — за спасения; БОЛЬШЕЕ — за умножающиеся духовные семьи; НАИБОЛЬШЕЕ — за отданные жизни и поднятых местных основателей церквей, умножающих здоровые церкви по всему народу, чего бы это ни стоило.",
"refs": [
"Acts 2:42–47",
"Matthew 28:19–20"
]
}
]
},
"ar": {
"map_page_kicker": "شعوب غير مبلَّغة",
"map_page_sub": "قائمة صلاة من أجل {count} شعبًا غير مبلَّغ",
"list_header": "{from}–{to} من {count} · صلّوا لأجلهم بالاسم",
"people_suffix": "نسمة",
"no_photo": "لا توجد صورة متاحة",
"deck_title": "بطاقات الصلاة",
"card_country": "الدولة",
"card_population": "عدد السكان",
"card_language": "اللغة",
"card_religion": "الديانة",
"card_cta": "صلّوا لأجلهم",
"points_title": "12 نقطة صلاة",
"points_intro": "ساعة واحدة مع الله، خمس دقائق لكل نقطة. صلّوا هذه النقاط الاثنتي عشرة لأجل الشعوب في هذه الحزمة.",
"points_attrib": "إيقاعات الصلاة مستوحاة من Metacamp · metacamp.org",
"wheel_title": "عجلة الصلاة",
"wheel_intro": "أن تقضي ساعة مع الله؟ الأمر أسهل مما تظن. قسّمها إلى فترات من خمس دقائق وركّز على واحدة من هذه النقاط في كل فترة.",
"wheel_minutes": "دقائق",
"wheel_attrib": "عجلة الصلاة · وحدة Metacamp الأولى · metacamp.org",
"privacy_note": "مواقع العلامات تقريبية · تُعمَّم مواقع الشعوب في المصدر حفاظًا على الخصوصية",
"rhythms": {
"praise": "تسبيح",
"wait": "انتظار",
"confess": "اعتراف",
"read": "قراءة الكلمة",
"ask": "طلب",
"intercede": "شفاعة",
"pray_word": "الصلاة بالكلمة",
"thank": "شكر",
"sing": "ترنيم",
"meditate": "تأمل",
"listen": "إصغاء",
"praise_end": "تسبيح"
},
"points": [
{
"n": 1,
"rhythm": "praise",
"sub": "إنجيل الصليبين",
"text": "أن يقبلوا المسيح ملكًا، مغفورًا لهم بصليبه — وأن يحملوا صليبهم، مستعدين للتألم في منطقة اضطهاد. ليَنَلِ الحمل أجر آلامه، ابتداءً بي.",
"refs": [
"Matthew 27:27",
"Matthew 16:24–25"
]
},
{
"n": 2,
"rhythm": "wait",
"sub": "الروح القدس والتحرير",
"text": "أن يمتلئوا بالروح ويصيروا شهودًا جسورين؛ ألا يكونوا منعزلين؛ معمَّدين بالماء والروح؛ وأن تُكسَر كل قبضة للشر. وأن يُدفَع المؤمنون من الشعوب المجاورة ليكونوا عمالًا.",
"refs": [
"Acts 1:8",
"John 14:26"
]
},
{
"n": 3,
"rhythm": "confess",
"sub": "",
"text": "نعترف بعدم الإيمان الذي يحسب هذا أعظم من أن يقدر الله عليه. أن يُحيي فينا المحبة والإيمان لأجل غير المبلَّغين في العالم.",
"refs": [
"John 3:16",
"1 John 1:9"
]
},
{
"n": 4,
"rhythm": "read",
"sub": "محبة الآب",
"text": "أن يَخلُصوا ويَعرِفوا أن أباهم السماوي يحبهم — وأن يحمل بهم الخلاص إلى عائلاتهم وأصدقائهم وجيرانهم وزملائهم في العمل والدراسة، وكل من يعرفونهم شخصيًا.",
"refs": [
"Mark 5:1–20",
"Acts 16:31"
],
"print_passage": true
},
{
"n": 5,
"rhythm": "ask",
"sub": "المعموديات",
"text": "معموديات جديدة بين أهل البلد، وأن يُدرَّب كل معمَّد ليعمّد آخرين، فيتكاثروا.",
"refs": [
"Acts 16",
"Acts 10"
]
},
{
"n": 6,
"rhythm": "intercede",
"sub": "عمال ورعاة",
"text": "عمال مرسَلون ليحبوا بعمق شعبًا لم يلتقوه قط؛ ورعاة صالحون يُقامون من الداخل.",
"refs": [
"Luke 10:2",
"John 10:11–15"
]
},
{
"n": 7,
"rhythm": "pray_word",
"sub": "أشخاص وبيوت السلام",
"text": "أن يجد العمال والقادة المحليون الشخص المستعد وبيت السلام، وأن يتلمذوهم جيدًا.",
"refs": [
"Luke 10:5–7",
"Matthew 10:5–14"
]
},
{
"n": 8,
"rhythm": "thank",
"sub": "الراحة",
"text": "نشكر الله على الراحة التي أعطاها؛ أن يدخلوا تلك الراحة في المسيح، وأن تكون عائلتهم الروحية مكانًا آمنًا.",
"refs": [
"Mark 4:26–29",
"Hebrews 4:9–11"
]
},
{
"n": 9,
"rhythm": "sing",
"sub": "",
"text": "أن يفيض الشعب بالساجدين — عبادة في كل مكان، في الحرية وفي القيود.",
"refs": [
"Acts 16:25–26",
"Colossians 3:16"
]
},
{
"n": 10,
"rhythm": "meditate",
"sub": "شركة",
"text": "أن يتناولوا العشاء الرباني معًا ويدركوا ثقل موته ودفنه وقيامته.",
"refs": [
"Matthew 26:26–30",
"1 Corinthians 11:23–26"
]
},
{
"n": 11,
"rhythm": "listen",
"sub": "المساءلة",
"text": "ليس أن يسمعوا فحسب، بل أن يكون في حياتهم من يعينهم على قراءة الكلمة والصلاة والالتزام بالجماعة والاستجابة الحسنة للألم — مقاومين العدو الذي يطارد المؤمنين في العالم أجمع.",
"refs": [
"1 Peter 5:6–11",
"Hebrews 10:24–25"
]
},
{
"n": 12,
"rhythm": "praise_end",
"sub": "عظيم · أعظم · الأعظم",
"text": "تسبيح مسبق — لأجل الخلاص؛ وأعظم، لأجل عائلات روحية تتكاثر؛ والأعظم، لأجل حياة مُسلَّمة وغارسي كنائس محليين يُقامون فيكثّرون كنائس صحيحة في الشعب كله، مهما كلّف الثمن.",
"refs": [
"Acts 2:42–47",
"Matthew 28:19–20"
]
}
]
}
}

View file

@ -57,6 +57,7 @@
"build:unlocked": "bun run gates:pre && bun run library-index && bun run check:library-index && bun run clean && bun run token && bun run build:bundles && bun run tree && bun run gates:post && bun run gallery",
"check:card-deck": "node internal/check-card-deck.mjs",
"check:poster-raster": "node internal/check-poster-raster.mjs",
"check:print-geometry": "node internal/check-print-geometry.mjs",
"check:packet-browser": "node internal/check-packet-browser.mjs",
"check:packet-render": "node internal/check-packet-render.mjs",
"check:template-literal": "node internal/template-literal-check.mjs",

View file

@ -271,9 +271,16 @@ const exportState = ref(null) // { label, phase, message, pct, kind }
// is what commercial card printers, sleeves and boxes are built around.
// @page takes these as explicit inches — a NAMED size silently falls back to letter
// in Chromium, which is the exact bug this deck is being fixed for.
// Both orientations, because the Driver asked for "horizontal cards" as well as
// vertical ones. A landscape stock is not merely transposed: the renderer moves
// the photo BESIDE the text, since a 46%-height band on a 2.5in-tall card is too
// short to carry a face. The labels come from the renderer's own STOCK table so
// this list cannot drift from what the renderer actually supports.
const DECK_STOCKS = [
{ id: 'poker', label: 'Card 2.5 × 3.5 in' },
{ id: 'pokerLandscape', label: 'Card 3.5 × 2.5 in (landscape)' },
{ id: 'postcard', label: 'Postcard 4 × 6 in' },
{ id: 'postcardLandscape', label: 'Postcard 6 × 4 in (landscape)' },
{ id: 'a6', label: 'A6 105 × 148 mm' },
]
const deckStock = ref('poker')

File diff suppressed because one or more lines are too long