Redesign web UI with Warm Studio theme#3
Conversation
Complete frontend overhaul using an editorial design language: - Instrument Serif + Work Sans font pairing via Google Fonts - Warm amber/terracotta color palette with CSS custom properties - Redesigned entity badges, confidence bars, tier sections - Amber accent header bar, warm card containers, cream background - CSP updated to allow Google Fonts (fonts.googleapis.com/gstatic.com) All functional JS IDs, classes, data attributes, and HTMX behavior preserved.
CLAUDE.md is personal per-contributor configuration — each developer should maintain their own. Also ignore .claude/, .playwright-mcp/, and design comparison screenshots.
📝 WalkthroughWalkthroughReplaces the Minimal design system with a Warm Studio theme (fonts, tokens, utilities), updates templates and JS to add an example-loader; removes CLAUDE.md and adds .gitignore entries; introduces line-ending normalization and extra debug logging in web routes; adds cache-control branching in middleware and corresponding tests. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
Greptile SummaryThis PR implements a complete visual redesign with "Warm Studio" editorial aesthetics while correctly maintaining privacy guarantees. Critically, all fonts are self-hosted (WOFF2 files in Key verifications:
Two style/quality improvements identified:
Confidence Score: 4/5
Last reviewed commit: 1e26bb4 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/document_anonymizer/web/static/css/app.css`:
- Line 133: The font-family declarations use unnecessary quotes around generic
and simple font names; update the declarations that currently read font-family:
'Instrument Serif', 'Georgia', serif; (and the similar occurrences) so that
quoted multi-word family names like 'Instrument Serif' remain quoted but remove
quotes from Georgia and the generic serif/sans-serif keywords (i.e., change to
font-family: 'Instrument Serif', Georgia, serif;), and apply the same change to
the other identical font-family declarations in the file.
In `@src/document_anonymizer/web/templates/base.html`:
- Around line 13-15: Remove the external Google Fonts links from
src/document_anonymizer/web/templates/base.html and replace them with a local
font stylesheet: vendor the Instrument Serif and Work Sans font files into
static/fonts/, create a static/css/fonts.css containing `@font-face` rules for
those families, and update base.html to include a link to /static/css/fonts.css
instead of the fonts.googleapis.com and fonts.gstatic.com URLs so all frontend
assets are served locally.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8ca9a3ce-738b-4c56-81dd-9d3c6b2609ab
📒 Files selected for processing (8)
.gitignoreCLAUDE.mdsrc/document_anonymizer/security/middleware.pysrc/document_anonymizer/web/static/css/app.csssrc/document_anonymizer/web/templates/anonymized.htmlsrc/document_anonymizer/web/templates/base.htmlsrc/document_anonymizer/web/templates/index.htmlsrc/document_anonymizer/web/templates/results.html
💤 Files with no reviewable changes (1)
- CLAUDE.md
| 5. TYPOGRAPHY | ||
| ============================================================ */ | ||
| .text-2xl { | ||
| font-family: 'Instrument Serif', 'Georgia', serif; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check if the file exists and its size
wc -l src/document_anonymizer/web/static/css/app.cssRepository: JuliusScheuerer/document-anonymizer
Length of output: 129
🏁 Script executed:
# Read the specific lines mentioned in the review
sed -n '130,140p; 648,652p; 672,676p' src/document_anonymizer/web/static/css/app.cssRepository: JuliusScheuerer/document-anonymizer
Length of output: 688
🌐 Web query:
Stylelint font-family-name-quotes rule quoted generic font family names
💡 Result:
Stylelint’s font-family-name-quotes rule will always forbid quoting generic font family keywords (e.g. serif, sans-serif, monospace, system-ui, etc.). The docs explicitly say that if you wrap these keywords in quotes, the browser treats them as a literal font name (e.g. "sans-serif") rather than the generic fallback, so all rule options enforce “no quotes” for these keywords. [1]
So:
font-family: "sans-serif";→ always a lint error with this rule enabled (regardless of option). [1]- Correct generic fallback usage:
font-family: Arial, sans-serif;(generic unquoted). [1][2]
If you genuinely need a real font family named "sans-serif" (rare), Stylelint recommends you turn this rule off for that case. [1]
Options (affect only non-keyword family names):
"always-unless-keyword": quote all non-keyword names. [1]"always-where-required": quote only when CSS syntax requires it. [1]"always-where-recommended": quote when CSS recommends it (e.g., spaces/digits/punctuation), and disallow other quotes. [1]
Sources:
[1] Stylelint rule docs: font-family-name-quotes https://stylelint.io/user-guide/rules/font-family-name-quotes/
[2] W3C CSS2.1 (generic family names are keywords and must not be quoted) https://www.w3.org/Style/css2-updates/css2/css2.pdf
🏁 Script executed:
# Search for stylelint configuration files
fd -e stylelintrc -e stylelintrc.json -e stylelintrc.js -e stylelintrc.yaml -e stylelintrc.yml -e stylelintrc.cjsRepository: JuliusScheuerer/document-anonymizer
Length of output: 61
🏁 Script executed:
# Also check package.json for stylelint config
cat package.json | grep -A 20 '"stylelint"'Repository: JuliusScheuerer/document-anonymizer
Length of output: 123
🏁 Script executed:
# Check for .stylelintignore and any stylelint references in config
find . -name ".stylelint*" -o -name "stylelint.config.*" | head -20Repository: JuliusScheuerer/document-anonymizer
Length of output: 98
🏁 Script executed:
cat .stylelintrc.jsonRepository: JuliusScheuerer/document-anonymizer
Length of output: 1085
🌐 Web query:
stylelint-config-standard-scss font-family-name-quotes default option
💡 Result:
In stylelint-config-standard-scss, font-family-name-quotes is not overridden; the config simply extends stylelint-config-standard, so it inherits that setting. In the current stylelint-config-standard, the rule is set to:
font-family-name-quotes: "always-where-recommended"(this is the effective/default option you get viastylelint-config-standard-scss). [1], [2]
That option means: quote font-family names only when quoting is recommended (and therefore also when required), and disallow quotes otherwise (keywords like serif, sans-serif, etc. must remain unquoted). [3]
Sources:
[1] https://github.com/stylelint/stylelint-config-standard/blob/main/index.js
[2] https://github.com/stylelint-scss/stylelint-config-standard-scss/blob/main/index.js
[3] https://stylelint.io/user-guide/rules/font-family-name-quotes/
🌐 Web query:
stylelint-config-standard font-family-name-quotes default "always-unless-keyword"
💡 Result:
In stylelint-config-standard, the default setting for font-family-name-quotes is "always-where-recommended", not "always-unless-keyword". This is defined directly in the config’s index.js. [1]
"always-unless-keyword" is a valid option for the rule (per Stylelint’s rule docs), but it’s not what stylelint-config-standard uses by default. [2]
Sources
stylelint-config-standardindex.js('font-family-name-quotes': 'always-where-recommended'). [1]- Stylelint rule docs for
font-family-name-quotes(shows"always-unless-keyword"as a supported configuration). [2]
Remove unnecessary quotes from generic font family fallbacks to comply with font-family-name-quotes.
Generic font family keywords (serif, sans-serif, etc.) and single-word font names without special characters should not be quoted. Georgia should be unquoted while 'Instrument Serif' (which contains a space) correctly remains quoted.
🎯 Proposed fix
- font-family: 'Instrument Serif', 'Georgia', serif;
+ font-family: 'Instrument Serif', Georgia, serif;Apply this at Lines 133, 139, 650, and 674.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| font-family: 'Instrument Serif', 'Georgia', serif; | |
| font-family: 'Instrument Serif', Georgia, serif; |
🧰 Tools
🪛 Stylelint (17.3.0)
[error] 133-133: Unexpected quotes around "Georgia" (font-family-name-quotes)
(font-family-name-quotes)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/document_anonymizer/web/static/css/app.css` at line 133, The font-family
declarations use unnecessary quotes around generic and simple font names; update
the declarations that currently read font-family: 'Instrument Serif', 'Georgia',
serif; (and the similar occurrences) so that quoted multi-word family names like
'Instrument Serif' remain quoted but remove quotes from Georgia and the generic
serif/sans-serif keywords (i.e., change to font-family: 'Instrument Serif',
Georgia, serif;), and apply the same change to the other identical font-family
declarations in the file.
| <link rel="preconnect" href="https://fonts.googleapis.com"> | ||
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | ||
| <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Work+Sans:wght@400;500;600;700&display=swap" rel="stylesheet"> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check if the file exists and view its content
cat -n src/document_anonymizer/web/templates/base.html | head -30Repository: JuliusScheuerer/document-anonymizer
Length of output: 2164
🏁 Script executed:
# Check the repository structure for static/asset directories
find . -type d \( -name static -o -name assets -o -name fonts \) | grep -v node_modules | head -20Repository: JuliusScheuerer/document-anonymizer
Length of output: 115
🏁 Script executed:
# Look for any existing font files in the repository
find . -type f \( -name "*.woff*" -o -name "*.ttf" -o -name "*.otf" -o -name "fonts.css" \) | grep -v node_modulesRepository: JuliusScheuerer/document-anonymizer
Length of output: 61
🏁 Script executed:
# Check if there are other HTML/Jinja2 templates that reference static assets to understand the pattern
grep -r "href=\"/static" src/document_anonymizer/web/templates/ --include="*.html" --include="*.j2" --include="*.jinja2" | head -10Repository: JuliusScheuerer/document-anonymizer
Length of output: 181
External Google Fonts CDN violates vendored assets requirement.
Lines 13–15 introduce fonts.googleapis.com and fonts.gstatic.com dependencies. Per coding guidelines, all frontend assets must be vendored with no external CDN dependencies. Replace with locally served fonts:
🔧 Proposed change
- <link rel="preconnect" href="https://fonts.googleapis.com">
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
- <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Work+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
+ <link rel="stylesheet" href="/static/css/fonts.css">Download Instrument Serif and Work Sans fonts, add to /static/fonts/, and create /static/css/fonts.css with corresponding @font-face rules.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/document_anonymizer/web/templates/base.html` around lines 13 - 15, Remove
the external Google Fonts links from
src/document_anonymizer/web/templates/base.html and replace them with a local
font stylesheet: vendor the Instrument Serif and Work Sans font files into
static/fonts/, create a static/css/fonts.css containing `@font-face` rules for
those families, and update base.html to include a link to /static/css/fonts.css
instead of the fonts.googleapis.com and fonts.gstatic.com URLs so all frontend
assets are served locally.
Replace Google Fonts CDN links with locally served WOFF2 files to maintain the privacy-first, zero-external-requests promise. Loading fonts from Google's CDN leaked user IP/UA to third parties on every page load — contradicting the "No external API calls" footer claim. - Add @font-face declarations in app.css for Instrument Serif + Work Sans - Bundle 6 WOFF2 files (latin + latin-ext subsets, ~150KB total) - Remove Google Fonts <link> and preconnect tags from base.html - Revert CSP to strict 'self'-only for style-src and font-src
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/document_anonymizer/web/static/css/app.css (1)
188-194:⚠️ Potential issue | 🟡 MinorRemove quotes around
Georgiato satisfyfont-family-name-quotes.Line 188, Line 194, Line 705, and Line 729 still quote
Georgia, which keeps Stylelint failing.🎯 Proposed fix
- font-family: 'Instrument Serif', 'Georgia', serif; + font-family: 'Instrument Serif', Georgia, serif;Also applies to: 705-705, 729-729
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/document_anonymizer/web/static/css/app.css` around lines 188 - 194, The CSS font-family declarations that list 'Georgia' are quoted and trigger the font-family-name-quotes lint rule; locate the font-family properties in the shown rule block and the .text-lg selector (and the other occurrences around the same pattern at the other reported locations) and remove the quotes around Georgia so the declarations use Georgia (unquoted) alongside the existing quoted custom family names.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/document_anonymizer/web/static/css/app.css`:
- Line 384: The CSS declaration "border-bottom: 2px solid currentColor;" uses
the mixed-case keyword "currentColor" which violates the project's stylelint
rule value-keyword-case: ["lower"]; update the value to the lowercase keyword
"currentcolor" (i.e., change currentColor to currentcolor) so the rule passes
and the declaration remains equivalent.
- Line 404: Locate the two occurrences of the non-standard CSS declaration
"word-break: break-word" and replace each with the modern property
"overflow-wrap: anywhere;" (remove the old declaration); update the same
selectors that currently contain "word-break: break-word" so they now use
"overflow-wrap: anywhere" for compliant, consistent word-wrapping behavior.
---
Duplicate comments:
In `@src/document_anonymizer/web/static/css/app.css`:
- Around line 188-194: The CSS font-family declarations that list 'Georgia' are
quoted and trigger the font-family-name-quotes lint rule; locate the font-family
properties in the shown rule block and the .text-lg selector (and the other
occurrences around the same pattern at the other reported locations) and remove
the quotes around Georgia so the declarations use Georgia (unquoted) alongside
the existing quoted custom family names.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2ad9a17e-4001-4635-a0f0-cba60b079958
⛔ Files ignored due to path filters (6)
src/document_anonymizer/web/static/fonts/instrument-serif-italic-latin-ext.woff2is excluded by!**/*.woff2src/document_anonymizer/web/static/fonts/instrument-serif-italic-latin.woff2is excluded by!**/*.woff2src/document_anonymizer/web/static/fonts/instrument-serif-normal-latin-ext.woff2is excluded by!**/*.woff2src/document_anonymizer/web/static/fonts/instrument-serif-normal-latin.woff2is excluded by!**/*.woff2src/document_anonymizer/web/static/fonts/work-sans-latin-ext.woff2is excluded by!**/*.woff2src/document_anonymizer/web/static/fonts/work-sans-latin.woff2is excluded by!**/*.woff2
📒 Files selected for processing (2)
src/document_anonymizer/web/static/css/app.csssrc/document_anonymizer/web/templates/base.html
🚧 Files skipped from review as they are similar to previous changes (1)
- src/document_anonymizer/web/templates/base.html
| border-radius: 0.25rem; | ||
| cursor: help; | ||
| cursor: pointer; | ||
| border-bottom: 2px solid currentColor; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find lint configuration files
find . -type f \( -name ".stylelintrc*" -o -name "stylelint.config.*" -o -name ".eslintrc*" -o -name "eslint.config.*" -o -name "package.json" -o -name ".lintrc*" \) | head -20Repository: JuliusScheuerer/document-anonymizer
Length of output: 98
🏁 Script executed:
# Check the actual content around line 384 of the CSS file
cat -n src/document_anonymizer/web/static/css/app.css | sed -n '380,390p'Repository: JuliusScheuerer/document-anonymizer
Length of output: 409
🏁 Script executed:
# Search for currentColor/currentcolor usage in the CSS file
rg -i "currentcolor" src/document_anonymizer/web/static/css/app.cssRepository: JuliusScheuerer/document-anonymizer
Length of output: 119
🏁 Script executed:
cat .stylelintrc.jsonRepository: JuliusScheuerer/document-anonymizer
Length of output: 1085
🌐 Web query:
CSS currentColor keyword casing stylelint keyword-case rule
💡 Result:
In CSS, keyword identifiers like currentColor are case-insensitive, so currentcolor and currentColor both work in browsers; the mixed-case form is commonly shown in docs (e.g., as part of the <color> value set). [2]
In stylelint, casing is enforced by the value-keyword-case rule:
- If you use
"lower", stylelint will normally requirecurrentcolor. - If you want to allow/require the SVG-style camelCase spelling
currentColorwhile still enforcing lowercase for other keywords, enablecamelCaseSvgKeywords: true: [1]
{
"rules": {
"value-keyword-case": ["lower", { "camelCaseSvgKeywords": true }]
}
}Alternatively, you can exempt it with ignoreKeywords: ["currentColor"] (or a regex) if you don’t want SVG-specific behavior. [1]
Sources: Stylelint value-keyword-case (including camelCaseSvgKeywords). [1] MDN <color> value (includes currentColor). [2]
[1] https://stylelint.io/user-guide/rules/value-keyword-case/
[2] https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
Change currentColor to lowercase currentcolor.
Line 384 uses currentColor, but the project's lint rules (inherited from stylelint-config-standard via .stylelintrc.json) enforce lowercase keyword values with the value-keyword-case: ["lower"] rule.
🎯 Proposed fix
- border-bottom: 2px solid currentColor;
+ border-bottom: 2px solid currentcolor;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| border-bottom: 2px solid currentColor; | |
| border-bottom: 2px solid currentcolor; |
🧰 Tools
🪛 Stylelint (17.3.0)
[error] 384-384: Expected "currentColor" to be "currentcolor" (value-keyword-case)
(value-keyword-case)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/document_anonymizer/web/static/css/app.css` at line 384, The CSS
declaration "border-bottom: 2px solid currentColor;" uses the mixed-case keyword
"currentColor" which violates the project's stylelint rule value-keyword-case:
["lower"]; update the value to the lowercase keyword "currentcolor" (i.e.,
change currentColor to currentcolor) so the rule passes and the declaration
remains equivalent.
| font-size: 0.875rem; | ||
| font-size: 0.8125rem; | ||
| white-space: pre-wrap; | ||
| word-break: break-word; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check the CSS file for lines 404 and 744
head -n 750 src/document_anonymizer/web/static/css/app.css | tail -n +400 | head -n 10Repository: JuliusScheuerer/document-anonymizer
Length of output: 327
🏁 Script executed:
# Also check line 744 specifically
sed -n '740,750p' src/document_anonymizer/web/static/css/app.cssRepository: JuliusScheuerer/document-anonymizer
Length of output: 329
🌐 Web query:
CSS word-break: break-word deprecated modern replacement overflow-wrap
💡 Result:
word-break: break-word is a legacy/non-standard value and is deprecated. Use overflow-wrap instead:
-
Closest behavioral equivalent to
word-break: break-word:overflow-wrap: anywhere; word-break: normal;
(MDN notes
word-break: break-wordhas the same effect as this combination.) [1] -
Common “break only if needed to prevent overflow” replacement:
overflow-wrap: break-word;
(Standard property;
break-wordis likeanywherebut with a subtle intrinsic sizing difference.) [2] -
If you need legacy naming for old codebases,
word-wrapis a legacy alias ofoverflow-wrapin browsers/specs:overflow-wrap: break-word; word-wrap: break-word; /* alias/fallback */
[3]
Sources: MDN word-break [1], MDN overflow-wrap [2], W3C CSS Text (alias note for word-wrap) [3].
Replace deprecated word-break: break-word with overflow-wrap.
Lines 404 and 744 use the non-standard word-break: break-word value. Replace with:
- word-break: break-word;
+ overflow-wrap: anywhere;
+ word-break: normal;This provides modern CSS compliance and consistent cross-browser behavior.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| word-break: break-word; | |
| overflow-wrap: anywhere; | |
| word-break: normal; |
🧰 Tools
🪛 Stylelint (17.3.0)
[error] 404-404: Unexpected deprecated keyword "break-word" for property "word-break" (declaration-property-value-keyword-no-deprecated)
(declaration-property-value-keyword-no-deprecated)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/document_anonymizer/web/static/css/app.css` at line 404, Locate the two
occurrences of the non-standard CSS declaration "word-break: break-word" and
replace each with the modern property "overflow-wrap: anywhere;" (remove the old
declaration); update the same selectors that currently contain "word-break:
break-word" so they now use "overflow-wrap: anywhere" for compliant, consistent
word-wrapping behavior.
…ering (#4) - Normalize CRLF/CR line endings to LF at server boundary in both /detect and /anonymize-form endpoints, preventing entity position mismatches when text round-trips through HTML hidden inputs - Add "Beispieltext laden" link to load sample German PII into textarea for quick testing, with warm-palette styling - Replace HTML entities (≥, –) with UTF-8 characters in tier config to fix double-escaping by Jinja2 autoescaping - Add debug logging for entity skip reasons in both text and PDF reconstruction paths for better diagnostics - Add tests for line ending normalization and score range validation
There was a problem hiding this comment.
♻️ Duplicate comments (3)
src/document_anonymizer/web/static/css/app.css (3)
404-404:⚠️ Potential issue | 🟡 MinorReplace deprecated
word-break: break-wordusage.Line 404 and Line 744 use a deprecated value; switch to
overflow-wrap-based wrapping.🎯 Proposed fix
- word-break: break-word; + overflow-wrap: anywhere; + word-break: normal;Also applies to: 744-744
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/document_anonymizer/web/static/css/app.css` at line 404, Replace the deprecated CSS property usage by locating the declarations that currently set "word-break: break-word" (the rules containing that exact string) and change them to use modern wrapping: remove "word-break: break-word" and add "overflow-wrap: anywhere;" (and optionally "word-wrap: break-word;" for older browsers) so text wrapping behavior is preserved.
188-194:⚠️ Potential issue | 🟡 MinorUnquote
Georgiain font stacks to satisfyfont-family-name-quotes.
'Georgia'should be unquoted in these declarations (Line 188, Line 194, Line 705, Line 729).🎯 Proposed fix
- font-family: 'Instrument Serif', 'Georgia', serif; + font-family: 'Instrument Serif', Georgia, serif;Also applies to: 705-705, 729-729
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/document_anonymizer/web/static/css/app.css` around lines 188 - 194, Remove the unnecessary quotes around Georgia in the font-family declarations: update the font-family values in the shown rule (the block ending just before .text-lg) and in the .text-lg rule so they read Instrument Serif, Georgia, serif (and do the same for the other occurrences flagged in the stylesheet). Search for any other font-family declarations that currently use 'Georgia' and unquote them to satisfy the font-family-name-quotes rule while preserving the comma-separated order and fallback stack.
384-384:⚠️ Potential issue | 🟡 MinorUse lowercase
currentcolorfor lint compliance.Line 384 uses
currentColor, but configured keyword-case linting expects lowercase.🎯 Proposed fix
- border-bottom: 2px solid currentColor; + border-bottom: 2px solid currentcolor;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/document_anonymizer/web/static/css/app.css` at line 384, The CSS property declaration using "currentColor" should use lowercase to satisfy keyword-case linting: find the rule containing "border-bottom: 2px solid currentColor" and change the keyword to "currentcolor" so the declaration reads "border-bottom: 2px solid currentcolor".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/document_anonymizer/web/static/css/app.css`:
- Line 404: Replace the deprecated CSS property usage by locating the
declarations that currently set "word-break: break-word" (the rules containing
that exact string) and change them to use modern wrapping: remove "word-break:
break-word" and add "overflow-wrap: anywhere;" (and optionally "word-wrap:
break-word;" for older browsers) so text wrapping behavior is preserved.
- Around line 188-194: Remove the unnecessary quotes around Georgia in the
font-family declarations: update the font-family values in the shown rule (the
block ending just before .text-lg) and in the .text-lg rule so they read
Instrument Serif, Georgia, serif (and do the same for the other occurrences
flagged in the stylesheet). Search for any other font-family declarations that
currently use 'Georgia' and unquote them to satisfy the font-family-name-quotes
rule while preserving the comma-separated order and fallback stack.
- Line 384: The CSS property declaration using "currentColor" should use
lowercase to satisfy keyword-case linting: find the rule containing
"border-bottom: 2px solid currentColor" and change the keyword to "currentcolor"
so the declaration reads "border-bottom: 2px solid currentcolor".
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 838caf41-2027-44da-b1d7-1c6493d045d8
📒 Files selected for processing (6)
src/document_anonymizer/web/routes.pysrc/document_anonymizer/web/static/css/app.csssrc/document_anonymizer/web/static/js/app.jssrc/document_anonymizer/web/templates/index.htmlsrc/document_anonymizer/web/templates/results.htmltests/test_web/test_review_helpers.py
🚧 Files skipped from review as they are similar to previous changes (2)
- src/document_anonymizer/web/templates/index.html
- src/document_anonymizer/web/templates/results.html
Address all review findings from the ux-overhaul PR: - Add conditional Cache-Control: public for static assets, no-store for dynamic responses (with status_code==200 guard to prevent cached 404s) - Fix WCAG contrast: btn-primary amber-500→amber-700, footer/muted text warm-400→warm-500 - Extract CSS design tokens: font stacks, RGB channel vars for rgba() - Remove unused CSS classes and italic font files (~34KB saved) - Replace inline styles with utility classes across all templates - Add font preload hints for primary latin subsets - Add .gitattributes for binary woff2 handling - Add 5 new tests: static caching, PII no-cache, cache branching unit tests
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/document_anonymizer/security/middleware.py (1)
36-45:⚠️ Potential issue | 🟠 MajorCSP currently blocks the new Google Fonts setup.
At Line 39 and Line 41, CSP only allows local styles/fonts. With Google Fonts in the UI, these requests will be blocked unless
fonts.googleapis.comandfonts.gstatic.comare allowlisted.Suggested fix
response.headers["Content-Security-Policy"] = ( "default-src 'self'; " "script-src 'self'; " - "style-src 'self' 'unsafe-inline'; " + "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " "img-src 'self' data:; " - "font-src 'self'; " + "font-src 'self' https://fonts.gstatic.com; " "frame-ancestors 'none'; " "base-uri 'self'; " "form-action 'self'" )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/document_anonymizer/security/middleware.py` around lines 36 - 45, The CSP set on response.headers["Content-Security-Policy"] in security.middleware.py currently restricts styles and fonts to 'self' causing Google Fonts requests to be blocked; update the CSP string in that block (the response.headers assignment) to allowlist the Google Fonts hosts by adding https://fonts.googleapis.com (or fonts.googleapis.com) to style-src and https://fonts.gstatic.com (or fonts.gstatic.com) to font-src (optionally include the https: scheme and consider keeping 'unsafe-inline' for styles if needed) so the UI can load Google Fonts successfully.
♻️ Duplicate comments (2)
src/document_anonymizer/web/static/css/app.css (2)
199-199:⚠️ Potential issue | 🟡 MinorReplace deprecated
word-break: break-wordusage.Line [199], Line [385], and Line [714] use a deprecated value. Use
overflow-wrapand keepword-breakatnormalwhere needed.Proposed fix
-.break-words { word-break: break-word; } +.break-words { + overflow-wrap: anywhere; + word-break: normal; +} @@ - word-break: break-word; + overflow-wrap: anywhere; + word-break: normal; @@ - word-break: break-word; + overflow-wrap: anywhere; + word-break: normal;#!/bin/bash set -e rg -n "word-break:\\s*break-word" src/document_anonymizer/web/static/css/app.css cat .stylelintrc.json | rg -n "declaration-property-value-keyword-no-deprecated"Also applies to: 385-385, 714-714
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/document_anonymizer/web/static/css/app.css` at line 199, Replace the deprecated usage of "word-break: break-word" in the .break-words rule (and the other two occurrences) by setting overflow-wrap: break-word and keeping word-break: normal; locate the CSS rules that use "word-break: break-word" (e.g., the .break-words class) and change them to use overflow-wrap: break-word plus word-break: normal to preserve behavior without the deprecated value.
365-365:⚠️ Potential issue | 🟡 MinorNormalize
currentColorcasing for lint compliance.At Line [365], use lowercase
currentcolorto satisfyvalue-keyword-case.Proposed fix
- border-bottom: 2px solid currentColor; + border-bottom: 2px solid currentcolor;#!/bin/bash set -e rg -n "currentColor|currentcolor" src/document_anonymizer/web/static/css/app.css cat .stylelintrc.json | rg -n '"value-keyword-case"'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/document_anonymizer/web/static/css/app.css` at line 365, The CSS uses the keyword with incorrect casing in the declaration `border-bottom: 2px solid currentColor;` — update the value to lowercase `currentcolor` to satisfy the `value-keyword-case` rule; locate the `border-bottom` declaration in src/document_anonymizer/web/static/css/app.css (the line containing `border-bottom: 2px solid currentColor;`) and replace `currentColor` with `currentcolor`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/test_web/test_routes.py`:
- Around line 280-285: The CSP test test_csp_header_present currently only
asserts "font-src 'self'" and should also assert that Google Fonts are
allowlisted; update the assertions on the csp string (from
r.headers["Content-Security-Policy"]) to explicitly check for
fonts.googleapis.com and fonts.gstatic.com (or their expected sources) being
present in the font-src directive so missing Google Fonts entries are detected.
---
Outside diff comments:
In `@src/document_anonymizer/security/middleware.py`:
- Around line 36-45: The CSP set on response.headers["Content-Security-Policy"]
in security.middleware.py currently restricts styles and fonts to 'self' causing
Google Fonts requests to be blocked; update the CSP string in that block (the
response.headers assignment) to allowlist the Google Fonts hosts by adding
https://fonts.googleapis.com (or fonts.googleapis.com) to style-src and
https://fonts.gstatic.com (or fonts.gstatic.com) to font-src (optionally include
the https: scheme and consider keeping 'unsafe-inline' for styles if needed) so
the UI can load Google Fonts successfully.
---
Duplicate comments:
In `@src/document_anonymizer/web/static/css/app.css`:
- Line 199: Replace the deprecated usage of "word-break: break-word" in the
.break-words rule (and the other two occurrences) by setting overflow-wrap:
break-word and keeping word-break: normal; locate the CSS rules that use
"word-break: break-word" (e.g., the .break-words class) and change them to use
overflow-wrap: break-word plus word-break: normal to preserve behavior without
the deprecated value.
- Line 365: The CSS uses the keyword with incorrect casing in the declaration
`border-bottom: 2px solid currentColor;` — update the value to lowercase
`currentcolor` to satisfy the `value-keyword-case` rule; locate the
`border-bottom` declaration in src/document_anonymizer/web/static/css/app.css
(the line containing `border-bottom: 2px solid currentColor;`) and replace
`currentColor` with `currentcolor`.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 78b5bc4b-1047-417b-9440-f001f5478369
📒 Files selected for processing (9)
.gitattributessrc/document_anonymizer/security/middleware.pysrc/document_anonymizer/web/static/css/app.csssrc/document_anonymizer/web/templates/anonymized.htmlsrc/document_anonymizer/web/templates/base.htmlsrc/document_anonymizer/web/templates/index.htmlsrc/document_anonymizer/web/templates/results.htmltests/test_security/test_middleware.pytests/test_web/test_routes.py
✅ Files skipped from review due to trivial changes (1)
- .gitattributes
🚧 Files skipped from review as they are similar to previous changes (2)
- src/document_anonymizer/web/templates/base.html
- src/document_anonymizer/web/templates/anonymized.html
| def test_csp_header_present(self) -> None: | ||
| r = client.get("/") | ||
| csp = r.headers["Content-Security-Policy"] | ||
| assert "default-src 'self'" in csp | ||
| assert "frame-ancestors 'none'" in csp | ||
| assert "font-src 'self'" in csp |
There was a problem hiding this comment.
Strengthen CSP test to verify Google Fonts allowlist explicitly.
At Line 285, checking only "font-src 'self'" is insufficient; it won’t catch missing Google Fonts domains in CSP.
Suggested test hardening
csp = r.headers["Content-Security-Policy"]
assert "default-src 'self'" in csp
assert "frame-ancestors 'none'" in csp
assert "font-src 'self'" in csp
+ assert "fonts.googleapis.com" in csp
+ assert "fonts.gstatic.com" in csp🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/test_web/test_routes.py` around lines 280 - 285, The CSP test
test_csp_header_present currently only asserts "font-src 'self'" and should also
assert that Google Fonts are allowlisted; update the assertions on the csp
string (from r.headers["Content-Security-Policy"]) to explicitly check for
fonts.googleapis.com and fonts.gstatic.com (or their expected sources) being
present in the font-src directive so missing Google Fonts entries are detected.
Summary
Complete frontend redesign using an editorial "Warm Studio" aesthetic, replacing the default utilitarian styling with a polished, professional look suitable for an open-source tool.
--warm-*,--amber-*)font-src 'self'; fonts self-hosted to eliminate external requestsCLAUDE.mduntracked (personal per-contributor), AI tooling dirs and design artifacts added to.gitignoreAll functional JS IDs, CSS classes,
data-*attributes, and HTMX behavior are fully preserved — this is a purely visual change.Screenshots
Test plan
Summary by CodeRabbit
Style
New Features
Bug Fixes
Tests
Documentation