To: ${range.to_surah}:${range.to_ayah} (${toSurah})
+ `;
+};
+
+juzSelect.addEventListener("change", render);
+juzSelect.value = "30";
+render();
+```
+
+## 7) Common Mistakes to Avoid
+
+- Treating metadata as text content instead of navigation data.
+- Hardcoding ranges instead of using metadata package values.
+- Ignoring enum fields (for example revelation place) during filtering.
+
+## 8) When to Request Updates or Changes
+
+Open an issue if you find:
+
+- Incorrect structural ranges
+- Missing metadata records
+- Broken json/sqlite links
+
+Issue tracker:
+
+- [https://github.com/TarteelAI/quranic-universal-library/issues](https://github.com/TarteelAI/quranic-universal-library/issues)
+
+## Related Docs
+
+- [Tutorials Index](tutorials.md)
+- [Quran Metadata Guide](resource-quran-metadata.md)
+- [Quran Script Guide](resource-quran-script.md)
+- [Surah Information Guide](resource-surah-information.md)
diff --git a/docs/tutorial-quran-script-end-to-end.md b/docs/tutorial-quran-script-end-to-end.md
new file mode 100644
index 00000000..c681f04b
--- /dev/null
+++ b/docs/tutorial-quran-script-end-to-end.md
@@ -0,0 +1,281 @@
+# Tutorial 5: Quran Script End-to-End
+
+This tutorial is for users who want to download Quran Script data and render Arabic text reliably in apps.
+
+## 1) What This Resource Is
+
+Quran Script resources provide Arabic Quran text in script-specific formats (for example: word-by-word and ayah-by-ayah variants).
+
+Depending on the selected package, script data can include:
+
+- Verse-level text (`verse_key`, `text`)
+- Script metadata (`script_type`, `font_family`)
+- Word-level arrays (`words[].position`, `words[].text`, `words[].location`)
+- Navigation metadata (`page_number`, `juz_number`, `hizb_number`)
+
+Primary category:
+
+- [https://qul.tarteel.ai/resources/quran-script](https://qul.tarteel.ai/resources/quran-script)
+
+## 2) When to Use It
+
+Use Quran Script data when you are building:
+
+- Arabic Quran readers
+- Word-by-word reading and study interfaces
+- Features that require stable ayah or word keys for joins (translation, tafsir, audio sync)
+
+## 3) How to Get Your First Example Resource
+
+1. Open [https://qul.tarteel.ai/resources/quran-script](https://qul.tarteel.ai/resources/quran-script).
+2. Keep the default listing order and open the first published card.
+3. Confirm the detail page includes:
+ - `Preview` tab
+ - `Help` tab
+4. Confirm available downloads:
+ - `sqlite`
+ - `json`
+5. Confirm whether the package is marked `Word by word` or `Ayah by ayah`.
+
+This keeps onboarding concrete without hardcoding a resource ID.
+
+## 4) What the Preview Shows (Website-Aligned)
+
+On the script detail page:
+
+- `Preview` tab:
+ - `Jump to Ayah` selector
+ - Previous/next ayah navigation
+ - Rendered Arabic script output (often word-by-word blocks in word resources)
+- `Help` tab:
+ - Sample JSON structure
+ - Field descriptions (`verse_key`, `text`, `script_type`, `font_family`, `words`)
+ - Rendering notes and usage examples (CSS + JS)
+
+Practical meaning:
+
+- You should treat `verse_key` and `words[].location` as canonical join keys.
+- You should apply the provided `font_family` (or compatible fallback) for accurate rendering.
+
+## 5) Download and Use (Step-by-Step)
+
+1. Download selected script package (`json` or `sqlite`).
+2. Inspect core fields:
+ - `verse_key` in `surah:ayah`
+ - `text`
+ - `script_type`
+ - `font_family`
+ - `words` (if word-by-word package)
+3. Normalize keys in your app:
+ - Ayah key: `surah:ayah`
+ - Word key: `surah:ayah:word`
+4. Store verse and word rows in indexed tables/maps.
+5. Join with translation/tafsir/recitation by shared ayah keys.
+6. Apply RTL direction + script font in UI.
+7. Validate on one full surah and several random ayahs.
+
+Starter integration snippet (JavaScript):
+
+```javascript
+// Build fast verse lookup by canonical ayah key.
+const buildVerseIndex = (rows) =>
+ rows.reduce((index, row) => {
+ index[row.verse_key] = {
+ text: row.text,
+ scriptType: row.script_type,
+ fontFamily: row.font_family,
+ words: Array.isArray(row.words) ? row.words : []
+ };
+ return index;
+ }, {});
+
+// Render one verse with script-aware font + RTL settings.
+const renderVerse = (container, verseRecord) => {
+ container.dir = "rtl";
+ container.style.textAlign = "right";
+ container.style.fontFamily = `${verseRecord.fontFamily || "serif"}, "Amiri Quran", "Noto Naskh Arabic", serif`;
+ container.textContent = verseRecord.text;
+};
+
+// Optional: render word-by-word blocks when word data exists.
+const renderWordBlocks = (container, words) => {
+ container.innerHTML = "";
+ words
+ .slice()
+ .sort((a, b) => a.position - b.position)
+ .forEach((word) => {
+ const chip = document.createElement("span");
+ chip.textContent = word.text;
+ chip.title = word.location; // e.g., 1:1:2
+ chip.style.display = "inline-block";
+ chip.style.padding = "6px 10px";
+ chip.style.margin = "4px";
+ chip.style.border = "1px solid #e2e8f0";
+ chip.style.borderRadius = "8px";
+ container.appendChild(chip);
+ });
+};
+```
+
+## 6) Real-World Example: Render One Ayah (Verse + Words)
+
+Goal:
+
+- User selects an ayah and sees both full Arabic verse text and word-by-word chips.
+
+Inputs:
+
+- Quran Script package (word-by-word variant)
+
+Processing:
+
+1. User selects ayah key (example: `73:4`).
+2. App loads verse row by `verse_key`.
+3. App renders full verse text using script-aware font.
+4. App renders sorted `words[]` as chips.
+
+Expected output:
+
+- Correct Arabic script display.
+- Word order remains stable by `position`.
+- Keys remain compatible with translation/tafsir/audio joins.
+
+Interactive preview (temporary sandbox):
+
+You can edit this code for testing. Edits are not saved and may not persist after refresh.
+
+```playground-js
+// This playground mirrors Quran Script help concepts:
+// verse_key + text + script_type + font_family + words[] with location keys.
+
+const scriptRows = [
+ {
+ verse_key: "73:4",
+ text: "أَوۡ زِدۡ عَلَيۡهِ وَرَتِّلِ ٱلۡقُرۡءَانَ تَرۡتِيلًا",
+ script_type: "text_qpc_hafs",
+ font_family: "qpc-hafs",
+ words: [
+ { position: 1, text: "أَوۡ", location: "73:4:1" },
+ { position: 2, text: "زِدۡ", location: "73:4:2" },
+ { position: 3, text: "عَلَيۡهِ", location: "73:4:3" },
+ { position: 4, text: "وَرَتِّلِ", location: "73:4:4" },
+ { position: 5, text: "ٱلۡقُرۡءَانَ", location: "73:4:5" },
+ { position: 6, text: "تَرۡتِيلًا", location: "73:4:6" }
+ ]
+ },
+ {
+ verse_key: "1:1",
+ text: "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ",
+ script_type: "text_qpc_hafs",
+ font_family: "qpc-hafs",
+ words: [
+ { position: 1, text: "بِسۡمِ", location: "1:1:1" },
+ { position: 2, text: "ٱللَّهِ", location: "1:1:2" },
+ { position: 3, text: "ٱلرَّحۡمَٰنِ", location: "1:1:3" },
+ { position: 4, text: "ٱلرَّحِيمِ", location: "1:1:4" }
+ ]
+ }
+];
+
+// Create verse lookup by verse_key.
+const verseByKey = scriptRows.reduce((index, row) => {
+ index[row.verse_key] = row;
+ return index;
+}, {});
+
+const app = document.getElementById("app");
+const dropdownStyle = [
+ "margin-bottom:12px",
+ "padding:8px",
+ "border:1px solid #cbd5e1",
+ "border-radius:8px",
+ "background:#fff",
+ "color:#0f172a",
+ "font-size:0.95rem",
+ "line-height:1.3",
+ "min-width:220px"
+].join(";");
+
+app.innerHTML = `
+
Quran Script Preview (Verse + Word by Word)
+
Shows how verse_key and words[].location map to rendering + integration keys
+
+
+
+
+
+`;
+
+const ayahSelect = app.querySelector("#ayah");
+const metaBox = app.querySelector("#meta");
+const verseBox = app.querySelector("#verse");
+const wordsBox = app.querySelector("#words");
+
+const renderAyah = (ayahKey) => {
+ const verse = verseByKey[ayahKey];
+ if (!verse) {
+ verseBox.textContent = "(Verse not found)";
+ wordsBox.innerHTML = "";
+ metaBox.textContent = "";
+ return;
+ }
+
+ // Show script metadata users should carry into app rendering rules.
+ metaBox.textContent = `verse_key: ${verse.verse_key} | script_type: ${verse.script_type} | font_family: ${verse.font_family}`;
+
+ // Full verse rendering.
+ verseBox.textContent = verse.text;
+
+ // Word-by-word rendering sorted by position.
+ wordsBox.innerHTML = "";
+ verse.words
+ .slice()
+ .sort((a, b) => a.position - b.position)
+ .forEach((word) => {
+ const chip = document.createElement("span");
+ chip.textContent = word.text;
+ chip.title = word.location;
+ chip.style.display = "inline-block";
+ chip.style.padding = "6px 10px";
+ chip.style.margin = "4px";
+ chip.style.border = "1px solid #e2e8f0";
+ chip.style.borderRadius = "8px";
+ chip.style.fontFamily = "'KFGQPC Uthmanic Script HAFS','Amiri Quran','Noto Naskh Arabic','Scheherazade New',serif";
+ wordsBox.appendChild(chip);
+ });
+};
+
+ayahSelect.addEventListener("change", (event) => renderAyah(event.target.value));
+renderAyah(ayahSelect.value);
+```
+
+## 7) Common Mistakes to Avoid
+
+- Joining script data to other resources using row order instead of keys.
+- Ignoring `font_family` and then assuming text is wrong when rendering is visually off.
+- Treating word-by-word and ayah-by-ayah packages as interchangeable shapes.
+- Ignoring `words[].position` and rendering words out of order.
+
+## 8) When to Request Updates or Changes
+
+Open an issue if you find:
+
+- Missing ayah rows or mismatched `verse_key` values
+- Broken json/sqlite links for script resources
+- Incorrect word order/location keys in word-by-word exports
+- Metadata inconsistencies in `script_type` or `font_family`
+
+Issue tracker:
+
+- [https://github.com/TarteelAI/quranic-universal-library/issues](https://github.com/TarteelAI/quranic-universal-library/issues)
+
+## Related Docs
+
+- [Tutorials Index](tutorials.md)
+- [Quran Script Guide](resource-quran-script.md)
+- [Translations Guide](resource-translations.md)
+- [Tafsirs Guide](resource-tafsirs.md)
+- [Downloading and Using Data](downloading-data.md)
diff --git a/docs/tutorial-recitation-end-to-end.md b/docs/tutorial-recitation-end-to-end.md
new file mode 100644
index 00000000..07b7ecce
--- /dev/null
+++ b/docs/tutorial-recitation-end-to-end.md
@@ -0,0 +1,207 @@
+# Tutorial 1: Recitation End-to-End
+
+This tutorial is for users who want to download recitation data and build a minimal synced playback experience.
+
+## 1) What This Resource Is
+
+Recitation resources provide Quran audio and related timing metadata.
+
+Depending on the selected package, you can get:
+
+- Surah-by-surah audio (gapless playback)
+- Ayah-by-ayah audio (gapped playback)
+- Segment timing arrays used for synchronized word or ayah highlighting
+
+Primary category:
+
+- [https://qul.tarteel.ai/resources/recitation](https://qul.tarteel.ai/resources/recitation)
+
+## 2) When to Use It
+
+Use recitation data when you are building:
+
+- Quran audio players
+- Memorization or revision tools
+- Reading experiences that sync highlights to playback
+
+## 3) How to Get Your First Example Resource
+
+1. Open [https://qul.tarteel.ai/resources/recitation](https://qul.tarteel.ai/resources/recitation).
+2. Open the first published card in the default page order.
+3. Confirm the resource detail page includes:
+ - A `Recitation` preview tab
+ - A `Help` tab with segment format examples
+4. Download the available file format (`JSON`, `SQLite`, or both).
+
+This avoids hardcoding a resource ID while keeping onboarding concrete.
+
+## 4) What the Preview Shows (Website-Aligned)
+
+On the recitation detail page, the preview helps you validate usability before download:
+
+- `Recitation` tab:
+ - Jump-to-ayah selector
+ - Previous/next ayah navigation
+ - Audio player with timing-driven highlighting behavior
+- `Help` tab:
+ - Difference between surah-by-surah and ayah-by-ayah data
+ - Segment/timestamp sample formats for integration
+
+Practical meaning:
+
+- If segment arrays are present, you can build synchronized highlighting.
+- If segment arrays are absent, treat the resource as audio-only playback.
+
+## 5) Download and Use (Step-by-Step)
+
+1. Download your selected recitation package.
+2. Inspect fields before integration:
+ - Ayah identity fields (`surah`, `ayah`, or `surah:ayah`)
+ - Timing fields (`segments`, `timestamp_from`, `timestamp_to`) when provided
+ - Audio pointer field (`audio_url` or equivalent)
+3. Normalize to a consistent key in your app.
+4. Join recitation rows with Quran text rows using the same ayah key.
+5. Build a minimal player loop.
+6. Test with at least one full surah.
+
+Starter integration snippet (JavaScript):
+
+```javascript
+// Convert mixed source fields into one stable key format (e.g., "2:255").
+const normalizeAyahKey = (row) => {
+ if (row.ayah_key) return row.ayah_key;
+ return `${row.surah}:${row.ayah}`;
+};
+
+// Build a quick lookup so playback can find timing/audio by ayah key.
+const buildTimingIndex = (recitationRows) => {
+ return recitationRows.reduce((index, row) => {
+ const key = normalizeAyahKey(row);
+ index[key] = {
+ audioUrl: row.audio_url,
+ from: row.timestamp_from,
+ to: row.timestamp_to,
+ segments: Array.isArray(row.segments) ? row.segments : []
+ };
+ return index;
+ }, {});
+};
+
+// Merge Quran text rows with recitation timing rows for display + sync.
+const joinTextWithTiming = (scriptRows, timingIndex) => {
+ return scriptRows
+ .map((row) => {
+ const ayahKey = `${row.surah}:${row.ayah}`;
+ return { ...row, ayahKey, timing: timingIndex[ayahKey] || null };
+ })
+ // Keep only rows we can actually sync.
+ .filter((row) => row.timing);
+};
+```
+
+## 6) Real-World Example: Play One Surah with Live Ayah Highlighting
+
+Goal:
+
+- User plays a surah and sees the currently recited ayah highlighted in real time.
+
+Inputs:
+
+- Recitation resource (audio + timings when available)
+- Quran Script resource (ayah text)
+
+Processing:
+
+1. User selects a surah.
+2. App loads surah text from Quran Script.
+3. App loads matching recitation timing map for the same surah.
+4. On each player time update, app finds the active ayah time window.
+5. UI updates highlight state for that ayah.
+
+Expected output:
+
+- Audio playback is smooth.
+- Highlight transitions follow recitation timing.
+- Ayah text and audio stay mapped by the same ayah key.
+
+Interactive preview (temporary sandbox):
+
+You can edit this code for testing. Edits are not saved and may not persist after refresh.
+
+```playground-js
+const words = [
+ { wordKey: "1:1:1", text: "بِسۡمِ", from: 0, to: 2 },
+ { wordKey: "1:1:2", text: "ٱللَّهِ", from: 2, to: 4 },
+ { wordKey: "1:1:3", text: "ٱلرَّحۡمَٰنِ", from: 4, to: 6 },
+ { wordKey: "1:1:4", text: "ٱلرَّحِيمِ", from: 6, to: 8 }
+];
+
+const app = document.getElementById("app");
+app.innerHTML = `
+
Word Playback Preview (Real Arabic Text)
+
Simulated timestamp-driven highlighting for Surah 1:1 words
+
+`;
+
+const list = app.querySelector("#word-list");
+words.forEach((word) => {
+ const li = document.createElement("li");
+ li.dataset.wordKey = word.wordKey;
+ li.style.padding = "8px 10px";
+ li.style.marginBottom = "6px";
+ li.style.borderRadius = "8px";
+ li.style.border = "1px solid #e2e8f0";
+ li.style.transition = "all 120ms ease";
+ li.style.textAlign = "right";
+ li.style.fontSize = "1.2rem";
+ li.textContent = word.text;
+ list.appendChild(li);
+});
+
+let currentSecond = 0;
+const totalDuration = words[words.length - 1].to + 1;
+
+const setActiveWord = (second) => {
+ const active = words.find((word) => second >= word.from && second < word.to);
+ list.querySelectorAll("li").forEach((li) => {
+ const isActive = active && li.dataset.wordKey === active.wordKey;
+ li.style.background = isActive ? "#dcfce7" : "#ffffff";
+ li.style.borderColor = isActive ? "#22c55e" : "#e2e8f0";
+ li.style.fontWeight = isActive ? "700" : "400";
+ });
+};
+
+setActiveWord(currentSecond);
+setInterval(() => {
+ currentSecond = (currentSecond + 1) % totalDuration;
+ setActiveWord(currentSecond);
+}, 1000);
+```
+
+## 7) Common Mistakes to Avoid
+
+- Assuming all recitations include segments.
+- Mixing key formats without normalization.
+- Joining recitation to text using row order instead of ayah identity.
+- Treating preview success for one ayah as proof that whole-surah mapping is correct.
+
+## 8) When to Request Updates or Changes
+
+Open an issue if you find:
+
+- Broken or inaccessible audio file links
+- Segment/timestamp values that do not match audible recitation
+- Missing ayah mappings in downloaded files
+- Inconsistent reciter or package metadata
+
+Issue tracker:
+
+- [https://github.com/TarteelAI/quranic-universal-library/issues](https://github.com/TarteelAI/quranic-universal-library/issues)
+
+## Related Docs
+
+- [Tutorials Index](tutorials.md)
+- [Recitations Guide](resource-recitations.md)
+- [Quran Script Guide](resource-quran-script.md)
+- [Data Model](data-model.md)
+- [Downloading and Using Data](downloading-data.md)
diff --git a/docs/tutorial-similar-ayah-end-to-end.md b/docs/tutorial-similar-ayah-end-to-end.md
new file mode 100644
index 00000000..73184070
--- /dev/null
+++ b/docs/tutorial-similar-ayah-end-to-end.md
@@ -0,0 +1,348 @@
+# Tutorial 13: Similar Ayah End-to-End
+
+This tutorial is for users who want to show ayah-to-ayah similarity results (matched words, coverage, and score).
+
+## 1) What This Resource Is
+
+Similar Ayah resources provide ayah-level similarity records.
+
+Typical fields include:
+
+- `verse_key`
+- `matched_ayah_key`
+- `matched_words_count`
+- `coverage`
+- `score`
+- `match_words_range` (word position range in matched ayah)
+
+Primary category:
+
+- [https://qul.tarteel.ai/resources/similar-ayah](https://qul.tarteel.ai/resources/similar-ayah)
+
+## 2) When to Use It
+
+Use similar-ayah data when building:
+
+- Compare-verses tools
+- Pattern discovery across Quranic wording
+- Memorization reinforcement features
+
+## 3) How to Get Your First Example Resource
+
+1. Open [https://qul.tarteel.ai/resources/similar-ayah](https://qul.tarteel.ai/resources/similar-ayah).
+2. Keep default listing order and open the first published card.
+3. Confirm the detail page includes:
+ - `Similar Ayah Preview` tab
+ - `Help` tab
+4. Confirm available downloads (`json`, `sqlite`).
+
+This keeps onboarding concrete without hardcoded IDs.
+
+## 4) What the Preview Shows (Website-Aligned)
+
+On similar-ayah detail pages:
+
+- `Similar Ayah Preview` tab:
+ - `Jump to Ayah`
+ - Source ayah card for selected ayah
+ - "X has N similar ayahs" banner
+ - List of matching ayahs for selected ayah
+ - Highlighted matched words inside matched ayah text
+ - Match summaries ("This ayah matches N words with X% coverage and a similarity score of Y")
+- `Help` tab:
+ - Field definitions (`verse_key`, `matched_ayah_key`, `matched_words_count`, `coverage`, `score`, `match_words_range`)
+ - Export format notes
+
+Practical meaning:
+
+- Similarity is scored data, not binary “same/different”.
+- You should sort by score/coverage and let users inspect why matches appear.
+
+## 5) Download and Use (Step-by-Step)
+
+1. Download selected package (`json` or `sqlite`).
+2. Import similarity rows.
+3. Group rows by `verse_key`.
+4. Sort matches by score and/or coverage.
+5. Join with script text for readable display.
+6. Use `match_words_range` to highlight matched words in the matched ayah.
+
+Starter integration snippet (JavaScript):
+
+```javascript
+const matchesForAyah = (rows, ayahKey) =>
+ rows
+ .filter((row) => row.verse_key === ayahKey)
+ .sort((a, b) => b.score - a.score || b.coverage - a.coverage);
+
+const summaryText = (row) =>
+ `This ayah matches ${row.matched_words_count} words with ${row.coverage}% coverage and a similarity score of ${row.score}`;
+
+const isMatchedWordPosition = (wordIndexOneBased, range) => {
+ if (!Array.isArray(range) || range.length !== 2) return false;
+ const [from, to] = range;
+ return wordIndexOneBased >= from && wordIndexOneBased <= to;
+};
+```
+
+## 6) Real-World Example: Top Similar Ayahs Panel
+
+Goal:
+
+- User opens an ayah and sees top similar ayahs ranked by score.
+
+Inputs:
+
+- Similar Ayah package
+- Quran Script package
+
+Processing:
+
+1. Filter rows by selected `verse_key`.
+2. Sort by `score` (and `coverage` as tie-breaker).
+3. Join matched ayah text and highlight words by `match_words_range`.
+4. Display per-match summary sentence.
+
+Expected output:
+
+- Ranked similarity results that are interpretable, with visible highlighted overlap.
+
+Interactive preview (temporary sandbox):
+
+You can edit this code for testing. Edits are not saved and may not persist after refresh.
+
+```playground-js
+// Preview-aligned sandbox:
+// Jump to Ayah -> source ayah card -> similar ayah cards with highlighted matched words.
+// Based on the behavior shown in similar-ayah resource 74.
+
+const sourceAyahTextByKey = {
+ "1:1": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ ١",
+ "1:3": "ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ ٣"
+};
+
+const similarRows = [
+ {
+ verse_key: "1:1",
+ matched_ayah_key: "27:30",
+ matched_words_count: 4,
+ coverage: 50,
+ score: 80,
+ match_words_range: [5, 8]
+ },
+ {
+ verse_key: "1:1",
+ matched_ayah_key: "59:22",
+ matched_words_count: 2,
+ coverage: 15,
+ score: 56,
+ match_words_range: [12, 13]
+ },
+ {
+ verse_key: "1:1",
+ matched_ayah_key: "1:3",
+ matched_words_count: 2,
+ coverage: 100,
+ score: 50,
+ match_words_range: [1, 2]
+ },
+ {
+ verse_key: "1:1",
+ matched_ayah_key: "41:2",
+ matched_words_count: 2,
+ coverage: 50,
+ score: 50,
+ match_words_range: [3, 4]
+ },
+ {
+ verse_key: "1:3",
+ matched_ayah_key: "1:1",
+ matched_words_count: 2,
+ coverage: 100,
+ score: 50,
+ match_words_range: [3, 4]
+ }
+];
+
+// Keep literals as UTF-8 Arabic text.
+const matchedAyahTextByKey = {
+ "27:30": "إِنَّهُۥ مِن سُلَيۡمَٰنَ وَإِنَّهُۥ بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ ٣٠",
+ "59:22": "هُوَ ٱللَّهُ ٱلَّذِي لَآ إِلَٰهَ إِلَّا هُوَۖ عَٰلِمُ ٱلۡغَيۡبِ وَٱلشَّهَٰدَةِۖ هُوَ ٱلرَّحۡمَٰنُ ٱلرَّحِيمُ ٢٢",
+ "1:3": "ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ ٣",
+ "41:2": "تَنزِيلٞ مِّنَ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ ٢",
+ "1:1": "بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ ١"
+};
+
+// Help-aligned schema and sample block (as shown on the resource Help tab).
+const helpSchema = [
+ { column: "verse_key", type: "TEXT", description: "The ayah key that similar ayahs belongs to (e.g., 1:1)." },
+ { column: "matched_ayah_key", type: "TEXT", description: "Matching ayah key that shares similar wording." },
+ { column: "matched_words_count", type: "INTEGER", description: "Number of matching words between the two ayahs." },
+ { column: "coverage", type: "INTEGER", description: "Percentage of words in the source ayah that matched." },
+ { column: "score", type: "INTEGER", description: "Similarity score between the source and matched ayah (0–100)." },
+ { column: "match_words_range", type: "TEXT", description: "Word position range in matching ayah that matched with source ayah." }
+];
+
+const helpExample = {
+ verse_key: "1:1",
+ matched_ayah_key: "27:30",
+ matched_words_count: 4,
+ coverage: 100,
+ score: 100,
+ match_words_range: [5, 8]
+};
+
+const highlightMatchedWords = (ayahText, range) =>
+ String(ayahText || "")
+ .split(/\s+/)
+ .filter(Boolean)
+ .map((word, index) => {
+ const pos = index + 1;
+ const inRange =
+ Array.isArray(range) &&
+ range.length === 2 &&
+ pos >= range[0] &&
+ pos <= range[1];
+ if (!inRange) return word;
+ return `${word}`;
+ })
+ .join(" ");
+
+const app = document.getElementById("app");
+const dropdownStyle = [
+ "margin-bottom:12px",
+ "padding:8px",
+ "border:1px solid #cbd5e1",
+ "border-radius:8px",
+ "background:#fff",
+ "color:#0f172a",
+ "font-size:0.95rem",
+ "line-height:1.3",
+ "min-width:220px"
+].join(";");
+
+app.innerHTML = `
+
Similar Ayah Preview
+
Preview + Help on one screen: interactive similar-ayah cards and schema/sample reference
+
+ Top section mirrors Preview. Bottom section mirrors the Help field/schema explanation.
+
+
+
+
+
Select the source ayah to compare similar matches.
QUL exports similar ayah data in JSON and SQLite. Core fields:
+
+
+
+
+
Column
+
Type
+
Description
+
+
+ ${schemaRows}
+
+
+
Help sample (if 1:1 matches 27:30):
+
${JSON.stringify(helpExample, null, 2)}
+
+ This ayah matches ${helpExample.matched_words_count} words, with ${helpExample.coverage}% coverage and a similarity score of ${helpExample.score}.
+ Word ${helpExample.match_words_range[0]} to ${helpExample.match_words_range[1]} matched with source ayah.
+
+ `;
+};
+
+ayahSelect.addEventListener("change", render);
+render();
+```
+
+## 7) Common Mistakes to Avoid
+
+- Treating similarity score as strict equivalence.
+- Ignoring coverage and matched-word context.
+- Not sorting results (raw order can be misleading).
+
+## 8) When to Request Updates or Changes
+
+Open an issue if you find:
+
+- Mismatched `verse_key`/`matched_ayah_key` pairs
+- Invalid score/coverage values
+- Broken json/sqlite downloads
+
+Issue tracker:
+
+- [https://github.com/TarteelAI/quranic-universal-library/issues](https://github.com/TarteelAI/quranic-universal-library/issues)
+
+## Related Docs
+
+- [Tutorials Index](tutorials.md)
+- [Similar Ayah Guide](resource-similar-ayah.md)
+- [Mutashabihat Guide](resource-mutashabihat.md)
+- [Quran Script Guide](resource-quran-script.md)
diff --git a/docs/tutorial-surah-information-end-to-end.md b/docs/tutorial-surah-information-end-to-end.md
new file mode 100644
index 00000000..0cc9c4eb
--- /dev/null
+++ b/docs/tutorial-surah-information-end-to-end.md
@@ -0,0 +1,297 @@
+# Tutorial 9: Surah Information End-to-End
+
+This tutorial is for users who want to show chapter-level context (names, summaries, key notes) before ayah reading.
+
+## 1) What This Resource Is
+
+Surah Information resources provide chapter metadata and explanatory context.
+
+Typical fields include:
+
+- Surah identity (`surah_id` / number)
+- Names/titles
+- Short summary text
+- Detailed long-form content (often with sections such as `Name`, `Period of Revelation`, `Theme`)
+- Language/source metadata
+- Revelation context and related descriptors
+
+Primary category:
+
+- [https://qul.tarteel.ai/resources/surah-info](https://qul.tarteel.ai/resources/surah-info)
+
+## 2) When to Use It
+
+Use surah-info data when building:
+
+- Surah intro cards before ayah list
+- Chapter overview pages
+- Learning experiences with chapter context
+
+## 3) How to Get Your First Example Resource
+
+1. Open [https://qul.tarteel.ai/resources/surah-info](https://qul.tarteel.ai/resources/surah-info).
+2. Keep default listing order and open the first published card.
+3. Confirm the detail page includes:
+ - `Surah Info Preview` tab
+ - `Help` tab
+4. Confirm available downloads (`csv`, `json`, `sqlite`).
+
+This keeps onboarding concrete without hardcoded IDs.
+
+## 4) What the Preview Shows (Website-Aligned)
+
+On surah-info detail pages:
+
+- `Surah Info Preview` tab:
+ - `Jump to Surah`
+ - Next/previous surah navigation
+ - Short summary paragraph
+ - Detailed content blocks (for example `Name`, `Period of Revelation`, `Theme`)
+- `Help` tab:
+ - Resource purpose and coverage (themes/topics/reasons for revelation/summaries)
+ - Format availability (`SQLite`, `CSV`, `JSON`)
+ - Note that some records include both short summary and detailed long-form text
+ - Note that detailed text may include HTML tags for formatting
+
+Practical meaning:
+
+- Surah-info is chapter-level context, not ayah-level text.
+- Use it as a companion layer above script/translation views.
+
+Full Surah 1 example content (from a surah-info detail page, in the same structure users see):
+
+- Intro summary:
+ - This Surah is named Al-Fatihah because of its subject matter. Fatihah is that which opens a subject or a book or any other thing. In other words, Al-Fatihah is a sort of preface.
+- Name:
+ - This Surah is named Al-Fatihah because of its subject matter. Fatihah is that which opens a subject or a book or any other thing. In other words, Al-Fatihah is a sort of preface.
+- Period of Revelation:
+ - Surah Al-Fatihah is one of the very earliest Revelations to the Holy Prophet. As a matter of fact, we learn from authentic traditions that it was the first complete Surah that was revealed to Muhammad (Allah's peace be upon him). Before this, only a few miscellaneous verses were revealed which form parts of Alaq, Muzzammil, Muddaththir, etc.
+- Theme:
+ - This Surah is in fact a prayer that Allah has taught to all those who want to make a study of His book. It has been placed at the very beginning of the Quran to teach this lesson to the reader: if you sincerely want to benefit from the Quran, you should offer this prayer to the Lord of the Universe.
+ - This preface is meant to create a strong desire in the heart of the reader to seek guidance from the Lord of the Universe Who alone can grant it. Thus Al-Fatihah indirectly teaches that the best thing for a man is to pray for guidance to the straight path, to study the Quran with the mental attitude of a seeker searching for the truth, and to recognize the fact that the Lord of the Universe is the source of all knowledge. He should, therefore, begin the study of the Quran with a prayer to Him for guidance.
+ - From this theme, it becomes clear that the real relation between Al-Fatihah and the Quran is not that of an introduction to a book but that of a prayer and its answer. Al-Fatihah is the prayer from the servant and the Quran is the answer from the Master to the servant's prayer. The servant prays to Allah to show him guidance and the Master places the whole of the Quran before him in answer to his prayer, as if to say, "This is the Guidance you begged from Me."
+
+## 5) Download and Use (Step-by-Step)
+
+1. Download selected package (`csv`, `json`, or `sqlite`).
+2. Import surah records by surah number.
+3. Normalize language/source fields if multiple sources are used.
+4. Separate short summary and detailed content fields in your data model.
+5. If rendering detailed HTML content, sanitize before output in production.
+6. Cache chapter metadata for quick chapter loads.
+7. Render intro card before ayah list.
+
+Starter integration snippet (JavaScript):
+
+```javascript
+const buildSurahInfoIndex = (rows) =>
+ rows.reduce((index, row) => {
+ index[row.surah_id] = row;
+ return index;
+ }, {});
+
+// Use a proper HTML sanitizer in production; this is only a minimal placeholder.
+const sanitizeHtml = (html) =>
+ String(html || "")
+ .replace(/