diff --git a/.agents/memory/MEMORY.md b/.agents/memory/MEMORY.md
index 367778f..3c2a28a 100644
--- a/.agents/memory/MEMORY.md
+++ b/.agents/memory/MEMORY.md
@@ -1,2 +1,3 @@
- [Donate semantics](donate-semantics.md) — donations accumulate + clamp to target; a case enters the closed-loop pipeline only when fully funded.
- [api-server data](api-server-data.md) — mockDb is in-memory and mutated by POST calls; restart the workflow to reset to clean seed for demos.
+- [EHSAN branding](ehsan-branding.md) — ehsan.sa blocks scraping; font is IBM Plex Sans Arabic (best match), currency uses new Saudi Riyal symbol via mask component.
diff --git a/.agents/memory/ehsan-branding.md b/.agents/memory/ehsan-branding.md
new file mode 100644
index 0000000..43e1660
--- /dev/null
+++ b/.agents/memory/ehsan-branding.md
@@ -0,0 +1,13 @@
+---
+name: EHSAN branding (ehsan.sa)
+description: Font, currency symbol, and hero conventions for matching the official ehsan.sa look.
+---
+
+# Matching ehsan.sa
+
+- **Font:** the POC uses `IBM Plex Sans Arabic` (Google Fonts) as the closest official-looking match. ehsan.sa's exact webfont could NOT be auto-detected — the live site blocks server-side access (Firecrawl returns ERR_TUNNEL_CONNECTION_FAILED, curl with a browser UA returns nothing, and the Wayback Machine has no snapshot). If the font ever needs to be exact, ask the user to read it from browser DevTools (Computed > font-family).
+- **Currency = new Saudi Riyal symbol**, not the legacy `﷼` glyph and not the word "ريال". It is rendered by the `` component (`src/components/Riyal.tsx`) which masks a processed PNG (`src/assets/riyal.png`) with `mask-image` + `background-color: currentColor`, so it inherits the surrounding text color and font size. The symbol is decorative (`aria-hidden`) since the adjacent number conveys the value.
+
+**Why:** the user explicitly flagged the wrong font, the wrong currency symbol, and a non-official hero. The riyal mask approach was chosen because font/Unicode support for the new symbol is unreliable; masking the user-provided glyph guarantees it matches their reference and recolors anywhere.
+
+**How to apply:** put the amount number first, then `` (e.g. `{amount.toLocaleString()} `). The home hero should be a full-bleed green (`bg-primary`) banner with a badge, title/subtitle, and CTAs — not a gray search box.
diff --git a/.replit b/.replit
index ade20b3..b4c57e8 100644
--- a/.replit
+++ b/.replit
@@ -1,4 +1,4 @@
-modules = ["nodejs-24"]
+modules = ["nodejs-24", "python-3.11"]
[deployment]
router = "application"
diff --git a/artifacts/ehsan-poc/index.html b/artifacts/ehsan-poc/index.html
index 22123dd..359e252 100644
--- a/artifacts/ehsan-poc/index.html
+++ b/artifacts/ehsan-poc/index.html
@@ -15,7 +15,7 @@
-
+
diff --git a/artifacts/ehsan-poc/src/assets/riyal.png b/artifacts/ehsan-poc/src/assets/riyal.png
new file mode 100644
index 0000000..c5b951a
Binary files /dev/null and b/artifacts/ehsan-poc/src/assets/riyal.png differ
diff --git a/artifacts/ehsan-poc/src/components/OpportunityCard.tsx b/artifacts/ehsan-poc/src/components/OpportunityCard.tsx
index 69a2d2e..e8f4569 100644
--- a/artifacts/ehsan-poc/src/components/OpportunityCard.tsx
+++ b/artifacts/ehsan-poc/src/components/OpportunityCard.tsx
@@ -5,6 +5,7 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Share2, ShoppingCart } from "lucide-react";
import { getNeedImage } from "../lib/needImages";
+import { Riyal } from "@/components/Riyal";
interface OpportunityCardProps {
request: {
@@ -17,8 +18,6 @@ interface OpportunityCardProps {
};
}
-const RIYAL = "﷼";
-
export function OpportunityCard({ request }: OpportunityCardProps) {
const { t } = useLanguage();
const [, setLocation] = useLocation();
@@ -78,14 +77,14 @@ export function OpportunityCard({ request }: OpportunityCardProps) {