3 Commits

Author SHA1 Message Date
ODOO4projects Bot ed5119e92f Publish blog post: Local vs International Donors: Fundraising communication in 2026 2026-03-27 08:29:23 +00:00
ODOO4projects Bot bc33287967 Publish blog post: Low-cost Donor CRM Migration for Small NGOs (2026-03-27) 2026-03-27 08:22:26 +00:00
ODOO4projects Bot 0e1b73f6d3 Add blog post: local vs international donors 2026 2026-03-26 21:34:08 +00:00
24 changed files with 1909 additions and 7212 deletions
-21
View File
@@ -1,21 +0,0 @@
# Dependencies
node_modules/
# Tailwind build temp
tmp.json
# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# OS
.DS_Store
Thumbs.db
# Editor
.vscode/
.idea/
*.swp
*.swo
-233
View File
@@ -1,233 +0,0 @@
# AGENTS.md — NGO Landing Page
Read this file fully before taking any action.
---
## Project Context
Single-page static landing page for an NGO ERP product.
| Item | Detail |
|---|---|
| Pages | `index.html` — the only HTML file |
| Styling | Tailwind CSS v3 · source `src/input.css` → compiled `assets/site.css` |
| Data | `blog.json` — flat array of blog posts, loaded at runtime by inline JS |
| i18n | Inline `translations` object inside `index.html` (EN / ES / DE) |
| Blog renderer | Inline `<script>` in `index.html` — no external JS files |
| Dev server | `./start` (runs `live-server`) |
| Git remote | `git@git.odoo4projects.com:Oliver/NGO.git` |
### File map
```
index.html ← only HTML file — layout + all inline JS + i18n
src/input.css ← Tailwind source (edit here, then rebuild)
assets/site.css ← compiled output — DO NOT edit by hand
blog.json ← English blog posts (canonical + fallback)
blog.es.json ← Spanish blog posts
blog.de.json ← German blog posts
tailwind.config.js ← design tokens (colors, fonts, shadows)
```
### Design tokens (from `tailwind.config.js`)
| Token | Hex | Usage |
|---|---|---|
| `brand-ink` | `#201824` | default text / dark backgrounds |
| `brand-primary` | `#603F57` | section labels, bullet accents |
| `brand-accent` | `#F762B4` | CTA buttons, links |
| `brand-sunrise` | `#F8B84A` | hero highlights, hover states |
| `brand-emerald` | `#39B982` | positive indicators |
| `brand-snow` | `#F5F2F7` | page background |
| `brand-smoke` | `#E5DCE8` | borders, subtle dividers |
NEVER use raw hex values in HTML — always use the token class names above.
---
## 🎯 Goal
- Deliver an **SEO-optimised, fast-loading, responsive** single-page site.
- Keep all edits **minimal and targeted** — preserve design, structure, and functionality.
- NEVER introduce new frameworks, libraries, or external dependencies.
### Quality bar for every change
| Concern | Rule |
|---|---|
| SEO | Keep all existing meta tags, `ld+json`, `alt` attributes, and heading hierarchy |
| Performance | No comments in production HTML, no unused CSS classes, no render-blocking additions |
| Responsive | Every element must work on mobile (375 px), tablet (768 px), and desktop (1280 px+) |
| Consistency | Use only brand token classes; match existing spacing and rounding patterns |
---
## Commands
```bash
# Build CSS after editing src/input.css or tailwind.config.js
npm run build:css
# Watch CSS during active development
npm run watch:css
# Validate blog.json
jq empty blog.json && echo "JSON valid"
# Start dev server
./start
```
---
## Git Rules
- ALWAYS work on **`main`** branch.
- Pull before every session:
```bash
git pull origin main
```
- Commit messages must follow the pattern:
- `blog: add post <title>`
- `fix: <short description>`
- `content: <short description>`
- Push immediately after committing — never leave unpushed commits.
- Branch creation is permitted ONLY under the **Branch Handling Exception** (see bottom).
---
## File Safety Rules
- ONLY modify files required for the task.
- NEVER delete or restructure content unrelated to the task.
- NEVER remove existing blog posts from `blog.json`.
- NEVER edit `assets/site.css` directly — always rebuild from `src/input.css`.
---
## Blog Post Schema
### Language-to-file mapping
| Language | File loaded | Fallback |
|---|---|---|
| English (`en`) | `blog.json` | — |
| Spanish (`es`) | `blog.es.json` | `blog.json` |
| German (`de`) | `blog.de.json` | `blog.json` |
The loader in `index.html` fetches the language-specific file automatically when the visitor switches language. If a language file is missing or returns an error, it falls back to `blog.json` silently.
`blog.json` is always the **English source and fallback**. Keep all three files structurally identical — same number of posts, same order, translated content only.
---
`blog.json` (and every language variant) is a root-level JSON array. Every post object contains **exactly these five fields**:
```json
[
{
"area": "Automation",
"date": "2026-03-25",
"title": "Article title as plain text",
"teaser": "<p>One or two sentences visible before 'Read more'.</p>",
"content": "<h3>Section</h3><p>Full article as HTML.</p>"
}
]
```
| Field | Type | Constraint |
|---|---|---|
| `area` | plain string | Category label rendered above the title |
| `date` | ISO 8601 (`YYYY-MM-DD`) | Used by `Intl.DateTimeFormat` |
| `title` | plain string | Rendered as `<h3>` — no HTML |
| `teaser` | HTML string | Always visible — wrap in `<p>` tags |
| `content` | HTML string | Revealed by "Read more" toggle — use `<h3>`, `<p>`, `<ul>`, `<li>` |
NEVER add extra fields (`slug`, `author`, `tags`, `excerpt`, `hero_image`, etc.) — they are ignored by the renderer and pollute the file.
### Adding a new blog post (jq method)
> Add to **all three files** in the same session. A post that exists in English but not in Spanish/German will silently fall back to the English version for those visitors — which is acceptable temporarily but should be resolved promptly.
```bash
# 1. Pull latest
git pull origin main
# 2. Backup all blog files once per session
mkdir -p /backup
for f in blog.json blog.es.json blog.de.json; do
cp $f /backup/$f.$(date +%Y%m%d%H%M%S)
done
# 3. Prepend new post to each language file
# $NEW_EN, $NEW_ES, $NEW_DE must each be a valid single post object
jq --argjson new "$NEW_EN" '. = [$new] + .' blog.json > tmp.json && mv tmp.json blog.json
jq --argjson new "$NEW_ES" '. = [$new] + .' blog.es.json > tmp.json && mv tmp.json blog.es.json
jq --argjson new "$NEW_DE" '. = [$new] + .' blog.de.json > tmp.json && mv tmp.json blog.de.json
# 4. Validate all three
jq empty blog.json && echo "blog.json OK"
jq empty blog.es.json && echo "blog.es.json OK"
jq empty blog.de.json && echo "blog.de.json OK"
# 5. Commit and push
git add blog.json blog.es.json blog.de.json
git commit -m "blog: add post <title>"
git push origin main
```
NEVER use Python, Node scripts, or manual text editing to modify `blog.json`.
---
## Execution Workflow
Follow this order for every task:
1. `git pull origin main`
2. Identify the exact files to change — nothing else.
3. Apply minimal edits.
4. If `src/input.css` or `tailwind.config.js` were changed → rebuild CSS.
5. Validate: `jq empty blog.json` for JSON; visual check for HTML.
6. Commit with a descriptive message.
7. `git push origin main`
---
## Success Criteria
- Changes are minimal, validated, and committed.
- `blog.json` is a valid array with exactly five fields per post.
- `assets/site.css` reflects any CSS changes (rebuilt, not hand-edited).
- HTML passes a visual check — layout and design unchanged except for the intended edit.
- All commits pushed to `main`.
---
## Failure Conditions
These actions constitute a failure:
- Refusing to act due to perceived access restrictions.
- Failing to push after committing.
- Adding undeclared fields to `blog.json`.
- Removing or overwriting existing blog posts.
- Editing `assets/site.css` by hand.
- Modifying files outside the scope of the task.
- Leaving a branch open without merging.
---
## Branch Handling Exception
Branch creation is permitted **only** when:
- The task explicitly requires a feature branch, **or**
- A direct push to `main` is blocked by branch protection.
If a branch is created it **must**:
- Follow the naming convention `<type>/<short-description>` (e.g. `fix/blog-json-schema`).
- Be merged into `main` via PR immediately after the task is complete.
- Be deleted after merge — never abandoned.
@@ -0,0 +1,26 @@
Rollback and Recovery Changelog
Timestamp: ${TS}
Actions performed:
- Reset main branch (working tree and HEAD) to commit 6127867d51c9f0e4e86d1d8390081208f45136ab and force-pushed to origin/main.
- Confirmed README.md content matches version at commit 6127867d51.
- Investigated deleted backups: located backups in parent commit 5189b23 and extracted available files into recovered_backups/ directory in the working tree (not yet committed).
- Created this changelog and saved recovered backup files under recovered_backups/ for review.
Recovered backup files:
- backups/index.html.20260324164129.bak -> recovered_backups/index.html.20260324164129.bak (extracted from commit 5189b23)
- backups/index.html.bak.20260324164053 -> recovered_backups/index.html.bak.20260324164053 (extracted from commit 5189b23)
Notes on recovery:
- The deleted backup files were present in previous commits and have been extracted from git history into recovered_backups/.
- Additional backup files referencing other timestamps exist in git history (e.g., backups/index.html.20260324164556.bak and backups/index.html.20260324164626.bak). These can be extracted on request.
Suspicious findings:
- Commit 6127867d51 (message: "Deleted Backups and changed readme") removed backup files. Author: Oliver. This commit may be responsible for missing backups. Please confirm whether this deletion was authorized.
Remaining tasks / recommendations:
- Decide whether to reintroduce recovered backups into main branch. Restoring them to main will create a new commit on top of 6127867d51 (this changelog can be used), or they can be provided in a separate branch or as artifacts.
- If you want me to commit the recovered_backups/ content and this changelog to the repository and push, confirm and I will proceed.
- If you prefer the repository to remain exactly at 6127867d51 (no additional commits), I will not commit recovered files; instead I will provide them separately (download/attach) and leave main at the rollback state.
+50
View File
@@ -0,0 +1,50 @@
# NGO Website — ODOO4projects
**Project:** NGO marketing homepage and blog
**URL:** [ngo.odoo4projects.com](https://ngo.odoo4projects.com)
**Stack:** Static HTML · Tailwind CSS · Vanilla JS
---
## BLOG POSTS
Blog posts live in `blog.json` — do not create separate backup files.
To add a blog post customize this command
jq '.arrays[0] = [$NEW_JSON] + .arrays[0]' blog.json > tmp.json && mv tmp.json blog.json
## Repository Rules
- Do not touch this readme
- Keep the seperation of Site and the blogposts in blog.json
Example of JSON structure for blog.json
{
"area": "Transparency",
"title": "Every Peso on the Page: Ana's Ledger Story",
"teaser": "<p>Ana replaced five notebooks with a four-stop impact ledger and now answers donor questions in seconds.</p>",
"content": "<h3>Every peso needs a map</h3>\n<p>Ana used to juggle five notebooks and still felt blind when a donor asked where their coin landed.</p>\n<h3>Pressure points</h3>\n<p without late nights.</p>\n",
"date": "2026-03-22"
},
---
## Page Structure
| # | Block | Purpose |
|---|-------|---------|
| 1 | **Hero** | Headline, subheadline, free-trial CTA, key stats |
| 2 | **Hot NGO Topics** | Three focused topic cards (transparency, communications, fundraising) |
| 3 | **Blog** | Latest articles loaded dynamically from `blog.json` |
| 4 | **Sign Up — Free Trial** | Email signup form, 4-week free trial, no credit card |
| 5 | **Have a Meeting** | 30-minute consultation booking via Google Calendar |
---
## Languages
| Code | Language |
|------|----------|
| `en` | English (default) |
| `es` | Español |
| `de` | Deutsch |
All UI strings are managed via the inline `translations` object in `index.html`.
+1
View File
File diff suppressed because one or more lines are too long
+188
View File
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

-1
View File
@@ -1 +0,0 @@
google-site-verification: google261cafffa78d8c3d.html
-114
View File
@@ -1,114 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-1152,-256)">
<rect id="Icons" x="0" y="0" width="1280" height="800" style="fill:none;"/>
<g id="Icons1" serif:id="Icons">
<g id="Strike">
</g>
<g id="H1">
</g>
<g id="H2">
</g>
<g id="H3">
</g>
<g id="list-ul">
</g>
<g id="hamburger-1">
</g>
<g id="hamburger-2">
</g>
<g id="list-ol">
</g>
<g id="list-task">
</g>
<g id="trash">
</g>
<g id="vertical-menu">
</g>
<g id="horizontal-menu">
</g>
<g id="sidebar-2">
</g>
<g id="Pen">
</g>
<g id="Pen1" serif:id="Pen">
</g>
<g id="clock">
</g>
<g id="external-link">
</g>
<g id="hr">
</g>
<g id="info">
</g>
<g id="warning">
</g>
<g id="plus-circle">
</g>
<g id="minus-circle">
</g>
<g id="vue">
</g>
<g id="cog">
</g>
<g id="logo">
</g>
<g id="radio-check">
</g>
<g id="eye-slash">
</g>
<g id="eye">
</g>
<g id="toggle-off">
</g>
<g id="shredder">
</g>
<g id="spinner--loading--dots-" serif:id="spinner [loading, dots]">
</g>
<g id="react">
</g>
<g id="check-selected">
</g>
<g id="turn-off">
</g>
<g id="code-block">
</g>
<g id="user">
</g>
<g id="coffee-bean">
</g>
<g transform="matrix(0.638317,0.368532,-0.368532,0.638317,785.021,-208.975)">
<g id="coffee-beans">
<g id="coffee-bean1" serif:id="coffee-bean">
</g>
</g>
</g>
<g id="coffee-bean-filled" transform="matrix(0.866025,0.5,-0.5,0.866025,717.879,-387.292)">
<g transform="matrix(1,0,0,1,0,-0.699553)">
<path d="M737.673,328.231C738.494,328.056 739.334,328.427 739.757,329.152C739.955,329.463 740.106,329.722 740.106,329.722C740.106,329.722 745.206,338.581 739.429,352.782C737.079,358.559 736.492,366.083 738.435,371.679C738.697,372.426 738.482,373.258 737.89,373.784C737.298,374.31 736.447,374.426 735.735,374.077C730.192,371.375 722.028,365.058 722.021,352C722.015,340.226 728.812,330.279 737.673,328.231Z"/>
</g>
<g transform="matrix(-1,0,0,-1,1483.03,703.293)">
<path d="M737.609,328.246C738.465,328.06 739.344,328.446 739.785,329.203C739.97,329.49 740.106,329.722 740.106,329.722C740.106,329.722 745.206,338.581 739.429,352.782C737.1,358.507 736.503,365.948 738.383,371.527C738.646,372.304 738.415,373.164 737.796,373.703C737.177,374.243 736.294,374.356 735.56,373.989C730.02,371.241 722.028,364.92 722.021,352C722.016,340.255 728.779,330.328 737.609,328.246Z"/>
</g>
</g>
<g transform="matrix(0.638317,0.368532,-0.368532,0.638317,913.062,-208.975)">
<g id="coffee-beans-filled">
<g id="coffee-bean2" serif:id="coffee-bean">
</g>
</g>
</g>
<g id="clipboard">
</g>
<g transform="matrix(1,0,0,1,128.011,1.35415)">
<g id="clipboard-paste">
</g>
</g>
<g id="clipboard-copy">
</g>
<g id="Layer1">
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

-224
View File
@@ -1,224 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
fill="#000000"
width="800px"
height="800px"
viewBox="0 0 64 64"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
id="svg6"
sodipodi:docname="bean_dark_Roast.svg"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:serif="http://www.serif.com/"><defs
id="defs6" /><sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.075"
inkscape:cx="400"
inkscape:cy="400"
inkscape:window-width="1920"
inkscape:window-height="1129"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<g
transform="matrix(1,0,0,1,-1152,-256)"
id="g6">
<rect
id="Icons"
x="0"
y="0"
width="1280"
height="800"
style="fill:none;" />
<g
id="Icons1"
serif:id="Icons">
<g
id="Strike">
</g>
<g
id="H1">
</g>
<g
id="H2">
</g>
<g
id="H3">
</g>
<g
id="list-ul">
</g>
<g
id="hamburger-1">
</g>
<g
id="hamburger-2">
</g>
<g
id="list-ol">
</g>
<g
id="list-task">
</g>
<g
id="trash">
</g>
<g
id="vertical-menu">
</g>
<g
id="horizontal-menu">
</g>
<g
id="sidebar-2">
</g>
<g
id="Pen">
</g>
<g
id="Pen1"
serif:id="Pen">
</g>
<g
id="clock">
</g>
<g
id="external-link">
</g>
<g
id="hr">
</g>
<g
id="info">
</g>
<g
id="warning">
</g>
<g
id="plus-circle">
</g>
<g
id="minus-circle">
</g>
<g
id="vue">
</g>
<g
id="cog">
</g>
<g
id="logo">
</g>
<g
id="radio-check">
</g>
<g
id="eye-slash">
</g>
<g
id="eye">
</g>
<g
id="toggle-off">
</g>
<g
id="shredder">
</g>
<g
id="spinner--loading--dots-"
serif:id="spinner [loading, dots]">
</g>
<g
id="react">
</g>
<g
id="check-selected">
</g>
<g
id="turn-off">
</g>
<g
id="code-block">
</g>
<g
id="user">
</g>
<g
id="coffee-bean">
</g>
<g
transform="matrix(0.638317,0.368532,-0.368532,0.638317,785.021,-208.975)"
id="g1">
<g
id="coffee-beans">
<g
id="coffee-bean1"
serif:id="coffee-bean">
</g>
</g>
</g>
<g
id="coffee-bean-filled"
transform="matrix(0.866025,0.5,-0.5,0.866025,717.879,-387.292)">
<g
transform="matrix(1,0,0,1,0,-0.699553)"
id="g2">
<path
d="M737.673,328.231C738.494,328.056 739.334,328.427 739.757,329.152C739.955,329.463 740.106,329.722 740.106,329.722C740.106,329.722 745.206,338.581 739.429,352.782C737.079,358.559 736.492,366.083 738.435,371.679C738.697,372.426 738.482,373.258 737.89,373.784C737.298,374.31 736.447,374.426 735.735,374.077C730.192,371.375 722.028,365.058 722.021,352C722.015,340.226 728.812,330.279 737.673,328.231Z"
id="path1"
style="fill:#3e2723;fill-opacity:1" />
</g>
<g
transform="matrix(-1,0,0,-1,1483.03,703.293)"
id="g3">
<path
d="M737.609,328.246C738.465,328.06 739.344,328.446 739.785,329.203C739.97,329.49 740.106,329.722 740.106,329.722C740.106,329.722 745.206,338.581 739.429,352.782C737.1,358.507 736.503,365.948 738.383,371.527C738.646,372.304 738.415,373.164 737.796,373.703C737.177,374.243 736.294,374.356 735.56,373.989C730.02,371.241 722.028,364.92 722.021,352C722.016,340.255 728.779,330.328 737.609,328.246Z"
id="path2"
style="stroke:#3e2723;stroke-opacity:1;fill:#3e2723;fill-opacity:1" />
</g>
</g>
<g
transform="matrix(0.638317,0.368532,-0.368532,0.638317,913.062,-208.975)"
id="g4">
<g
id="coffee-beans-filled">
<g
id="coffee-bean2"
serif:id="coffee-bean">
</g>
</g>
</g>
<g
id="clipboard">
</g>
<g
transform="matrix(1,0,0,1,128.011,1.35415)"
id="g5">
<g
id="clipboard-paste">
</g>
</g>
<g
id="clipboard-copy">
</g>
<g
id="Layer1">
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.4 KiB

-224
View File
@@ -1,224 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
fill="#000000"
width="800px"
height="800px"
viewBox="0 0 64 64"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
id="svg6"
sodipodi:docname="bean_light_brown.svg"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:serif="http://www.serif.com/"><defs
id="defs6" /><sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.075"
inkscape:cx="400"
inkscape:cy="400"
inkscape:window-width="1920"
inkscape:window-height="1129"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<g
transform="matrix(1,0,0,1,-1152,-256)"
id="g6">
<rect
id="Icons"
x="0"
y="0"
width="1280"
height="800"
style="fill:none;" />
<g
id="Icons1"
serif:id="Icons">
<g
id="Strike">
</g>
<g
id="H1">
</g>
<g
id="H2">
</g>
<g
id="H3">
</g>
<g
id="list-ul">
</g>
<g
id="hamburger-1">
</g>
<g
id="hamburger-2">
</g>
<g
id="list-ol">
</g>
<g
id="list-task">
</g>
<g
id="trash">
</g>
<g
id="vertical-menu">
</g>
<g
id="horizontal-menu">
</g>
<g
id="sidebar-2">
</g>
<g
id="Pen">
</g>
<g
id="Pen1"
serif:id="Pen">
</g>
<g
id="clock">
</g>
<g
id="external-link">
</g>
<g
id="hr">
</g>
<g
id="info">
</g>
<g
id="warning">
</g>
<g
id="plus-circle">
</g>
<g
id="minus-circle">
</g>
<g
id="vue">
</g>
<g
id="cog">
</g>
<g
id="logo">
</g>
<g
id="radio-check">
</g>
<g
id="eye-slash">
</g>
<g
id="eye">
</g>
<g
id="toggle-off">
</g>
<g
id="shredder">
</g>
<g
id="spinner--loading--dots-"
serif:id="spinner [loading, dots]">
</g>
<g
id="react">
</g>
<g
id="check-selected">
</g>
<g
id="turn-off">
</g>
<g
id="code-block">
</g>
<g
id="user">
</g>
<g
id="coffee-bean">
</g>
<g
transform="matrix(0.638317,0.368532,-0.368532,0.638317,785.021,-208.975)"
id="g1">
<g
id="coffee-beans">
<g
id="coffee-bean1"
serif:id="coffee-bean">
</g>
</g>
</g>
<g
id="coffee-bean-filled"
transform="matrix(0.866025,0.5,-0.5,0.866025,717.879,-387.292)">
<g
transform="matrix(1,0,0,1,0,-0.699553)"
id="g2">
<path
d="M737.673,328.231C738.494,328.056 739.334,328.427 739.757,329.152C739.955,329.463 740.106,329.722 740.106,329.722C740.106,329.722 745.206,338.581 739.429,352.782C737.079,358.559 736.492,366.083 738.435,371.679C738.697,372.426 738.482,373.258 737.89,373.784C737.298,374.31 736.447,374.426 735.735,374.077C730.192,371.375 722.028,365.058 722.021,352C722.015,340.226 728.812,330.279 737.673,328.231Z"
id="path1"
style="fill:#5d4037;fill-opacity:1" />
</g>
<g
transform="matrix(-1,0,0,-1,1483.03,703.293)"
id="g3">
<path
d="M737.609,328.246C738.465,328.06 739.344,328.446 739.785,329.203C739.97,329.49 740.106,329.722 740.106,329.722C740.106,329.722 745.206,338.581 739.429,352.782C737.1,358.507 736.503,365.948 738.383,371.527C738.646,372.304 738.415,373.164 737.796,373.703C737.177,374.243 736.294,374.356 735.56,373.989C730.02,371.241 722.028,364.92 722.021,352C722.016,340.255 728.779,330.328 737.609,328.246Z"
id="path2"
style="stroke:#5d4037;stroke-opacity:1;fill:#5d4037;fill-opacity:1" />
</g>
</g>
<g
transform="matrix(0.638317,0.368532,-0.368532,0.638317,913.062,-208.975)"
id="g4">
<g
id="coffee-beans-filled">
<g
id="coffee-bean2"
serif:id="coffee-bean">
</g>
</g>
</g>
<g
id="clipboard">
</g>
<g
transform="matrix(1,0,0,1,128.011,1.35415)"
id="g5">
<g
id="clipboard-paste">
</g>
</g>
<g
id="clipboard-copy">
</g>
<g
id="Layer1">
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.4 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

-116
View File
@@ -1,116 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="124.8711mm"
height="31.440542mm"
viewBox="0 0 124.8711 31.440542"
version="1.1"
id="svg1"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
sodipodi:docname="logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.70021044"
inkscape:cx="329.90082"
inkscape:cy="345.61039"
inkscape:window-width="1920"
inkscape:window-height="1046"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-17.727083,-56.885417)">
<g
id="g5"
transform="matrix(0.26458333,0,0,0.26458333,-67.310852,25.675979)">
<text
id="text5"
xml:space="preserve"
transform="matrix(1.3333333,0,0,1.3333333,316.00667,186.29426)"><tspan
id="tspan5"
style="font-variant:normal;font-weight:700;font-size:65.991px;font-family:'Noto Sans';writing-mode:lr-tb;fill:#3e2723;fill-opacity:1;fill-rule:nonzero;stroke:#3e2723;stroke-width:2.19965;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
x="0"
y="0">my</tspan></text>
<text
id="text6"
xml:space="preserve"
transform="matrix(1.3333333,0,0,1.3333333,452.48533,186.29426)"><tspan
id="tspan6"
style="font-variant:normal;font-weight:700;font-size:65.991px;font-family:'Noto Sans';writing-mode:lr-tb;fill:#e65100;fill-opacity:1;fill-rule:nonzero;stroke:#e65100;stroke-width:2.19965;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
x="0"
y="0">-</tspan></text>
<text
id="text7"
xml:space="preserve"
transform="matrix(1.3333333,0,0,1.3333333,480.79333,186.29426)"><tspan
id="tspan7"
style="font-variant:normal;font-weight:700;font-size:65.991px;font-family:'Noto Sans';writing-mode:lr-tb;fill:#3e2723;fill-opacity:1;fill-rule:nonzero;stroke:#3e2723;stroke-width:2.19965;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
x="0"
y="0">biz</tspan></text>
<text
id="text8"
xml:space="preserve"
transform="matrix(1.3333333,0,0,1.3333333,606.236,186.29426)"><tspan
id="tspan8"
style="font-variant:normal;font-weight:700;font-size:65.991px;font-family:'Noto Sans';writing-mode:lr-tb;fill:#e65100;fill-opacity:1;fill-rule:nonzero;stroke:#e65100;stroke-width:2.19965;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
x="0"
y="0">.app</tspan></text>
</g>
<g
id="g8"
transform="matrix(0.26458333,0,0,0.26458333,-67.310852,25.675979)">
<path
id="path8"
d="M 249.449,279.212 H 391.181"
style="fill:none;stroke:#e65100;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,0,595.27559)" />
</g>
<g
id="g9"
transform="matrix(0.26458333,0,0,0.26458333,-67.310852,25.675979)">
<path
id="path9"
d="M 442.205,279.212 H 583.937"
style="fill:none;stroke:#e65100;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,0,595.27559)" />
</g>
<g
id="g10"
transform="matrix(0.26458333,0,0,0.26458333,-67.310852,25.675979)">
<path
id="path10"
d="m 420.661,289.332 c 0.369,-0.114 0.596,-0.454 0.596,-0.822 0.028,-0.171 0.028,-0.284 0.028,-0.284 0,0 -0.028,-4.535 -5.386,-8.702 -2.182,-1.701 -4.053,-4.451 -4.564,-7.03 -0.056,-0.34 -0.311,-0.624 -0.652,-0.681 -0.368,-0.085 -0.708,0.057 -0.907,0.369 -1.53,2.268 -3.259,6.491 -0.368,11.48 2.608,4.536 7.427,6.832 11.253,5.67 z"
style="fill:#3e2723;fill-opacity:1;fill-rule:evenodd;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,0,595.27559)" />
<path
id="path11"
d="m 413.121,269.376 c -0.368,0.141 -0.623,0.482 -0.623,0.85 0,0.17 0,0.284 0,0.284 0,0 0,4.535 5.357,8.702 2.154,1.672 4.054,4.394 4.564,6.945 0.057,0.368 0.34,0.623 0.709,0.708 0.34,0.057 0.708,-0.085 0.907,-0.396 1.53,-2.268 3.174,-6.463 0.34,-11.424 -2.608,-4.507 -7.399,-6.803 -11.254,-5.669 z"
style="fill:#3e2723;fill-opacity:1;fill-rule:evenodd;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,0,595.27559)" />
<path
id="path12"
d="m 413.121,269.376 c -0.368,0.141 -0.623,0.482 -0.623,0.85 0,0.17 0,0.284 0,0.284 0,0 0,4.535 5.357,8.702 2.154,1.672 4.054,4.394 4.564,6.945 0.057,0.368 0.34,0.623 0.709,0.708 0.34,0.057 0.708,-0.085 0.907,-0.396 1.53,-2.268 3.174,-6.463 0.34,-11.424 -2.608,-4.507 -7.399,-6.803 -11.254,-5.669 z"
style="fill:none;stroke:#3e2723;stroke-width:0.4428;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,0,595.27559)" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.8 KiB

+553 -4601
View File
File diff suppressed because it is too large Load Diff
+1027
View File
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
{
"name": "ngo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git@git.odoo4projects.com:Oliver/NGO.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"devDependencies": {
"tailwindcss": "^3.4.17"
}
}
-47
View File
File diff suppressed because one or more lines are too long
View File
-1
View File
@@ -1 +0,0 @@
{"area": "CRM", "Vertical": "NGO", "date": "2026-05-04", "title": "Impact Reporting in Minutes", "teaser": "Small NGOs waste countless hours turning donor data into reports—instead of serving those theyre meant to help.", "content": "<article>\n<h2>Impact Reporting in Minutes</h2>\n<p style=\"margin: 0; color: #374151;\">— \"Maria stared at her screen at 11 p.m., three days before the grant deadline. Her donor database had 872 entries. Excel had 14 tabs. She hadnt slept in 36 hours. Every email from a donor—How was the clean water project?—demanded a new report. She couldnt tell them. Not without weeks of work. <strong>Spreadsheets</strong> were drowning her. <strong>Manual reporting</strong> was stealing her purpose. And worst of all—she knew donors were slipping away, not because her work wasnt impactful, but because she couldnt prove it.\" —</p>\n\n<p style=\"margin: 0; color: #374151;\">Modern digital tools can transform how NGOs capture and communicate impact. Automated systems can pull data from donations, program logs, and field reports into unified dashboards. Reports once built by hand can now be generated with a single click, reducing errors, saving weeks of labor, and preserving the emotional integrity of the stories behind the numbers.</p>\n\n<h3>Stop drowning in spreadsheets. Start telling stories.</h3>\n<p style=\"margin: 0; color: #374151;\">When your team spends 20 hours a week just compiling donor data, youre not serving beneficiaries—youre serving Excel. Automated reporting tools reset that balance. They sync with your existing donation platforms, track program outcomes across locations, and turn fragmented inputs into cohesive, real-time narratives that donors actually read.</p>\n\n<h3>Trust isnt built with PDFs. Its built with clarity.</h3>\n<p style=\"margin: 0; color: #374151;\">Donors dont want line items. They want to know lives changed. A clean, automated dashboard shows a childs progress in school, not just the $50 spent on textbooks. When you can show, not tell, donors see their values reflected in real results. Thats how <strong>retention grows</strong>—not through emails begging for more, but through transparency that feels genuine.</p>\n\n<h3>Proof that matters. Without the panic.</h3>\n<p style=\"margin: 0; color: #374151;\">Grant applications and board reviews require compliance—not creativity. When audit season rolls around, having pre-built, audit-ready templates means your finance lead isnt working through the night. No more frantic last-minute data fixes. Just a few clicks, and your compliance is done. That peace of mind? Its priceless.</p>\n\n<div class=\"video-container\" style=\"display: flex; margin: 2rem 0; gap: 2rem;\">\n <div class=\"video-text\" style=\"flex: 1;\">\n <p style=\"margin: 0; color: #374151;\">This is how you generate an impact report for your donors—no more spreadsheets, no more stress. Just one click, and your story goes live.</p>\n </div>\n <div class=\"video-player\" style=\"flex: 1; min-width: 300px; height: 300px;\">\n <iframe width=\"100%\" height=\"100%\"\n src=\"https://www.youtube.com/embed/huVrXvkCAqg\"\n title=\"YouTube video player\"\n frameborder=\"0\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n allowfullscreen\n style=\"width: 100%; height: 100%; border-radius: 8px;\">\n </iframe>\n </div>\n</div>\n\n<p style=\"margin: 0; color: #374151;\"><em>Remember: Every hour you spend wrestling with data is an hour taken from the field, the classroom, the clinic.</em></p>\n\n<a class=\"cta\" href=\"https://calendar.google.com/calendar/u/0/appointments/schedules/AcZssZ3DDbaiHFlhNhWySszAQoPXE_H73QLqYT3w7H9IYWC76RA_TgNIhLESjb4N7ep_D2D_OyW9q4-c\">When you want to explore how this could work for your organization, you can book a meeting here:</a>\n</article>", "image": "ngo_office3"}
View File
+17
View File
@@ -0,0 +1,17 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
}
#lang-selector {
color: #ffffff;
}
#lang-selector:focus,
#lang-selector:focus-visible {
color: #201824;
background-color: #ffffff;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

-1630
View File
File diff suppressed because it is too large Load Diff
+27
View File
@@ -0,0 +1,27 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./index.html'],
theme: {
extend: {
colors: {
'brand-ink': '#201824',
'brand-primary': '#603F57',
'brand-accent': '#F762B4',
'brand-sunrise': '#F8B84A',
'brand-emerald': '#39B982',
'brand-snow': '#F5F2F7',
'brand-smoke': '#E5DCE8'
},
fontFamily: {
brand: ['Inter', 'Segoe UI', 'system-ui', 'sans-serif']
},
boxShadow: {
brand: '0 20px 60px rgba(32, 24, 36, 0.15)'
},
backgroundImage: {
'hero-gradient': 'radial-gradient(circle at top left, rgba(247,98,180,0.35), rgba(32,24,36,0.95))'
}
}
},
plugins: []
};