# Canada Fig Shutdown Plan

Fig has asked Acorn to shut down Fig, the Canada lender, by **Mon 10/5/2026 at 5:00 PM PDT** (`2026-10-06T00:00:00Z`).

After that time, no one can submit a new Canada application. Applicants who already have active offers can still view and select them.

- **By Monday:** PAW v5 (section 1) and the Borrower Platform (section 1b).
- **Follow-up:** the Lowest Payment Amount API (section 6). No partner uses it today.

PAW v5 keeps showing the payment widget to Canadian applicants. Clicking **Learn more** opens a popup with the message below on the partner's page, instead of opening the loan app in a new tab, so partners don't need to change anything. The Borrower Platform shows the same message as a notice card on its Canada pages:

> **We've temporarily paused new loan applications**
>
> We can't accept new loan applications in Canada right now. Please check back at a later time.

## Approach

- **Unversioned `dist/` only.** All three live Canada partners load `dist/af-box.min.js` or `dist/shared/af-standard.min.js`, so a `src/` change reaches them on the next `main` deploy. **Except Joist:** Joist production pins an SRI build (5.5.3), which is frozen and never pauses. SRI 5.7.0 (`versions/5.7.0/af-box.min.js` with the new `integrity` hash) adds the widget popup; Joist can switch when convenient. Not required for Monday: the Borrower Platform shows the pause message to Joist users.
- **Time-gated.** We deploy early. The widget switches to the paused popup at the cutoff, so nobody has to deploy at 5 PM Monday.
- **Test override.** `?cafig=off` on the page URL forces the paused state before the cutoff.
- **Do NOT touch `src/versions-org/*` or `versions/*`.** These are frozen builds that older partner pages and demos may still pin with SRI hashes. Each SRI version is frozen on `fs.acornfinance.com` and copied in on `main` deploys (see `amplify.yml`), but editing `versions-org` would still change what QA and UAT serve.

## Quebec: French and English

For Quebec, follow the pattern the Borrower Platform already uses for the "not available in Quebec" message (`src/components/2025-11/CalculatorHero.vue`): **French first**, then English in slightly smaller text with a small globe icon. Every other province stays English only.

**When it applies:** the province is `QC`, `Quebec` or `Québec` (any case, trimmed). Check the applicant's province, which is `personalInfo.state` in PAW and the `province` or `state` URL parameter in the Borrower Platform, the same way `PaymentCalculatorCanadaPage-cv-0500.vue` reads it today.

| | French (shown first) | English (shown second) |
|---|---|---|
| Title | Nous avons temporairement suspendu les nouvelles demandes de prêt | We've temporarily paused new loan applications |
| Body | Nous ne pouvons pas accepter de nouvelles demandes de prêt au Canada pour le moment. Veuillez revenir plus tard. | We can't accept new loan applications in Canada right now. Please check back at a later time. |
| Button | Fermer | Close |

- [ ] **Get the French reviewed** by a fluent speaker (and compliance, if needed) before it goes live. The text above is a proposed translation.
- [ ] Mark the French block `lang="fr-CA"` so screen readers pronounce it correctly. Done in PAW.
- [ ] Use one shared copy object (FR and EN strings) in each repo so the French and English text can't drift apart. Done in PAW: `COPY` in `src/shared/af-ca-paused-popup.js`.

## 1. Widget code

The first commit (`088a4192`) hid the widget (`display: none`, `PayAmt Hidden`). We then changed the approach: the widget stays visible with its current copy, and clicks open a paused popup.

### `src/af-standard.js`

- [x] Add `static CANADA_PAUSE_AT = Date.parse('2026-10-06T00:00:00Z') // Fig shutdown 10/5/2026 5PM PDT`
- [x] Add `_isCanadaPaused()`. It returns true when `_isCanada()` is true and either the current time is at or past `CANADA_PAUSE_AT` or the URL has `?cafig=off`. Wrap the URL read in try/catch.
- [x] `_onClick(e)`: when paused, call `preventDefault()` and `stopImmediatePropagation()`, then `_showCanadaPausedPopup()`. This covers the standard Canada row, the box Canada layout and its Learn more, the compact layout, `_fallBackHtml`, and the `kind="popup"` / iframe paths. `AcornPopup.openPopupLink()` (the regular popup's Apply button) has the same check, for a popup opened before the cutoff.
- [x] `_clickedOnLinkToPage(e)`: the standard Canada Learn more is a real `<a href target="_blank">`. When paused, prevent the default action and show the popup instead. The `href` stays, so a ctrl/middle-click reaches the Borrower Platform, which shows its own paused notice.
- [x] `_showCanadaPausedPopup()`: reuse `<acorn-ca-paused-popup>` or append a new one to `document.body`, call `open(this)`, and post `Canada Paused Popup Shown`.
- [x] `_logLoadActivity()`: after the usual `PayAmt Loaded` / `PayAmt Updated` post, also post `PayAmt Canada Paused` (`Canada paused - Fig shutdown 2026-10-05 5PM PDT`) when paused.
- [x] `postActivity()`: add `platform_data.canadaPaused` (`1` / `0`) to every log row.
- [x] Bump `widgetVersion` to `5.5.6-PaymtAmtLib`.

### `src/shared/af-ca-paused-popup.js` (new)

- [x] The `acorn-ca-paused-popup` LitElement, statically imported by `af-standard.js`, so there's no extra chunk to fetch on click.
- [x] A fixed overlay (`z-index: 9999999`) with a white dialog containing the cream notice (amber "!", title and body, as in the Borrower Platform mockup), plus a Close button and ×.
- [x] `role="dialog"` and `aria-modal`. Focus moves to Close on open, Tab stays inside the dialog, and focus returns to the element that opened it (the Learn more link) on close. Esc, a backdrop click, × and Close all close it.
- [x] **Quebec:** add `_isQuebec()` to `AcornStandard`, which checks whether the province from `getProvince()` (`personalInfo.state`, else `companyInfo.state`, the same value sent as `province=`) is `QC` or `QUEBEC`, with accents stripped. `open(trigger)` reads `trigger._isQuebec?.()`. When it's true:
  - render the French title and body first, then a thin divider, then the English title and body, with the globe icon before the English title at the smaller English size
  - label the button **Fermer / Close** and give × the `aria-label` "Fermer / Close"
  - point `aria-labelledby` at the French title, and mark the French block `lang="fr-CA"`
  - keep the English-only layout for every other province

### `src/af-box.js`

- [x] No paused-specific code is needed, because box clicks go through `_onClick`. Bump `widgetVersion` to `5.5.6-box-PaymtAmtLib`.

## 1b. Borrower Platform (`borrower_platform` repo)

After the cutoff, Canada pages such as `/calc-connect?d=1001&ctry=CA` and `/apply?d=1001&ctry=CA` stay up. Each one shows a **paused notice card** at the top of the page content, and **every apply and Continue button is disabled**. Inputs stay as they are, and nothing redirects.

**Mockup:** [bp-canada-paused-mockup.png](bp-canada-paused-mockup.png) shows the mobile "Canada Pre-Qualify" (`/calc-connect`) and "Loan App 3" (`/apply`) screens.

The Borrower Platform switches to the Canada flow when the URL has `ctry=CA` or `country=CA` (`urlParamsStore.isCanadianFlow()`). Existing applicants reach their offers through `/access-offers`, `/magic-link` and `/offers`. `OffersPage.vue` sets the country to CA on its own when it finds a Fig Financial offer, so those pages must stay untouched: no notice and nothing disabled.

Work on a new branch off `main`. The current branch is `prod_your`.

### 1b.1 Time gate (`src/utils/canadaPause.js`, new)

- [ ] `CANADA_PAUSE_AT = Date.parse('2026-10-06T00:00:00Z') // Fig shutdown 10/5/2026 5PM PDT`
- [ ] `isCanadaPaused()`: true when the time is at or past the cutoff, `process.env.CANADA_PAUSED === 'true'` (QA/UAT testing and an early kill switch), or the URL has `?cafig=off` (the same test param as PAW).
- [ ] `isExistingAppRoute(path)` returns true for the routes that must keep working:
  - `/access-offers`, `/access-offers-if`, `/magic-link`
  - `/offers`, `/offers-if`, `/review-offered-amount`
  - `/mer-*`, `/no-offers*`
- [ ] `isCanadaNewAppPaused(route, urlParamStore)`: `isCanadaPaused() && urlParamStore.isCanadianFlow() && !isExistingAppRoute(route.path)`. The notice and every disable check below use this one function.

### 1b.2 Notice card (`src/components/canada/CanadaPausedNotice.vue`, new)

- [ ] Build one component and use it on both pages. Its look comes from the mockup and the existing `.canada-disclaimer-box` in `CalculatorHero.vue`:
  - a warm cream card: the `#FEF3C7` family, a little lighter in the mockup, so confirm the hex with design; 8px radius; no border; ~24–32px padding
  - on the left, the amber outlined "!" circle that `CalculatorHero.vue` already uses (`stroke="#F59E0B"`), top-aligned with the title
  - title in Open Sans 700, ~20px, `#03171A`: **We've temporarily paused new loan applications**
  - body in Open Sans 400, ~18px, `#03171A`: We can't accept new loan applications in Canada right now. Please check back at a later time.

    The calc-connect mockup originally had "now.Please" with no space; the image is fixed, and the copy above is correct.
  - `role="status"`, and no dismiss button
- [ ] Desktop width: match the column it sits in. That's the hero's left column on calc-connect, and the question column (`col-md-6`/`col-md-8`) on the loan app.
- [ ] On mount, push a `canadaPausedNoticeShown` dataLayer event with `dealerId` and the path, so GA/GTM tracks how many people still reach these pages.
- [ ] **Quebec:** add an `isQuebec` prop (or computed from the `province`/`state` URL param). When it's true:
  - show the French title and body first (`lang="fr-CA"`), then the English title and body
  - put the globe icon before the English part, and set the English slightly smaller
  - reuse the `.french-text` / `.english-text-qc` styles and the globe SVG from `CalculatorHero.vue`
  - add `quebec: true` to the dataLayer event

### 1b.3 Calc-connect (`src/pages/PaymentCalculatorCanadaPage-cv-0500.vue`)

- [ ] **Placement:** at the top of the hero's left column, above the "MARKETPLACE OF LENDERS" eyebrow. Add a `notice` slot to `src/components/2025-11/CalculatorHero.vue`, before `.hero-sec-div-sm` / `.overlap-group-calc-hero`, and fill it from the page with `<CanadaPausedNotice v-if="canadaNewAppPaused" />`. The card sits on the hero gradient, as in the mockup.
- [ ] **CTAs:** there are two "Check offers" CTAs, one in `CalculatorHero` (`.hero-cta-button`) and one in `FigWhyChooseSection` (`.why-choose-cta`). Both are `<a :href="ctaUrl" @click.prevent="$emit('cta-click')">` that call `redirectToApply()`.
  - Add a `ctaDisabled` prop (default `false`) to both components. When it's true, the CTA gets `aria-disabled="true"`, `tabindex="-1"`, no `href`, `pointer-events: none` and `cursor: not-allowed`, and the click doesn't emit.
  - Disabled style, from the mockup: the same `#016DE1` button at about 40–45% opacity, with white text.
  - `CalculatorHero` is shared with the US calculator pages, so the default must stay `false`.
- [ ] Pass `:ctaDisabled="canadaNewAppPaused"` to both, and make `redirectToApply()` return early when paused.
- [ ] **One notice only.** While paused, hide the existing "not available in Quebec / Nova Scotia / Saskatchewan" disclaimer (`:showDisclaimer="!isProvinceSupported && !canadaNewAppPaused"`). The paused notice replaces it, so Quebec visitors see one bilingual card instead of two.

### 1b.4 Loan app (`src/components/loan-app/LoanApplication.vue`)

- [ ] Add the `canadaNewAppPaused` computed.
- [ ] **Placement:** put `<CanadaPausedNotice v-if="canadaNewAppPaused" />` at the top of the question column, just inside `<form>` (line 28) and above `<loanAppQuestions>`. It then sits below the header progress bar and above the question title ("What's your Postal Code?"), as in the mockup.
- [ ] **Continue (`#LoanAppContinue`):** add `canadaNewAppPaused` to its existing `:disabled` and `:tabindex` bindings. Style it from the mockup: the primary blue at about 40–45% opacity, with white text. This also covers the "View Pre-Qualified Offers" label on the last step.
- [ ] **Answer buttons:** on `type: 'button'` / `'button-link'` questions, the buttons that advance the app get `:disable="canadaNewAppPaused"`, using the same faded style. These are the `q-btn`s inside `loanAppQuestions.vue` and in `LoanApplication.vue` around lines 157–218.
- [ ] **Inputs stay enabled.** The mockup shows the postal code field as normal, so don't disable the whole form with a `<fieldset>`.
- [ ] **Quebec:** pass `isQuebec` to the notice from the `province`/`state` URL param, or from `loanAppData.province` if it's already set to Quebec. The existing "We have yet to open for business in your selected province" dialog can't appear, because Continue is disabled.
- [ ] **Leave enabled:** "Not in Canada" (`switchToUSLoanAppFlow`, which clears `ctry=CA` and with it the notice and the disabled state), Back, and the close buttons on the info modals.
- [ ] **`handleContinueNext()` guard** (line 2854): return immediately when paused. This blocks Enter-key submits and programmatic calls such as line 2110.
- [ ] **Submit guard:** in the submit path (around line 2988, before `axios.post(this.apiEdpoints.loan_applications ...)`), re-check `isCanadaPaused()` and don't POST. This is the real block. It catches anyone who loaded the page before 5 PM, and anything that changes `currentPage` directly. The confirm-modal "Yes" buttons do `currentPage += 1`, which skips `handleContinueNext()`. When the guard trips, show the notice in place of the submit dialog. A 60-second `nowTick` data property (with `setInterval`, cleared in `beforeUnmount`) keeps `canadaNewAppPaused` current, so an open tab shows the notice without a reload.

### 1b.5 Tests (Vitest)

- [ ] `canadaPause.js`: before and after the cutoff (`vi.setSystemTime`), the ENV flag, `?cafig=off`, and the route allowlist. `/apply` and `/calc-connect` are paused, and `/access-offers`, `/offers` and `/mer-has-approved-account` are not.
- [ ] Mount `CalculatorHero` and `FigWhyChooseSection` with `ctaDisabled: true` and check that clicking the CTA emits no `cta-click`.
- [ ] Mount `CanadaPausedNotice` and snapshot the copy, once English-only and once with `isQuebec` (French first, then English).
- [ ] Calc-connect with `province=QC` while paused shows only the bilingual paused notice, not the old "not available in Quebec" disclaimer.
- [ ] Mount `LoanApplication` paused and check three things: the notice renders, `#LoanAppContinue` is disabled while the postal code input is still enabled, and `handleContinueNext()` makes no axios call.

### 1b.6 Docs and deploy

- [ ] Add `CANADA_PAUSE_README.md`, modeled on `MAINTENANCE_MODE_README.md`. Cover the cutoff, the notice card, what gets disabled, the existing-app allowlist, `CANADA_PAUSED`, `?cafig=off`, and how to re-enable Canada. Add a `CHANGELOG.md` entry and bump `package.json` to 6.3.2.
- [ ] Deploy to QA/UAT with `CANADA_PAUSED=true` to test, then to prod by **Mon 10/5 morning**. Prod doesn't need the flag.

### 1b.7 Server-side gap (recommended follow-up)

- [ ] This section only blocks applications in the browser. A direct POST to `borrower-platform-api` `POST /api/v1/loan_applications` (`Api::V1::LoanApplicationsController#create`) would still go through. Fig will presumably reject new apps on their side after 10/5 in any case. As a follow-up, add a time-gated guard in `create` that rejects Canada applications with `render_error(..., :unprocessable_entity)` and logs them.

## 2. Demo pages

The demo pages behave like partner pages: the widget shows, and Learn more opens the paused popup. There's no page-level notice, and nothing is hidden.

- [x] `canada-fig/canada-fig-box.html`: switch from the SRI-pinned `versions/5.5.1/af-box.min.js` to `/dist/af-box.min.js`, so the demo shows the current behavior.
- [x] Joist: every page with a Country dropdown is in a versioned SRI folder (`joist/5.5.x/`), so those stay as historical references. A new `joist/latest/joist-box-json-compact.html` (copied from the 5.5.3 compact page, with its CA JSON data) loads `dist/` like Joist prod. The folder isn't named `dist/` because `.gitignore` ignores that name.
- [x] `partners/index.html`: label the Canada Fig links "(paused 10/5/2026)", and add a preview link (`?cafig=off`) plus a link to this plan. The Joist index links the new `latest/` demo.

## 3. Docs

- [x] `canada-fig/README.md`: add a banner at the top saying Canada is paused as of 10/5/2026 5 PM PDT. The widget stays, Learn more opens the paused popup, and partners don't need to change anything. `README.html` renders the .md file, so it needs no edit of its own.
- [x] `canada-fig/ToDo-canada.md`: add a "Fig Shutdown 10/5/2026" section that links to this plan.
- [x] Add a one-line pause note to the "Canada Support" section of `paw/v5/README.md` and to `invoice-simple/README.md`.
- [x] `CHANGELOG.md`: add a `5.5.6` entry.
- [x] Save a memory for the Fig/Canada sunset.

## 4. Tests

`tests/canada-paused.spec.js` uses the route-intercept pattern from `tests/unigroup-logging-happy.spec.js` and pins the clock with `page.clock.setFixedTime`.

- [x] `canada-fig.html?cafig=off`:
  - the widget still shows "Financing options available"
  - `PayAmt Loaded` and `PayAmt Canada Paused` are logged, with `canadaPaused: 1`
  - Learn more opens the popup with no new tab, and `Canada Paused Popup Shown` is logged
  - Esc, Close and × each dismiss it
- [x] At the cutoff with no param: the popup opens.
- [x] Before the cutoff: Learn more opens `/calc-connect` in a new tab, and there's no popup.
- [x] US after the cutoff: there's no popup, and `canadaPaused: 0`.
- [x] `canada-fig-box.html?cafig=off`: the box Learn more opens the popup, logged once.
- [x] `joist/latest/joist-box-json-compact.html?country=CA&cafig=off`: the popup opens, logged with `dealer_id` `JST-ESTIMATE`.
- [x] `invoice-simple/ins-estimate.html?country=CA&cafig=off` at mobile width: the compact bar opens the popup.
- [x] `canada-fig.html?cafig=off&st=QC`: the popup shows the French title first, then the English title, with the button reading "Fermer / Close". `?st=ON` stays English only.

## 5. Outside PAW v5 / coordination

1. **Borrower Platform notice and disabled buttons (section 1b).** This is the real safety net. The widget popup doesn't stop people reaching `/apply?ctry=CA` and `/calc-connect` through:
   - QR codes already printed on PDF estimates
   - bookmarked links
   - the light-DOM fallback `<a>` on partner pages
   - a ctrl/middle-click on the Learn more link
   - partners still running a cached old build

   On all of those, section 1b shows the notice and disables applying.
2. **Calculator Open** (`calculator-open/`) passes `ctry` through to the borrower platform. If any partner uses it for Canada, the borrower platform pause page is what protects that path.
3. **Notify DripJobs, Invoice Simple and Joist.** They don't need to change anything: the widget stays, and Learn more opens the paused popup on their page. Let them know what their Canada customers will see.
4. **Deploy timing.** Merge widgets to `main` and deploy the Borrower Platform, both by **Fri 10/2, or Mon 10/5 morning** at the latest. Confirm the widgets-cdn cache TTL, or invalidate the cache, so the time-gated build is live well before 5 PM.
5. **Monitoring.** After 5 PM PDT, check the logs for two things:
   - `PayAmt Canada Paused` and `Canada Paused Popup Shown` rows from `DPJ-`, `INS-` and `JST-` dealer IDs, which show the pause is working and how many people still try to apply.
   - `PayAmt Loaded` rows with `country=CA` and an `app_version` below 5.5.6, which point to an old cached build (or a partner still on a pinned version).

   Add the new kinds and `platform_data.canadaPaused` to any reports or dashboards.
6. **Lender platform and Portal.** Turning off Fig routing and new Fig applications is backend work, outside PAW.
7. **Rollback / re-enable.** Change `CANADA_PAUSE_AT` in `src/af-standard.js` and in the Borrower Platform's `src/utils/canadaPause.js` (later, also in headway's `acorn_rate.rb`), or revert the commits.
8. **Optional cleanup.** `src/af-standard.js` line ~210 has an operator-precedence bug: `'...' + this.loanAmountRangeError ? a : b`. Because of it, `PayAmt Updated` logs show the wrong amount.

## Verification

1. Run `npm run build` and then `npm start`. Open `localhost:8001/partners/canada-fig/canada-fig.html?cafig=off` and check:
   - the widget looks the same as before
   - Learn more opens the paused popup with no new tab, and Esc, the backdrop, × and Close all close it
   - the Network tab has `PayAmt Loaded`, `PayAmt Canada Paused` and `Canada Paused Popup Shown` POSTs to `activity_log_for_payment_widgets`, with `platform_data.canadaPaused: 1`
2. Open the same page without `?cafig=off`. Before the cutoff, Learn more opens the Borrower Platform as it does today.
3. Open it with `?country=US`. The US widget works normally, with no popup.
4. Repeat step 1 on `canada-fig-box.html`, `ins-estimate.html?country=CA&cafig=off` (including the compact bar at mobile width) and `joist/latest/joist-box-json-compact.html?country=CA&cafig=off`.
5. Check that the existing versioned Joist pages (`joist/5.5.x/`) still load, which confirms `versions/` didn't change. Spot-check a PODS page as well.
6. Run `npx playwright test tests/canada-paused.spec.js`. The full suite also has 2 UniGroup specs that were already failing before this work.
7. The spec pins the clock on both sides of the cutoff, which covers the automatic switch at 5 PM PDT without the URL param.
8. **Borrower Platform.** With `CANADA_PAUSED=true` on QA (or `?cafig=off` locally), check that:
   - `/calc-connect?d=1001&ctry=CA&province=QC` and `/apply?d=1001&ctry=CA&province=QC` show the paused notice in French first, then English, with no second "not available in Quebec" box. `province=ON` is English only.
   - compare both pages side by side with [bp-canada-paused-mockup.png](bp-canada-paused-mockup.png) at 375px width and on desktop
   - `/calc-connect?d=1001&ctry=CA` shows the notice above "MARKETPLACE OF LENDERS", and both "Check offers" CTAs are faded and do nothing
   - `/apply?d=1001&ctry=CA` shows the notice below the progress bar. The postal code input still works, while Continue and every answer button are faded and disabled, and Enter does nothing
   - "Not in Canada" still switches to the US flow, which clears the notice and re-enables the buttons
   - `/access-offers?ctry=CA&aid=<existing Canada app>` and `/offers` show no notice, and existing Fig offers can still be viewed and selected
   - `/apply?d=1001&ctry=US` and `/calculator-cv-0006` are unchanged
   - with `?cafig=off` added mid-session (or the cutoff set a minute ahead locally), an application started before the pause makes no `loan_applications` POST

   Run `npm test` (Vitest).
9. **API (follow-up, section 6).** With `CANADA_PAUSED=true` on QA, `curl` `POST /lowest-payment-amount-link` three times:
   - `country=CA, state=ON`: returns the unsupported shape with `canadaPaused: true`
   - `country=CANADA`: same result
   - `country=US`: payment and link unchanged

   Run `bin/rails test test/models/acorn_rate_test.rb`.

## 6. Follow-up: Lowest Payment Amount API (`headway` repo)

This doesn't need to be live by Monday, since no partner uses the API today. Do it after the PAW and Borrower Platform release.

`POST /lowest-payment-amount` and `POST /lowest-payment-amount-link` both go through `AcornRate#calculate` in `headway/app/models/acorn_rate.rb`. Canada already has an "unsupported" response. After the cutoff, every Canada request returns that response:

```json
{ "value": null, "currency": "", "stateSupported": false, "loanAppUrl": "",
  "prefix": "Not available for your location", "linkLabel": "", "secondLine": "",
  "canadaPaused": true }
```

### 6.1 `app/models/acorn_rate.rb`

- [ ] Add `CANADA_PAUSE_AT = Time.utc(2026, 10, 6) # Fig shutdown 10/5/2026 5PM PDT`.
- [ ] Add `canada_paused?(country)`: returns `canada?(country) && (Time.current >= CANADA_PAUSE_AT || ENV['CANADA_PAUSED'] == 'true')`. The ENV flag lets QA/UAT test before the cutoff, and is an early kill switch for prod.
- [ ] `calculate`: after the `canada_loan_amount_supported?` line, add `state_supported = false if canada_paused?(data['country'])`. The existing code then returns the unsupported `prefix`/`linkLabel`/`secondLine` and `loanAppUrl: ''` with no further changes.
- [ ] Merge `canadaPaused: true` into the result when paused. The field is new, so existing callers are unaffected.
- [ ] Leave `countrySupported` as is. It means "recognized country", not "lending available".
- [ ] **Case gap.** `canada?` uses a case-sensitive list (`Canada CAN Can CA`). A partner sending `CANADA` or `canada` gets a **US** payment and a `/calculator` link today, and would still get one after the shutdown. Make `canada?` case-insensitive and strip whitespace. This also changes behavior before the cutoff: those requests start getting Canada handling, which is correct.

### 6.2 Logging

- [ ] When paused, write `Rails.logger.info "[CanadaPaused] lowest-payment d=#{data['d']} state=#{data['state']}"`. This runs on every request, because the BigQuery log only fires when `actionType` starts with `create`.
- [ ] Optional: add `country` and `canada_paused` to `LowestPaymentLog#attributes`. **Add the columns to the BigQuery table `activity_log_for_low_payment` before deploying**, or the inserts will fail.

### 6.3 Tests (`headway/test/models/acorn_rate_test.rb`, new)

- [ ] `travel_to` after the cutoff, Canada request: `stateSupported: false`, `loanAppUrl: ''`, prefix `Not available for your location`, `canadaPaused: true`.
- [ ] `CANADA` (uppercase) is treated as Canada.
- [ ] Before the cutoff, a supported Canada province is unchanged. This needs an `app_states` fixture.
- [ ] A US request is unaffected.

### 6.4 Docs

- [ ] `headway/docs/lowest-payment-amount-link.md` §5 Canada and the response-field table: document the pause, `canadaPaused`, and `CANADA_PAUSED`.
- [ ] `quotes-r-us/README-API.md`: note the Canada pause, and tell partners to hide the CTA/QR code when `loanAppUrl` is `""`.
- [ ] `quotes-r-us/demo-api-pdf.html`: it currently sets `href = data.loanAppUrl` even when it's empty. Show the fallback/hidden state instead.

### 6.5 Deploy

- [ ] Set `CANADA_PAUSED=true` in QA/UAT and test with curl. Then deploy headway to prod. Because of the time gate, a deploy after 10/5 takes effect immediately, and prod doesn't need the ENV flag.
