diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..c0d283b
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,59 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Project Overview
+
+Mizu (水) is a FileMaker theme and add-on by Proof+Geist, inspired by Material Design and IBM Carbon. It targets FileMaker 19+ and ships as a `.fmaddon` archive with a companion `.fmp12` helper file.
+
+## Build Process
+
+The build is a hybrid manual/scripted process — theme changes happen inside FileMaker, then XML is cleaned up and packaged:
+
+1. Update theme in FileMaker (foundations-dev file)
+2. Update version in `mizu_theme::__versionString` and `FMAddonTemplate_Version` on `__FMdAddonTemplate_Metadata` layout
+3. Export via "Generate Add-on" in FileMaker (outputs to `~/Library/Application Support/FileMaker/Extensions/AddonModules`)
+4. Copy `proof_mizu_theme/` folder to project root
+5. Clean up extraneous XML (see below)
+6. Build the archive: `source build.sh`
+
+### Build Command
+
+```
+source build.sh
+```
+
+Requires `xar` utility. Creates `proof_mizu_theme.fmaddon` from the `proof_mizu_theme/` directory.
+
+### XML Cleanup After Export
+
+FileMaker generates duplicate objects that must be manually removed. Use VSCode compare against `previous/` versions to detect diffs. Key fixes:
+
+- **Portals layout**: Remove 2 extra buttons in Portal UUID `47F1ED16-...`, set membercount to 5
+- **Tabs layout**: Remove 3 duplicate button bar buttons in SlidePanel UUID `B2C37ECE-...`, set membercount to 14
+- **List layout**: Remove 2 extra objects in Portal, set membercount to 3
+
+See `build-how-to.md` for exact XPaths and UUIDs.
+
+### Testing
+
+1. Uninstall existing mizu add-on in FileMaker
+2. Delete `.fmaddon` file and `proof_mizu_theme/` from FileMaker's `Extensions/AddonModules` directory
+3. Double-click the new `.fmaddon` to install
+4. Create a new FileMaker file, add the add-on, verify no duplicate buttons on Portal/List/Tabs layouts
+
+## Architecture
+
+This is an XML/JSON-based theme definition, not a traditional code project.
+
+### Key Files
+
+- **`proof_mizu_theme/template.xml`** — Main theme definition (~7,000 lines). Contains structure definitions (FieldCatalog, LayoutCatalog with 13 layouts) and literal content in CDATA sections. **Do not modify CDATA sections** — it breaks XML folding and risks corrupting the file.
+- **`proof_mizu_theme/info.json`** — Core metadata (GUID, version, supported clients)
+- **`proof_mizu_theme/info_[lang].json`** + **`[lang].xml`** + **`records_[lang].xml`** — Localized strings for 11 languages (en, de, es, fr, it, ja, ko, nl, pt, sv, zh)
+- **`proof_mizu_helper.fmp12`** — Companion helper file (binary, Git LFS tracked)
+- **`previous/`** — Previous template.xml versions kept for diff comparison during builds
+
+### Binary Files
+
+`.fmp12`, `.fmaddon`, and `.zip` files are tracked via Git LFS (configured in `.gitattributes`).
diff --git a/build-shadcn.sh b/build-shadcn.sh
new file mode 100755
index 0000000..e035b85
--- /dev/null
+++ b/build-shadcn.sh
@@ -0,0 +1,9 @@
+#! /bin/bash
+if xar -h &> /dev/null
+then
+ echo "xar could not be found"
+else
+
+ xar -cf proof_shadcn_theme.fmaddon proof_shadcn_theme/
+ echo 'build succesful'
+fi
diff --git a/proof_shadcn_theme.fmaddon b/proof_shadcn_theme.fmaddon
new file mode 100644
index 0000000..c8e21db
--- /dev/null
+++ b/proof_shadcn_theme.fmaddon
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0ffb73b472c5cbcc096e6acb063ea28e972e0a5936e6c1b8cd65353a88f8bc77
+size 693596
diff --git a/proof_shadcn_theme/de.xml b/proof_shadcn_theme/de.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/de.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/en.xml b/proof_shadcn_theme/en.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/en.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/es.xml b/proof_shadcn_theme/es.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/es.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/fr.xml b/proof_shadcn_theme/fr.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/fr.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/icon.png b/proof_shadcn_theme/icon.png
new file mode 100644
index 0000000..3820bad
Binary files /dev/null and b/proof_shadcn_theme/icon.png differ
diff --git a/proof_shadcn_theme/icon@2x.png b/proof_shadcn_theme/icon@2x.png
new file mode 100644
index 0000000..1ad1b26
Binary files /dev/null and b/proof_shadcn_theme/icon@2x.png differ
diff --git a/proof_shadcn_theme/info.json b/proof_shadcn_theme/info.json
new file mode 100644
index 0000000..81c02ce
--- /dev/null
+++ b/proof_shadcn_theme/info.json
@@ -0,0 +1,11 @@
+{
+ "GUID" : "F3A896D8-5322-475C-8206-AA6C4AFD87E4",
+ "Clients" :
+ [
+ "Pro","Go"
+ ],
+ "Attribution" : "Proof+Geist",
+ "URL" : "https://github.com/proofgeist/mizu",
+ "Icon_Color" : "",
+ "Version" : "1.0"
+}
diff --git a/proof_shadcn_theme/info_de.json b/proof_shadcn_theme/info_de.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_de.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_en.json b/proof_shadcn_theme/info_en.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_en.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_es.json b/proof_shadcn_theme/info_es.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_es.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_fr.json b/proof_shadcn_theme/info_fr.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_fr.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_it.json b/proof_shadcn_theme/info_it.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_it.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_ja.json b/proof_shadcn_theme/info_ja.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_ja.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_ko.json b/proof_shadcn_theme/info_ko.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_ko.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_nl.json b/proof_shadcn_theme/info_nl.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_nl.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_pt.json b/proof_shadcn_theme/info_pt.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_pt.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_sv.json b/proof_shadcn_theme/info_sv.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_sv.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/info_zh.json b/proof_shadcn_theme/info_zh.json
new file mode 100644
index 0000000..76e1804
--- /dev/null
+++ b/proof_shadcn_theme/info_zh.json
@@ -0,0 +1,11 @@
+{
+ "Title": "shadcn by Proof+Geist",
+ "Description": "Adds the shadcn theme to your file",
+ "Category": "Themes",
+ "Features": [],
+ "Optimized": [
+ "Desktop",
+ "Tablet",
+ "Mobile"
+ ]
+}
diff --git a/proof_shadcn_theme/it.xml b/proof_shadcn_theme/it.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/it.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/ja.xml b/proof_shadcn_theme/ja.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/ja.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/ko.xml b/proof_shadcn_theme/ko.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/ko.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/nl.xml b/proof_shadcn_theme/nl.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/nl.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/preview.png b/proof_shadcn_theme/preview.png
new file mode 100644
index 0000000..086703b
Binary files /dev/null and b/proof_shadcn_theme/preview.png differ
diff --git a/proof_shadcn_theme/pt.xml b/proof_shadcn_theme/pt.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/pt.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/records_de.xml b/proof_shadcn_theme/records_de.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_de.xml differ
diff --git a/proof_shadcn_theme/records_en.xml b/proof_shadcn_theme/records_en.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_en.xml differ
diff --git a/proof_shadcn_theme/records_es.xml b/proof_shadcn_theme/records_es.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_es.xml differ
diff --git a/proof_shadcn_theme/records_fr.xml b/proof_shadcn_theme/records_fr.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_fr.xml differ
diff --git a/proof_shadcn_theme/records_it.xml b/proof_shadcn_theme/records_it.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_it.xml differ
diff --git a/proof_shadcn_theme/records_ja.xml b/proof_shadcn_theme/records_ja.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_ja.xml differ
diff --git a/proof_shadcn_theme/records_ko.xml b/proof_shadcn_theme/records_ko.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_ko.xml differ
diff --git a/proof_shadcn_theme/records_nl.xml b/proof_shadcn_theme/records_nl.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_nl.xml differ
diff --git a/proof_shadcn_theme/records_pt.xml b/proof_shadcn_theme/records_pt.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_pt.xml differ
diff --git a/proof_shadcn_theme/records_sv.xml b/proof_shadcn_theme/records_sv.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_sv.xml differ
diff --git a/proof_shadcn_theme/records_zh.xml b/proof_shadcn_theme/records_zh.xml
new file mode 100644
index 0000000..e13f76f
Binary files /dev/null and b/proof_shadcn_theme/records_zh.xml differ
diff --git a/proof_shadcn_theme/sv.xml b/proof_shadcn_theme/sv.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/sv.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/proof_shadcn_theme/template.xml b/proof_shadcn_theme/template.xml
new file mode 100644
index 0000000..c82b24d
Binary files /dev/null and b/proof_shadcn_theme/template.xml differ
diff --git a/proof_shadcn_theme/zh.xml b/proof_shadcn_theme/zh.xml
new file mode 100644
index 0000000..ef70b08
--- /dev/null
+++ b/proof_shadcn_theme/zh.xml
@@ -0,0 +1,98 @@
+
+
+ com.fmi.basedirectory.CB285A0FD66A28850057FEB1F4A82D17
+ Mizu/
+ Mizu/
+ com.fmi.basedirectory.Mizu/
+
+
+
+ com.fmi.basetable.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.basetable.__FMAddonTemplate_Metadata
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::1A6F6D8A5D201F2A21420B43C5345AE0
+ __FMAddonTemplate_Version
+ __FMAddonTemplate_Version
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Version
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::3DF4202D460A0197901676D33510E2A9
+ __FMAddonTemplate_GUID
+ __FMAddonTemplate_GUID
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_GUID
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::4C401D80F095E4875C589E7F30613788
+ __FMAddonTemplate_PreviewImage
+ __FMAddonTemplate_PreviewImage
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_PreviewImage
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::58C8AA9702E724A8E8528A4EFD8E39BC
+ __FMAddonTemplate_Icon
+ __FMAddonTemplate_Icon
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Icon
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::5A65B734A19B7A9D40A8E233BCECC32B
+ __FMAddonTemplate_Desc
+ __FMAddonTemplate_Desc
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Desc
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::9C2DB678CD3FAB550FD3E0896225AC19
+ __FMAddonTemplate_Clients
+ __FMAddonTemplate_Clients
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Clients
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::B0F082A2B4B8CD0DD4CC13D936B12D82
+ __FMAddonTemplate_Attribution
+ __FMAddonTemplate_Attribution
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Attribution
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::BF67E2BFE93D889A4BB3ACAEF0833675
+ __FMAddonTemplate_URL
+ __FMAddonTemplate_URL
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_URL
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::C3705CECC929CE96E6BCD1628F27214E
+ __FMAddonTemplate_Title
+ __FMAddonTemplate_Title
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Title
+
+
+
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::DFF29DF31A6BCD82433020A5B2096A06
+ __FMAddonTemplate_Category
+ __FMAddonTemplate_Category
+ com.fmi.basetable.field.__FMAddonTemplate_Metadata::__FMAddonTemplate_Category
+
+
+
+ com.fmi.calculation.text.E06123D571693687770B1259FAD99B28
+ Proof Add-on Module
+ Proof Add-on Module
+ com.fmi.calculation.text.Proof Add-on Module
+
+
+
+ com.fmi.tableoccurrence.A72664F13DDFEACC5F6AAC99DE88BC03
+ __FMAddonTemplate_Metadata
+ __FMAddonTemplate_Metadata
+ com.fmi.tableoccurrence.__FMAddonTemplate_Metadata
+
diff --git a/tools/color_transform.py b/tools/color_transform.py
new file mode 100644
index 0000000..8e4797c
--- /dev/null
+++ b/tools/color_transform.py
@@ -0,0 +1,254 @@
+#!/usr/bin/env python3
+"""
+Color transformation script for shadcn theme.
+
+Reads a FileMaker template.xml (UTF-16 LE with BOM), applies ordered
+find-and-replace on rgba color values within the CSS CDATA block,
+and writes back preserving encoding exactly.
+
+Usage:
+ python3 tools/color_transform.py [--dry-run]
+"""
+
+import re
+import sys
+from collections import OrderedDict
+
+TEMPLATE_PATH = "proof_shadcn_theme/template.xml"
+
+# ─── shadcn target palette (FileMaker rgba format) ───────────────────
+# background: rgba(100%,100%,100%,1) — page/card backgrounds
+# foreground: rgba(14.1%,14.1%,14.1%,1) — primary text
+# primary: rgba(18%,18%,18%,1) — buttons, active states
+# primary-foreground: rgba(98%,98%,98%,1) — text on primary surfaces
+# secondary: rgba(96.1%,96.1%,96.1%,1) — hover backgrounds, alt rows
+# muted-foreground: rgba(56.5%,56.5%,56.5%,1) — placeholders, secondary labels
+# border: rgba(92.2%,92.2%,92.2%,1) — all borders
+# ring: rgba(70.2%,70.2%,70.2%,1) — focus ring
+# destructive: keep current red — error states
+
+# ─── Color mapping ──────────────────────────────────────────────────
+# Order matters: more specific values first to avoid partial replacements.
+# Each entry: (old_rgba, new_rgba, category_description)
+
+COLOR_MAP = OrderedDict([
+ # ── Batch 1: Blue accents → primary (dark gray) ──────────────────
+ # Main blue accent (232 occurrences - biggest single color)
+ ("rgba(14.5098%,40.3922%,96.0784%,1)", "rgba(18%,18%,18%,1)"),
+ # Blue accent with alpha (for subtle backgrounds)
+ ("rgba(14.5098%,40.3922%,96.0784%,0.0740582)", "rgba(18%,18%,18%,0.07)"),
+ # Saturated blues → primary
+ ("rgba(0%,43.9216%,81.1765%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(0%,47.8431%,100%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(0%,25.4095%,80.0784%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(0%,40.1882%,84%,1)", "rgba(18%,18%,18%,1)"),
+ # Darker blues → primary
+ ("rgba(10.1961%,34.5098%,88.2353%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(2.7451%,19.6078%,58.8235%,1)", "rgba(14.1%,14.1%,14.1%,1)"),
+ ("rgba(10.0502%,25.829%,46.7451%,1)", "rgba(14.1%,14.1%,14.1%,1)"),
+ ("rgba(0%,16.0784%,22.3529%,1)", "rgba(14.1%,14.1%,14.1%,1)"),
+
+ # ── Batch 2: Blue-tinted light backgrounds → secondary/neutral ───
+ # Light blue tints → neutral near-white
+ ("rgba(75.2941%,92.9412%,99.6078%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(89.0196%,94.902%,99.2157%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(96.0784%,97.2549%,98.0392%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(95.6863%,96.4706%,98.0392%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(95.6863%,96.8627%,97.6471%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(92.3695%,95.9839%,100%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(90.1961%,93.7255%,97.6471%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(70.1961%,89.4118%,98.8235%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(70.1961%,89.8039%,98.8235%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(98.0392%,98.0392%,100%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ # Cyan/teal-tinted colors → neutral
+ ("rgba(30.1961%,78.8235%,96.0784%,1)", "rgba(70.2%,70.2%,70.2%,1)"),
+ ("rgba(15.6863%,71.3726%,96.4706%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+ ("rgba(16.0784%,71.3726%,96.4706%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+ ("rgba(0%,72.9412%,98.4314%,1)", "rgba(70.2%,70.2%,70.2%,1)"),
+ ("rgba(0%,73.3333%,98.4314%,1)", "rgba(70.2%,70.2%,70.2%,1)"),
+ ("rgba(1.56863%,72.549%,98.4314%,1)", "rgba(70.2%,70.2%,70.2%,1)"),
+ ("rgba(49.4118%,73.7255%,100%,1)", "rgba(70.2%,70.2%,70.2%,1)"),
+ ("rgba(50.1961%,65.8824%,100%,1)", "rgba(70.2%,70.2%,70.2%,1)"),
+ # Teal/green-blue mid-tones → muted-foreground
+ ("rgba(12.549%,62.3529%,80.3922%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+ ("rgba(12.9129%,62.6278%,80.7059%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+ ("rgba(67.2722%,76.1324%,82.0392%,1)", "rgba(80%,80%,80%,1)"),
+
+ # ── Batch 3: Purple/blue-cast grays → neutral grays ──────────────
+ # Purple-cast grays used in borders and backgrounds
+ ("rgba(78.4314%,78.0392%,80%,1)", "rgba(80%,80%,80%,1)"),
+ ("rgba(78.4314%,77.6471%,80%,1)", "rgba(80%,80%,80%,1)"),
+ ("rgba(93.7255%,93.7255%,95.6863%,1)", "rgba(92.2%,92.2%,92.2%,1)"),
+ ("rgba(97.6471%,96.8627%,98.0392%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(97.7024%,97.1215%,98.1489%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ # Purple-cast mid-grays
+ ("rgba(22.7451%,20.3922%,25.098%,1)", "rgba(22.3529%,22.3529%,22.3529%,1)"),
+ ("rgba(22.9226%,20.6687%,25.1765%,1)", "rgba(22.3529%,22.3529%,22.3529%,1)"),
+ ("rgba(40.7843%,40.3922%,41.1765%,1)", "rgba(38.3529%,38.3529%,38.3529%,1)"),
+ ("rgba(45.098%,44.7059%,45.4902%,1)", "rgba(45.8824%,45.8824%,45.8824%,1)"),
+ ("rgba(45.098%,44.7059%,45.4902%,0.4)", "rgba(45.8824%,45.8824%,45.8824%,0.4)"),
+ ("rgba(45.9162%,56.2971%,60.4495%,0.579236)", "rgba(56.5%,56.5%,56.5%,0.58)"),
+ ("rgba(69.0196%,74.5098%,77.2549%,1)", "rgba(74.1961%,74.1961%,74.1961%,1)"),
+ ("rgba(96.3922%,15.4227%,83.3581%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+ ("rgba(97.1487%,89.2283%,100%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(80.3922%,0%,67.451%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+
+ # ── Batch 4: Text colors → foreground / muted-foreground ────────
+ # Near-black text shades → foreground
+ ("rgba(4.31373%,4.31373%,4.31373%,1)", "rgba(14.1%,14.1%,14.1%,1)"),
+ ("rgba(6.27451%,6.27451%,6.27451%,1)", "rgba(14.1%,14.1%,14.1%,1)"),
+ ("rgba(6.35294%,6.35294%,6.35294%,1)", "rgba(14.1%,14.1%,14.1%,1)"),
+ ("rgba(8.62745%,8.62745%,8.62745%,1)", "rgba(14.1%,14.1%,14.1%,1)"),
+ ("rgba(10.1961%,10.1961%,10.1961%,1)", "rgba(14.1%,14.1%,14.1%,1)"),
+ ("rgba(20.3922%,20.3922%,20.3922%,1)", "rgba(14.1%,14.1%,14.1%,1)"),
+ # Mid-gray text → muted-foreground
+ ("rgba(43.5294%,43.5294%,43.5294%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+ ("rgba(45.8824%,45.8824%,45.8824%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+ ("rgba(51.7647%,51.7647%,51.7647%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+ ("rgba(59.2157%,59.2157%,59.2157%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+ ("rgba(60.3922%,60.3922%,60.3922%,1)", "rgba(56.5%,56.5%,56.5%,1)"),
+
+ # ── Batch 5: Border grays → unified border color ────────────────
+ ("rgba(87.8431%,87.8431%,87.8431%,1)", "rgba(92.2%,92.2%,92.2%,1)"),
+ ("rgba(90.1961%,90.1961%,90.1961%,1)", "rgba(92.2%,92.2%,92.2%,1)"),
+ ("rgba(92.1569%,92.1569%,92.1569%,1)", "rgba(92.2%,92.2%,92.2%,1)"),
+ ("rgba(93.3333%,93.3333%,93.3333%,1)", "rgba(92.2%,92.2%,92.2%,1)"),
+ ("rgba(95.6863%,95.6863%,95.6863%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(96.0784%,96.0784%,96.0784%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+ ("rgba(96.4706%,96.4706%,96.4706%,1)", "rgba(96.1%,96.1%,96.1%,1)"),
+
+ # ── Batch 6: Dark surfaces → foreground ──────────────────────────
+ ("rgba(22.3529%,22.3529%,22.3529%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(25.8824%,25.8824%,25.8824%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(29.8039%,29.8039%,29.8039%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(30.1961%,30.1961%,30.1961%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(36.0784%,36.0784%,36.0784%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(38.0392%,38.0392%,38.0392%,1)", "rgba(18%,18%,18%,1)"),
+ ("rgba(38.3529%,38.3529%,38.3529%,1)", "rgba(18%,18%,18%,1)"),
+])
+
+# Colors to leave alone (no mapping needed, just documenting):
+# rgba(0%,0%,0%,0) — transparent
+# rgba(0%,0%,0%,1) — pure black
+# rgba(100%,100%,100%,0) — transparent white
+# rgba(100%,100%,100%,1) — white
+# rgba(0%,0%,0%,0.101825) — shadow alpha
+# rgba(0%,0%,0%,0.15) — shadow alpha
+# rgba(100%,80%,0%,1) — yellow/warning
+# rgba(42.3529%,10.1961%,9.41177%,1) — destructive dark
+# rgba(66.6667%,17.2549%,16.4706%,1) — destructive
+# rgba(78.8235%,20.3922%,19.6078%,1) — destructive light
+# rgba(78.8235%,20.7843%,19.6078%,1) — destructive light variant
+# rgba(14.1176%,14.1176%,14.1176%,1) — already matches foreground target
+
+
+def read_template(path):
+ """Read UTF-16 LE file with BOM, return (bom_bytes, text)."""
+ with open(path, "rb") as f:
+ raw = f.read()
+
+ # Check for BOM
+ if raw[:2] == b"\xff\xfe":
+ bom = raw[:2]
+ text = raw[2:].decode("utf-16-le")
+ else:
+ bom = b""
+ text = raw.decode("utf-16-le")
+
+ return bom, text
+
+
+def write_template(path, bom, text):
+ """Write back with original BOM and encoding."""
+ with open(path, "wb") as f:
+ f.write(bom)
+ f.write(text.encode("utf-16-le"))
+
+
+def find_css_cdata(text):
+ """Find the CSS CDATA block boundaries. Returns (start, end) of inner content."""
+ # The CSS CDATA starts with "/* Object Styles */"
+ marker = "", cdata_start)
+ if cdata_end == -1:
+ raise ValueError("Could not find end of CSS CDATA block")
+
+ return cdata_start, cdata_end
+
+
+def apply_color_map(css_text, color_map, dry_run=False):
+ """Apply ordered color replacements to CSS text. Returns (new_text, stats)."""
+ stats = OrderedDict()
+ result = css_text
+
+ for old_color, new_color in color_map.items():
+ count = result.count(old_color)
+ if count > 0:
+ if not dry_run:
+ result = result.replace(old_color, new_color)
+ stats[old_color] = {"new": new_color, "count": count}
+
+ return result, stats
+
+
+def main():
+ dry_run = "--dry-run" in sys.argv
+
+ print(f"Reading {TEMPLATE_PATH}...")
+ bom, text = read_template(TEMPLATE_PATH)
+ print(f" File size: {len(text)} characters, BOM: {'yes' if bom else 'no'}")
+
+ css_start, css_end = find_css_cdata(text)
+ css_text = text[css_start:css_end]
+ print(f" CSS block: {len(css_text)} characters ({css_start}..{css_end})")
+
+ # Count total rgba values before
+ rgba_before = len(re.findall(r"rgba\([^)]+\)", css_text))
+ print(f" Total rgba values: {rgba_before}")
+
+ # Apply replacements
+ mode = "DRY RUN" if dry_run else "APPLYING"
+ print(f"\n{mode} color replacements...")
+
+ new_css, stats = apply_color_map(css_text, COLOR_MAP, dry_run=dry_run)
+
+ total_replacements = 0
+ for old_color, info in stats.items():
+ print(f" {info['count']:4d}x {old_color}")
+ print(f" → {info['new']}")
+ total_replacements += info["count"]
+
+ print(f"\nTotal replacements: {total_replacements}")
+
+ if not dry_run:
+ # Reconstruct file
+ new_text = text[:css_start] + new_css + text[css_end:]
+
+ # Verify unique rgba values remaining
+ unique_after = sorted(set(re.findall(r"rgba\([^)]+\)", new_css)))
+ print(f"\nUnique rgba values remaining: {len(unique_after)}")
+ for v in unique_after:
+ count = new_css.count(v)
+ print(f" {count:4d}x {v}")
+
+ write_template(TEMPLATE_PATH, bom, new_text)
+ print(f"\nWritten to {TEMPLATE_PATH}")
+
+ # Verify encoding roundtrip
+ _, verify_text = read_template(TEMPLATE_PATH)
+ if verify_text == new_text:
+ print("Encoding verification: PASSED")
+ else:
+ print("ERROR: Encoding verification FAILED!")
+ sys.exit(1)
+ else:
+ print("\nDry run complete. Use without --dry-run to apply.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/element_refinements.py b/tools/element_refinements.py
new file mode 100644
index 0000000..def26aa
--- /dev/null
+++ b/tools/element_refinements.py
@@ -0,0 +1,320 @@
+#!/usr/bin/env python3
+"""
+Phase 2: Element-specific refinements for shadcn theme.
+
+Applies targeted CSS rule modifications that can't be done with global
+find-and-replace (semantically different elements need different treatment).
+"""
+
+import re
+import sys
+
+
+TEMPLATE_PATH = "proof_shadcn_theme/template.xml"
+
+
+def read_template(path):
+ with open(path, "rb") as f:
+ raw = f.read()
+ if raw[:2] == b"\xff\xfe":
+ bom = raw[:2]
+ text = raw[2:].decode("utf-16-le")
+ else:
+ bom = b""
+ text = raw.decode("utf-16-le")
+ return bom, text
+
+
+def write_template(path, bom, text):
+ with open(path, "wb") as f:
+ f.write(bom)
+ f.write(text.encode("utf-16-le"))
+
+
+def find_css_cdata(text):
+ marker = "", start)
+ return start, end
+
+
+def replace_rule(css, selector, old_props, new_props):
+ """Replace properties within a specific CSS rule block.
+
+ Finds the rule matching `selector`, then replaces `old_props` with
+ `new_props` within that rule only.
+ """
+ # Find the selector
+ idx = css.find(selector)
+ if idx == -1:
+ print(f" WARNING: selector not found: {selector}")
+ return css, False
+
+ # Find the opening and closing braces
+ brace_start = css.find("{", idx)
+ brace_end = css.find("}", brace_start)
+ if brace_start == -1 or brace_end == -1:
+ print(f" WARNING: could not find braces for: {selector}")
+ return css, False
+
+ rule_content = css[brace_start:brace_end + 1]
+ if old_props not in rule_content:
+ print(f" WARNING: props not found in {selector}: {old_props[:50]}...")
+ return css, False
+
+ new_rule = rule_content.replace(old_props, new_props, 1)
+ css = css[:brace_start] + new_rule + css[brace_end + 1:]
+ return css, True
+
+
+def insert_props_in_rule(css, selector, new_props):
+ """Insert new properties at the end of a rule block (before closing brace)."""
+ idx = css.find(selector)
+ if idx == -1:
+ print(f" WARNING: selector not found: {selector}")
+ return css, False
+
+ brace_start = css.find("{", idx)
+ brace_end = css.find("}", brace_start)
+
+ # Insert before the closing brace
+ css = css[:brace_end] + new_props + "\n" + css[brace_end:]
+ return css, True
+
+
+def apply_input_full_border(css):
+ """Convert bottom-border-only inputs to full-border with radius."""
+ print("\n--- Input fields: bottom-border → full border ---")
+ count = 0
+
+ # Elements that currently have bottom-border-only
+ for element in ["edit_box", "pop_up", "drop_down"]:
+ selector = f"{element}:normal .self"
+
+ # Change border styles from none to solid
+ old = (
+ "\tborder-top-style: none;\n"
+ "\tborder-right-style: none;\n"
+ "\tborder-bottom-style: solid;\n"
+ "\tborder-left-style: none;"
+ )
+ new = (
+ "\tborder-top-style: solid;\n"
+ "\tborder-right-style: solid;\n"
+ "\tborder-bottom-style: solid;\n"
+ "\tborder-left-style: solid;\n"
+ "\tborder-top-right-radius: 6pt 6pt;\n"
+ "\tborder-bottom-right-radius: 6pt 6pt;\n"
+ "\tborder-bottom-left-radius: 6pt 6pt;\n"
+ "\tborder-top-left-radius: 6pt 6pt;"
+ )
+
+ css, ok = replace_rule(css, selector, old, new)
+ if ok:
+ print(f" {element}: full border + 6pt radius")
+ count += 1
+
+ # Also update the border color from border gray to a slightly lighter
+ # shade for normal state (shadcn inputs use border color)
+ print(f" Updated {count} input elements")
+ return css
+
+
+def apply_checkbox_radio_filled(css):
+ """Make checkbox/radio dark-filled when checked (shadcn pattern)."""
+ print("\n--- Checkbox/radio: dark filled when checked ---")
+
+ # Checkbox checked icon: add dark background + white icon
+ old = (
+ "checkbox_set:checked .icon\n"
+ "{\n"
+ "\t-fm-icon: modern-check;\n"
+ "\t-fm-icon-color: rgba(0%,0%,0%,1);\n"
+ "}"
+ )
+ new = (
+ "checkbox_set:checked .icon\n"
+ "{\n"
+ "\tbackground-color: rgba(18%,18%,18%,1);\n"
+ "\tborder-top-color: rgba(18%,18%,18%,1);\n"
+ "\tborder-right-color: rgba(18%,18%,18%,1);\n"
+ "\tborder-bottom-color: rgba(18%,18%,18%,1);\n"
+ "\tborder-left-color: rgba(18%,18%,18%,1);\n"
+ "\t-fm-icon: modern-check;\n"
+ "\t-fm-icon-color: rgba(100%,100%,100%,1);\n"
+ "}"
+ )
+ css = css.replace(old, new, 1)
+ print(" checkbox_set:checked — dark bg + white check")
+
+ # Radio checked icon: add dark background + white icon
+ old = (
+ "radio_set:checked .icon\n"
+ "{\n"
+ "\t-fm-icon: radio;\n"
+ "\t-fm-icon-color: rgba(0%,0%,0%,1);\n"
+ "}"
+ )
+ new = (
+ "radio_set:checked .icon\n"
+ "{\n"
+ "\tbackground-color: rgba(18%,18%,18%,1);\n"
+ "\tborder-top-color: rgba(18%,18%,18%,1);\n"
+ "\tborder-right-color: rgba(18%,18%,18%,1);\n"
+ "\tborder-bottom-color: rgba(18%,18%,18%,1);\n"
+ "\tborder-left-color: rgba(18%,18%,18%,1);\n"
+ "\t-fm-icon: radio;\n"
+ "\t-fm-icon-color: rgba(100%,100%,100%,1);\n"
+ "}"
+ )
+ css = css.replace(old, new, 1)
+ print(" radio_set:checked — dark bg + white dot")
+
+ # Also handle FM-UUID instance overrides for checkbox/radio checked
+ # Find all checkbox_set.FM-*:checked .icon and radio_set.FM-*:checked .icon
+ pattern = re.compile(
+ r'((?:checkbox_set|radio_set)\.FM-[^:]+:checked \.icon\n\{\n)'
+ r'(\t-fm-icon: (?:modern-check|radio);\n'
+ r'\t-fm-icon-color: rgba\(0%,0%,0%,1\);\n\})'
+ )
+ def replace_instance_checked(m):
+ prefix = m.group(1)
+ icon_line = "\t-fm-icon: modern-check;" if "checkbox" in m.group(0) else "\t-fm-icon: radio;"
+ return (
+ prefix
+ + "\tbackground-color: rgba(18%,18%,18%,1);\n"
+ + "\tborder-top-color: rgba(18%,18%,18%,1);\n"
+ + "\tborder-right-color: rgba(18%,18%,18%,1);\n"
+ + "\tborder-bottom-color: rgba(18%,18%,18%,1);\n"
+ + "\tborder-left-color: rgba(18%,18%,18%,1);\n"
+ + icon_line + "\n"
+ + "\t-fm-icon-color: rgba(100%,100%,100%,1);\n"
+ + "}"
+ )
+
+ css, instance_count = pattern.subn(replace_instance_checked, css)
+ if instance_count:
+ print(f" {instance_count} FM-UUID instance overrides also updated")
+
+ return css
+
+
+def apply_filled_button_fixes(css):
+ """Ensure filled primary buttons have correct light text on hover/press."""
+ print("\n--- Filled buttons: ensure light text in all states ---")
+
+ # Find filled button instances and fix their hover states
+ # Pattern: button.FM-*:hover .self with background going to light color
+ # but text color not explicitly set to dark
+ # For filled buttons, hover should stay dark bg or go slightly lighter
+ # Current issue: some filled buttons hover to rgba(96.1%) bg (light) but
+ # don't set text color, so text stays white on light bg
+
+ # Fix filled button hover states: if hover bg is light, set text color dark
+ pattern = re.compile(
+ r'(button\.FM-[A-F0-9-]+:hover \.self\n\{\n'
+ r'\tbackground-image: none;\n'
+ r'\tbackground-color: rgba\(96\.1%,96\.1%,96\.1%,1\);\n'
+ r'\tborder-image-source: none;\n'
+ r'\})'
+ )
+
+ def add_text_color_to_hover(m):
+ # Replace closing brace with text color + closing brace
+ block = m.group(1)
+ return block.replace(
+ "\tborder-image-source: none;\n}",
+ "\tborder-image-source: none;\n"
+ "\tcolor: rgba(14.1%,14.1%,14.1%,1);\n}"
+ )
+
+ css, count = pattern.subn(add_text_color_to_hover, css)
+ print(f" Added dark text color to {count} button hover states")
+
+ # Fix icon colors for filled buttons: normal icon should be white
+ # Find filled buttons (bg: 18%) and set their icon color to white
+ lines = css.split("\n")
+ i = 0
+ icon_fixes = 0
+ while i < len(lines):
+ line = lines[i]
+ # Find filled button normal .self blocks
+ if re.match(r'button\.FM-[A-F0-9-]+:normal \.self', line):
+ # Check if this is a filled button (has dark bg)
+ block_end = i
+ for j in range(i + 1, min(i + 30, len(lines))):
+ if lines[j].strip() == "}":
+ block_end = j
+ break
+ block = "\n".join(lines[i:block_end + 1])
+ if "background-color: rgba(18%,18%,18%,1)" in block:
+ # This is a filled button - find its icon rule
+ uuid = re.search(r'FM-[A-F0-9-]+', line).group(0)
+ icon_selector = f"button.{uuid}:normal .icon"
+ icon_idx = css.find(icon_selector)
+ if icon_idx != -1:
+ # Check if icon color is black and change to white
+ old_icon = f"{icon_selector}\n{{\n\t-fm-icon-color: rgba(0%,0%,0%,1);\n}}"
+ new_icon = f"{icon_selector}\n{{\n\t-fm-icon-color: rgba(100%,100%,100%,1);\n}}"
+ if old_icon in css:
+ css = css.replace(old_icon, new_icon, 1)
+ icon_fixes += 1
+ i += 1
+
+ print(f" Fixed {icon_fixes} filled button icon colors to white")
+ return css
+
+
+def apply_placeholder_standardization(css):
+ """Standardize placeholder text to muted-foreground."""
+ print("\n--- Placeholder text: standardize to muted-foreground ---")
+
+ # Some placeholders use rgba(80%,...), some rgba(70.2%,...)
+ # Standardize to muted-foreground rgba(56.5%,...)
+ old = "color: rgba(80%,80%,80%,1)"
+ count_before = css.count(old)
+
+ # Only replace in placeholder rules
+ pattern = re.compile(
+ r'(:placeholder \.self\n\{\n\tcolor: )rgba\(80%,80%,80%,1\)'
+ )
+ css, count = pattern.subn(r'\1rgba(56.5%,56.5%,56.5%,1)', css)
+ print(f" Updated {count} placeholder colors to muted-foreground")
+
+ return css
+
+
+def main():
+ dry_run = "--dry-run" in sys.argv
+
+ print(f"Reading {TEMPLATE_PATH}...")
+ bom, text = read_template(TEMPLATE_PATH)
+
+ css_start, css_end = find_css_cdata(text)
+ css = text[css_start:css_end]
+ print(f" CSS block: {len(css)} characters")
+
+ # Apply refinements
+ css = apply_input_full_border(css)
+ css = apply_checkbox_radio_filled(css)
+ css = apply_filled_button_fixes(css)
+ css = apply_placeholder_standardization(css)
+
+ if not dry_run:
+ new_text = text[:css_start] + css + text[css_end:]
+ write_template(TEMPLATE_PATH, bom, new_text)
+ print(f"\nWritten to {TEMPLATE_PATH}")
+
+ # Verify
+ _, verify = read_template(TEMPLATE_PATH)
+ if verify == new_text:
+ print("Encoding verification: PASSED")
+ else:
+ print("ERROR: Encoding verification FAILED!")
+ sys.exit(1)
+ else:
+ print("\nDry run complete.")
+
+
+if __name__ == "__main__":
+ main()