Sweep all .cshtml files for encoding corruption; add pre-commit guard

Replace all corruption variants with HTML entities across 226 view files:
- 3-char UTF-8-as-Win1252 sequences (ae-corruption)
- Standalone smart/curly quotes that break C# Razor expressions
- Partially re-corrupted variants where the 3rd byte was normalised to ASCII

tools/Fix-Encoding.ps1: re-runnable sweep; uses [char] code points so the
script itself never contains a literal non-ASCII character; supports -DryRun

.githooks/pre-commit: blocks commits containing the ae-corruption byte
signature (xc3xa2xe2x82xac); git core.hooksPath = .githooks so the
hook is repo-committed and active for all future work on this machine.

Build clean; 225 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 21:37:10 -04:00
parent 21b39161a3
commit a0bdd2b5b4
252 changed files with 1785 additions and 1633 deletions
@@ -1,4 +1,4 @@
@model PowderCoating.Application.DTOs.User.UserProfileDto
@model PowderCoating.Application.DTOs.User.UserProfileDto
@{
ViewData["Title"] = "My Profile";
@@ -85,7 +85,7 @@
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
data-bs-title="Personal Information"
data-bs-content="First Name, Last Name, and Phone are editable and saved when you click Save Profile. Email is shown here for reference â€" change it on the Security tab. Department, Position, Role, and Employee Number are set by an administrator and cannot be changed here.">
data-bs-content="First Name, Last Name, and Phone are editable and saved when you click Save Profile. Email is shown here for reference &mdash; change it on the Security tab. Department, Position, Role, and Employee Number are set by an administrator and cannot be changed here.">
<i class="bi bi-question-circle"></i>
</a>
</div>
@@ -290,7 +290,7 @@
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
data-bs-title="Appearance Settings"
data-bs-content="Theme switches the app between Light and Dark mode. Sidebar Color changes the navigation panel background â€" click a swatch to preview it instantly. Date Format controls how dates display throughout the app. Timezone is used to localize timestamps. Click Save Appearance to persist your choices.">
data-bs-content="Theme switches the app between Light and Dark mode. Sidebar Color changes the navigation panel background &mdash; click a swatch to preview it instantly. Date Format controls how dates display throughout the app. Timezone is used to localize timestamps. Click Save Appearance to persist your choices.">
<i class="bi bi-question-circle"></i>
</a>
</div>
@@ -364,39 +364,39 @@
<label class="form-label fw-semibold">Timezone</label>
<select class="form-select" id="timezoneInput" name="TimeZone" style="max-width:350px;">
<optgroup label="United States">
<option value="America/New_York" selected="@(Model.TimeZone == "America/New_York" ? "selected" : null)">Eastern (ET) New York</option>
<option value="America/Chicago" selected="@(Model.TimeZone == "America/Chicago" ? "selected" : null)">Central (CT) Chicago</option>
<option value="America/Denver" selected="@(Model.TimeZone == "America/Denver" ? "selected" : null)">Mountain (MT) Denver</option>
<option value="America/Phoenix" selected="@(Model.TimeZone == "America/Phoenix" ? "selected" : null)">Mountain no-DST Phoenix</option>
<option value="America/Los_Angeles" selected="@(Model.TimeZone == "America/Los_Angeles" ? "selected" : null)">Pacific (PT) Los Angeles</option>
<option value="America/Anchorage" selected="@(Model.TimeZone == "America/Anchorage" ? "selected" : null)">Alaska (AKT) Anchorage</option>
<option value="Pacific/Honolulu" selected="@(Model.TimeZone == "Pacific/Honolulu" ? "selected" : null)">Hawaii (HT) Honolulu</option>
<option value="America/New_York" selected="@(Model.TimeZone == "America/New_York" ? "selected" : null)">Eastern (ET) &mdash; New York</option>
<option value="America/Chicago" selected="@(Model.TimeZone == "America/Chicago" ? "selected" : null)">Central (CT) &mdash; Chicago</option>
<option value="America/Denver" selected="@(Model.TimeZone == "America/Denver" ? "selected" : null)">Mountain (MT) &mdash; Denver</option>
<option value="America/Phoenix" selected="@(Model.TimeZone == "America/Phoenix" ? "selected" : null)">Mountain no-DST &mdash; Phoenix</option>
<option value="America/Los_Angeles" selected="@(Model.TimeZone == "America/Los_Angeles" ? "selected" : null)">Pacific (PT) &mdash; Los Angeles</option>
<option value="America/Anchorage" selected="@(Model.TimeZone == "America/Anchorage" ? "selected" : null)">Alaska (AKT) &mdash; Anchorage</option>
<option value="Pacific/Honolulu" selected="@(Model.TimeZone == "Pacific/Honolulu" ? "selected" : null)">Hawaii (HT) &mdash; Honolulu</option>
</optgroup>
<optgroup label="Canada">
<option value="America/Halifax" selected="@(Model.TimeZone == "America/Halifax" ? "selected" : null)">Atlantic (AT) Halifax</option>
<option value="America/Toronto" selected="@(Model.TimeZone == "America/Toronto" ? "selected" : null)">Eastern Toronto</option>
<option value="America/Winnipeg" selected="@(Model.TimeZone == "America/Winnipeg" ? "selected" : null)">Central Winnipeg</option>
<option value="America/Edmonton" selected="@(Model.TimeZone == "America/Edmonton" ? "selected" : null)">Mountain Edmonton</option>
<option value="America/Vancouver" selected="@(Model.TimeZone == "America/Vancouver" ? "selected" : null)">Pacific Vancouver</option>
<option value="America/Halifax" selected="@(Model.TimeZone == "America/Halifax" ? "selected" : null)">Atlantic (AT) &mdash; Halifax</option>
<option value="America/Toronto" selected="@(Model.TimeZone == "America/Toronto" ? "selected" : null)">Eastern &mdash; Toronto</option>
<option value="America/Winnipeg" selected="@(Model.TimeZone == "America/Winnipeg" ? "selected" : null)">Central &mdash; Winnipeg</option>
<option value="America/Edmonton" selected="@(Model.TimeZone == "America/Edmonton" ? "selected" : null)">Mountain &mdash; Edmonton</option>
<option value="America/Vancouver" selected="@(Model.TimeZone == "America/Vancouver" ? "selected" : null)">Pacific &mdash; Vancouver</option>
</optgroup>
<optgroup label="Europe">
<option value="Europe/London" selected="@(Model.TimeZone == "Europe/London" ? "selected" : null)">GMT/BST London</option>
<option value="Europe/Paris" selected="@(Model.TimeZone == "Europe/Paris" ? "selected" : null)">CET Paris / Berlin</option>
<option value="Europe/Helsinki" selected="@(Model.TimeZone == "Europe/Helsinki" ? "selected" : null)">EET Helsinki</option>
<option value="Europe/Moscow" selected="@(Model.TimeZone == "Europe/Moscow" ? "selected" : null)">MSK Moscow</option>
<option value="Europe/London" selected="@(Model.TimeZone == "Europe/London" ? "selected" : null)">GMT/BST &mdash; London</option>
<option value="Europe/Paris" selected="@(Model.TimeZone == "Europe/Paris" ? "selected" : null)">CET &mdash; Paris / Berlin</option>
<option value="Europe/Helsinki" selected="@(Model.TimeZone == "Europe/Helsinki" ? "selected" : null)">EET &mdash; Helsinki</option>
<option value="Europe/Moscow" selected="@(Model.TimeZone == "Europe/Moscow" ? "selected" : null)">MSK &mdash; Moscow</option>
</optgroup>
<optgroup label="Asia / Pacific">
<option value="Asia/Dubai" selected="@(Model.TimeZone == "Asia/Dubai" ? "selected" : null)">GST Dubai</option>
<option value="Asia/Kolkata" selected="@(Model.TimeZone == "Asia/Kolkata" ? "selected" : null)">IST India</option>
<option value="Asia/Bangkok" selected="@(Model.TimeZone == "Asia/Bangkok" ? "selected" : null)">ICT Bangkok</option>
<option value="Asia/Shanghai" selected="@(Model.TimeZone == "Asia/Shanghai" ? "selected" : null)">CST Beijing / Shanghai</option>
<option value="Asia/Tokyo" selected="@(Model.TimeZone == "Asia/Tokyo" ? "selected" : null)">JST Tokyo</option>
<option value="Australia/Sydney" selected="@(Model.TimeZone == "Australia/Sydney" ? "selected" : null)">AEST Sydney</option>
<option value="Pacific/Auckland" selected="@(Model.TimeZone == "Pacific/Auckland" ? "selected" : null)">NZST Auckland</option>
<option value="Asia/Dubai" selected="@(Model.TimeZone == "Asia/Dubai" ? "selected" : null)">GST &mdash; Dubai</option>
<option value="Asia/Kolkata" selected="@(Model.TimeZone == "Asia/Kolkata" ? "selected" : null)">IST &mdash; India</option>
<option value="Asia/Bangkok" selected="@(Model.TimeZone == "Asia/Bangkok" ? "selected" : null)">ICT &mdash; Bangkok</option>
<option value="Asia/Shanghai" selected="@(Model.TimeZone == "Asia/Shanghai" ? "selected" : null)">CST &mdash; Beijing / Shanghai</option>
<option value="Asia/Tokyo" selected="@(Model.TimeZone == "Asia/Tokyo" ? "selected" : null)">JST &mdash; Tokyo</option>
<option value="Australia/Sydney" selected="@(Model.TimeZone == "Australia/Sydney" ? "selected" : null)">AEST &mdash; Sydney</option>
<option value="Pacific/Auckland" selected="@(Model.TimeZone == "Pacific/Auckland" ? "selected" : null)">NZST &mdash; Auckland</option>
</optgroup>
<optgroup label="South America">
<option value="America/Sao_Paulo" selected="@(Model.TimeZone == "America/Sao_Paulo" ? "selected" : null)">BRT São Paulo</option>
<option value="America/Buenos_Aires" selected="@(Model.TimeZone == "America/Buenos_Aires" ? "selected" : null)">ART Buenos Aires</option>
<option value="America/Sao_Paulo" selected="@(Model.TimeZone == "America/Sao_Paulo" ? "selected" : null)">BRT &mdash; São Paulo</option>
<option value="America/Buenos_Aires" selected="@(Model.TimeZone == "America/Buenos_Aires" ? "selected" : null)">ART &mdash; Buenos Aires</option>
</optgroup>
<optgroup label="UTC">
<option value="UTC" selected="@(Model.TimeZone == "UTC" ? "selected" : null)">UTC</option>
@@ -538,7 +538,7 @@
});
});
// Theme radio â€" map light/dark ↠paper/ink surface system
// Theme radio &mdash; map light/dark â†' paper/ink surface system
document.querySelectorAll('input[name="theme"]').forEach(radio => {
radio.addEventListener('change', function () {
var surface = this.value === 'dark' ? 'ink' : 'paper';