← Back to Blog

AI Subscriptions, API Keys and a Recovery Plan for Your Business

· 22 min read A brass switchboard on a wooden desk with golden cables plugged in, a small padlock beside it and a stack of three archive boxes under a desk lamp.

A subscription is for a person working in the apps and supported coding tools. An API key is for software: your customer app, scheduled jobs and CI. Most small businesses building their own software need both, with separate credentials and controls, even when the subscription includes API credits.

An AI coding agent helped you build a CRM connected to your store. Now you need to know which account the nightly summary uses, who can stop its spending, and how you recover from a damaged database. The cheap model is expensive if nobody can restore the records it changed.

Keep a useful coding subscription, meter the software's calls, prepare another provider, and make recovery steps easy to follow on a bad morning. Start without your own gateway if you don't need one.

Buy the right kind of access

Anthropic's Consumer Terms, section 3, restrict accessing the services by automated or nonhuman means except through an Anthropic API key or where Anthropic explicitly permits it. That exception matters. Supported coding tools can have subscription sign-in and supported scheduled workflows. It is not a blanket ban on using a coding assistant without typing every prompt yourself.

OpenAI's consumer terms separately prohibit programmatic extraction of data or output and account sharing. That wording does not replace the documented authentication rules for supported coding tools.

It also does not turn your personal login into a credential for a customer facing CRM. Use the documented authentication for each product. A subscription cookie copied into a background service is a poor foundation for a business.

The older advice that subscriptions and APIs always have completely separate benefits now needs a correction. We read the vendor pages on October 29, 2026. Eligible Claude Max and Team plans and ChatGPT Pro and Business plans offer API credits, with linking and eligibility requirements. The application still uses an API key. Its calls are still metered, and its budget still needs a limit. Claude credit rules, OpenAI credit rules.

Scroll to compare columns and rows when the table extends beyond the box.

Subscription Monthly billing, USD Annual billing, USD
Claude Pro $20 $200 paid upfront; vendor displays $17 per month
Claude Max 5x / 20x $100 / $200 Monthly only
Claude Team Standard $25 per seat $20 per seat per month
Claude Team Premium $125 per seat $100 per seat per month
ChatGPT Plus $20 No annual price quoted
ChatGPT Pro 100 / 200 / 500 $100 / $200 / $500 Monthly tiers
ChatGPT Business Standard $25 per seat $20 per seat per month
ChatGPT Business Premium $125 per seat $100 per seat per month

Prices are before tax, read October 29, 2026: Claude pricing, Max details, ChatGPT pricing, Business seats and Pro tiers. Claude Team and ChatGPT Business start at two seats.

Claimed Claude Max credits are $100 or $200 monthly; Team credits are $20 per Standard seat or $100 per Premium seat, pooled up to $500 monthly. OpenAI's credit documentation identifies Pro tiers with $100, $200 or $500 credits and Business credits of $20 per Standard or $100 per Premium seat, capped at $500 monthly. New subscribers face a seven day eligibility wait. Credits expire; annual Business grants are issued upfront for the year, while annual Claude Team grants refresh monthly. Pro on Claude and Plus on ChatGPT are ineligible. Check the linked credit rules before counting them as savings.

Choose a seat for the work you do. Occasional writing rarely justifies the largest plan. A daily developer may get good value, but allowances have limits and separately charged usage can change the bill.

Count the work before choosing the model

These vendor prices are US dollars per one million tokens, with input and output priced separately. We selected a strong and a cheap option from each provider, rather than comparing unlike price units. Anthropic pricing, OpenAI pricing, read October 29, 2026.

Scroll to compare columns and rows when the table extends beyond the box.

Model Input per million Output per million
Claude Opus 5.5 $4 $20
Claude Haiku 5.5 (prompts up to 100K tokens) $0.10 $0.50
GPT-6 Astra $10.00 $50.00
GPT-6 Luna $0.10 $0.50

Our assumed low case uses 1,000 input and 200 output tokens per email summary; 1,500 input and 300 output per reply; 800 input and 200 output per product description. The high case doubles those per task figures. For daily coding, assume 20 working days and 50 model calls per day, each using 20,000 input and 2,000 output tokens in the low case, double in the high case. These are planning inputs, not measured averages.

The low CRM total is 1,500 × 1,000 + 300 × 1,500 = 1,950,000 input tokens and 1,500 × 200 + 300 × 300 = 390,000 output tokens. Products use 200 × 800 = 160,000 input and 200 × 200 = 40,000 output. Coding uses 20 × 50 × 20,000 = 20,000,000 input and 20 × 50 × 2,000 = 2,000,000 output.

Monthly cost is input millions × input price + output millions × output price. For example, the low Opus CRM cost is 1.95 × $4 + 0.39 × $20 = $15.60.

Scroll to compare columns and rows when the table extends beyond the box.

Monthly workload, low to high Opus 5.5 Haiku 5.5 GPT-6 Astra GPT-6 Luna
1,500 email summaries and 300 replies $15.60 to $31.20 $0.39 to $0.78 $39 to $78 $0.39 to $0.78
200 product descriptions $1.44 to $2.88 $0.036 to $0.072 $3.60 to $7.20 $0.036 to $0.072
Daily developer, 1,000 calls $120 to $240 $3 to $6 $300 to $600 $3 to $6

These are gross token charges before eligible credits. The low Opus CRM bill is below a $20 seat; the high case and both Astra CRM cases are above it. All product cases are below it. Strong model coding is well above it. The cheap coding columns show arithmetic, not evidence those models can replace a capable coding agent. Keep fractions of a dollar visible rather than rounding a small bill to zero.

These estimates count total billed output, including reasoning tokens where billed. They exclude paid tools, storage, taxes, retries and regional processing surcharges. Input includes instructions and context. We assume standard global routing, synchronous requests, no cached input or batch discounts, and short contexts: each prompt stays below Haiku's 100,000 token threshold and uses OpenAI's Standard short context rates. A long coding conversation can exceed these assumptions quickly. If your data policy requires a specific processing region, verify the route and its price before using this worksheet.

For a person drafting the descriptions inside a subscribed app, the subscription's allowance may cover the work. For a store job generating them automatically, use the API route. Eligible claimed API credits may pay that meter; they do not change the credential or make usage unlimited.

An API script also does not supply the coding tool's interface, permissions and workflow. Both vendors exclude their coding tool's API use from these subscription API credit benefits. Signed-in coding allowances are separate; do not subtract the advertised credits from a Claude Code or Codex API bill.

Track the first week by caller and task, including retries and human corrections. Scale representative work to your monthly volume. Count the cost of drafts someone had to rewrite.

The choices between one subscription and an expensive API

Scroll to compare columns and rows when the table extends beyond the box.

Choice Good first job Catch to check
Cheaper model from your current vendor Classify emails, extract fields, draft routine text It can fail a task the stronger model handles; test actual outputs
Second US provider Review code and carry selected work during an outage Different tool formats, billing and data terms; one funded account is not a tested fallback
Open weights on a US host Approved extraction or coding tasks needing another model family Check the actual hosting region, subprocessors, logging and license
Local model Triage text, sort requests, prepare redacted context Hardware and administration still cost money; small models need narrow jobs
Self hosted LiteLLM Give several applications controlled routes to multiple providers You own another service, database, updates and recovery
Cloudflare AI Gateway Add usage visibility and selected routing without operating a gateway server Another processor handles requests; feature limits and log settings matter
Hosted router such as OpenRouter Reach several model providers through one account Check fees, provider selection and data policies before sending customer text

OpenRouter's pricing page, read October 29, 2026, lists a 5.5% Standard platform fee and an 8% Business fee applied to credit purchases, with inference prices passed through. Include that fee before calling a router cheaper. It is also another account and another data processor to review.

For customer information, our proposed policy is no customer data to China hosted APIs. That is a business risk choice, not a claim that every model developed in China transmits your prompts there. The National Intelligence Law translation and analysis discusses obligations under Chinese law and the limits of simplistic readings. Jurisdiction, contracts and the actual endpoint deserve review together.

Open weights on your machine or an approved US host are a different case. Model origin does not identify where inference happens. Check telemetry, serving software and external tools. Test behavior too; a US address alone does not settle confidentiality. Our CLI versus browser guide explains the data path.

Start local models with triage. Ordinary code validates proposed categories and a person handles uncertain cases. The local model, Codex and Claude workflow separates routing, drafting and review.

Give every caller a boundary

Write down data classes before choosing destinations: public catalog text, internal business information, customer identifiers, regulated records and secrets. Payment credentials and API keys do not belong in prompts. For each caller, record which classes it may read and which endpoints it may reach. Apply the same rule to fallbacks; an outage does not authorize a new destination for customer records.

Give the CRM, each scheduled job and CI different keys. Where provider keys lack the controls you need, use gateway virtual keys or application enforcement. Allow only the approved model aliases, set a monthly budget, and limit request size, output length, concurrent calls and retries. Put provider spending controls and billing alerts behind these controls. A dashboard budget may be an alert rather than a hard cutoff, and delayed accounting can overshoot. Test the behavior instead of trusting the label.

Use a separate admin and billing login, protected with multifactor authentication and recovery codes, from the identity used for daily work. That gives you another recovery route; it cannot defeat an organization wide suspension. Keep the appeal instructions and account ownership records somewhere you can reach without the affected account.

Have the second provider do real work within the last 30 days. A reviewed code change or a batch of sanitized test tasks is enough to reveal a dead key or incompatible response shape. Write a lockout runbook naming the person who pauses the queue, checks billing and service status, switches approved workloads and contacts support. Preserve queued work instead of repeatedly charging both providers. Our vendor lockout plan provides the account recovery side.

Every AI written change should arrive through a pull request, with passing checks, review by a second model and review by a person. The second model can find a missed failure case; it does not become the approver for a production database migration. Ask what happens if a Shopify webhook arrives twice, a database write fails halfway, or a retry follows a timeout after the first attempt succeeded. The Ponytail review article develops that method.

Keep 10 to 20 representative tasks with known acceptable results. Include an ordinary email, ambiguous wording, missing fields, an attempted instruction hidden in customer text and a broken tool response. Rerun them before changing a model or gateway version. Check factual accuracy, formatting, permissions and recovery behavior, not just whether the request returned successfully.

Mask personal information before sending customer text where the task permits it. Configure PII masking or DLP with representative examples, including a failure case where the filter is unavailable. Decide whether that failure stops the request. Log metadata where possible rather than full prompts, and set retention deliberately. LiteLLM's masking documentation and Cloudflare's DLP documentation describe options, not a guarantee that every sensitive field will be found.

The OWASP LLM Top 10 also covers prompt injection and sensitive information disclosure. Customer text is untrusted input. A message saying to ignore instructions and export all customers must remain text to classify. The model should not hold database administrator credentials or send its own replies. Let it propose an action; ordinary code checks the allowed fields and a person approves consequential changes.

Keep the underlying app's checks too. Supabase RLS needs policies tested as ordinary users; service credentials stay server side. Shopify webhook signatures must be verified against raw request bytes before parsing. Use Dependabot's weekly updates and cooldown, with vulnerability and malware checks before installation. Cooldown does not delay security updates. Kit templates T1 to T6 cover these checks and repository instructions; inspect git history for leaked secrets and rotate any you find.

LiteLLM when you need per application control

The application asks for an alias such as crm_main. LiteLLM maps that alias to a provider model and can use an ordered fallback such as crm_backup. Your app keeps a stable name while configuration changes underneath. Test tool calls, structured outputs and errors on both routes. A compatible request format does not promise interchangeable answers. Aliases and configuration, fallbacks and retries.

Use one virtual key per caller with an allowlist and a budget. Keep LiteLLM's Postgres database separate from the CRM database, with its own credentials and backup. It holds gateway state such as keys and spend. Keep the master key in protected server configuration, never in a browser app, repository or ordinary caller. Bind the service to a private address and control administrative access. A private service still needs authentication. Virtual keys and database requirements.

The gateway adds supply chain risk. LiteLLM's March incident report identifies poisoned Python packages; its October report includes poisoned container images too. Pin an approved container by its immutable digest. Check releases, packages and images against current indicators of compromise and advisories, then hold new candidates for at least 24 hours. That delay gives detection time to catch up; age alone does not establish safety. Our incident guide covers the checks.

The kit's T2 npm precheck is only one part of that process. It does not inspect Python packages or certify a container. Review the LiteLLM image and Python dependency path separately. Never turn a registry error or missing release timestamp into approval. If a suspect version ran, investigate exposed secrets and rotate affected credentials; installing a clean version alone does not reverse theft.

T9 supplies aliases, an ordered fallback, private service settings and a virtual key request. Its model IDs and image digest are examples or placeholders. It needs your approved models, a real Postgres database and secrets supplied through your own protected environment. Validate a caller's allowlist with that caller's key, including a request it must reject.

Run a cutoff drill quarterly. In staging, revoke the primary test key, submit representative work and measure recovery time and output quality. Confirm that rejected destinations remain rejected and the budget still applies. Then disable the gateway itself and follow the manual recovery instructions. A second provider behind one failed gateway is still unreachable.

Cloudflare AI Gateway can be simpler. Its pricing page lists core features as free across plans. Model usage still costs money; Unified Billing adds a 5% credit purchase fee. Our cost comparison uses your own provider keys. Configure authentication, logs, limits and dynamic routes, currently Beta; T10 demonstrates the request. Gateway tokens cannot be scoped to one gateway, so do not assume LiteLLM's per caller controls. Avoid personalized caching until you test isolation. The Cloudflare guide provides depth; current log allowances depend on when the account first created a gateway.

Keep a native batch path where it saves money. Translating every job into synchronous requests can discard a provider's batch discount, and moving between models can lose cache reuse. Our provider diversification guide explains why another route is not automatically a cheaper one.

Back up the application, not just the repository

Git recovers code. It does not recover yesterday's customer records or an uploaded invoice. Inventory each layer and define how much loss and downtime the business can tolerate. The following is our suggested policy, subject to your legal retention and deletion obligations.

Scroll to compare columns and rows when the table extends beyond the box.

Layer Short term copy Long term copy and recovery limit
Code and configuration Tag production releases; nightly independent git mirror Encrypted snapshots with monthly and yearly history; document how to rebuild
Database Nightly off provider roles, schema and data dumps; provider recovery where purchased Weekly and monthly snapshots; a dump loses changes after its timestamp
Uploaded files Weekly actual file copies; nightly if a week of loss is unacceptable Retain matching object snapshots; database metadata cannot recreate a file
Store platform Regular exports and theme source in git Monthly records; exported orders are not a complete store restore
Secrets and recovery Password manager; protected recovery codes and backup password Offline recovery copy; rotate compromised credentials before reconnecting restored systems

For restic, keep a local repository on a separate drive for fast recovery, with 7 daily and 4 weekly snapshots. Copy new snapshots to a second repository in the cloud storage you already pay for, keeping 7 daily, 5 weekly, 12 monthly and, as our example, 3 yearly snapshots. Check whether your account has enough available space and supports the required access method.

Use restic copy, never rclone sync, for that repository transfer. Independent repository retention is the point. A mirror can reproduce local pruning remotely and remove the older history you meant to keep. Check the remote copy before pruning locally, and schedule maintenance away from backup runs. Copying repositories, retention and pruning.

Google Drive is one worked option through restic's rclone backend. Use your own OAuth client and consider drive.file scope so access is limited to files that client creates. Test that scope with the actual backup repository. Upload limits and trash consuming quota can delay a large first copy. The Drive backup walkthrough and rclone documentation explain the setup. Keep the encryption password in a password manager and an offline recovery copy, not only on the computer being backed up.

An optional third copy can use a separately controlled Google Cloud Storage bucket. Its soft delete policy defaults to 7 days for new buckets and supports retention up to 90 days. Verify the actual policy and permissions. Soft delete offers a recovery window; it is not an unlimited or independently immutable backup. Separate credentials and administration reduce the chance that one stolen identity can remove every copy.

For Supabase, use the CLI dump and restore sequence, including roles, schema and data. Vault or column encryption needs the old project's encryption root key, which a SQL dump does not contain. Check your plan's backups and export Storage objects separately. Shopify's backup guidance explains export limits. Orders cannot be imported back through the admin. Reconcile recovery with the live store.

Test a restore monthly into a scratch folder and isolated database. Check row counts, representative records, file contents and application behavior. Rebuild on a clean machine quarterly, using credentials you can retrieve without the original computer. Alert on failed backups and silence: our example heartbeat raises an alert after 26 hours without a successful nightly run, including confirmation of the off site copy.

Use the restore ladder in T8. A bad deploy starts with the last good tag, after checking schema compatibility. A bad data change today calls for available point in time recovery or a dump restored into scratch. A problem discovered weeks later needs an older snapshot. A lost account, ransomware incident or dead machine requires a clean rebuild from an independent copy. Stop writers and preserve evidence before changing production. A restore that overwrites newer legitimate orders can cause a second incident.

What six small businesses might choose

These are illustrations, not customer stories. Task volumes and staffing are our assumptions. The low cost case uses the lower token estimates above; the high case doubles them. Human review time is additional.

A four person online retailer: staff lose track of customer messages between Shopify and their CRM. They keep one coding seat, use the API for the email workload above, and start with managed routing. Each morning a person reviews suggested replies beside the order record. They budget the CRM token range plus the managed gateway and backup case below, and test webhook duplication before any model change.

A three person bookkeeping firm: staff want help drafting requests for missing paperwork. Use sanitized templates in approved business tooling, or the CRM API estimate for application drafts. Staff review before sending. Check whether the firm's activities bring it under the GLBA Safeguards Rule; IRS Publication 4557 identifies professional tax preparers as covered financial institutions. Approve the data handling plan before sending client financial documents.

A seven person dental office: the receptionist needs clearer public website answers. Use the 200 description estimate for similar writing volume. Before sending patient data to a model, check HIPAA applicability, a business associate agreement with relevant services and an approved handling plan. A consumer subscription or US hosting location is not that plan. NIST's HIPAA guide, section 5.1.9, covers business associate contracts and cloud providers.

A two person property manager: maintenance messages arrive while both people are away from the desk. A local model proposes categories from redacted text; uncertain and urgent messages go to a person. The CRM token estimate bounds a hosted alternative. Existing suitable hardware has no new rental charge, but allow setup and administration time at the rate below. Do not buy hardware until the test set shows it handles the work.

A six person print shop: the owner wants faster first drafts of quotes. Use the product description token range for 200 draft descriptions of jobs, with the price calculated by ordinary code from approved rates. Staff check quantities and dates before sending. One supported seat can cover manual drafting; an integrated quoting application uses API credentials. The model never invents a discount or commits the shop to delivery.

A solo developer supporting client apps: daily coding uses the developer estimate, with a subscription where its supported tool and allowance fit. CI and client applications get separate API keys and budgets. A second provider reviews patches weekly, while client data remains separated. Add the gateway cost below only when several callers justify the operational work. A long context agent can consume more than this worksheet assumes.

What the gateway and backups cost over 36 months

This comparison assumes one gateway, an existing application and backup worker, and an existing separate local backup drive. It excludes model tokens, application hosting, new hardware, custom development, compliance work and major incidents. Both choices still need application backups. A managed gateway does not do that work for you.

The shared cost basis is $68.09 an hour, from the BLS administrator median wage of $47.66 divided by a 70.0% private industry wage share. DigitalOcean's small tier is $24 monthly, with 2 shared vCPUs, 4 GiB RAM and 80 GiB disk. We assume light gateway traffic and Postgres on that server. Test this capacity assumption; it does not include local inference.

For LiteLLM, use our shared planning range of 4 to 12 setup hours and 1 to 3 administration hours monthly, including updates and backup checks. For the managed option, our assumption is 2 to 4 setup hours and 0.5 to 1.5 hours monthly for configuration, bills, application backups and recovery exercises. Managed service time is lower, never zero.

Backblaze B2 provides a priced alternative. At $6.95 per TB monthly, with the first 10 GB free, our assumed 40 to 100 GB of retained encrypted data costs (40 − 10) × $0.00695 = $0.2085 to (100 − 10) × $0.00695 = $0.6255 monthly. Count all retained versions. These examples assume transfer and requests stay within included allowances; otherwise add those charges.

Scroll to compare columns and rows when the table extends beyond the box.

Cost, rounded to whole dollars LiteLLM low LiteLLM high Cloudflare core low Cloudflare core high
Setup labor $272 $817 $136 $272
Monthly server or gateway core fee $24 $24 $0 $0
Monthly backup storage $0 $1 $0 $1
Monthly total with administration $92 $229 $34 $103
36 month total including setup $3,595 $9,057 $1,369 $3,972

Formula: setup hours × $68.09 + 36 × (hosting + backup storage + monthly admin hours × $68.09). Calculate with unrounded amounts. The low case stores 40 GB; the high case stores 100 GB. The displayed zero for low storage is rounding, not free storage.

Self hosting costs $2,226 more in the low case and $5,086 more in the high case. Break even is never under these assumptions, because both setup and monthly cost are higher. If existing cloud storage has spare capacity, its incremental bill may be zero; administration remains. An outside IT provider's billable rate can exceed this employee compensation estimate, so get a quote.

The managed option wins this small workload on cost and operational effort. LiteLLM can still be worth paying for when you need its controls and have someone to maintain them. The private development server guide explains a place to run internal services. Our Apache small business guide applies the same labor first cost method to other software.

If your starting point is the business website itself, my book The $97 Launch covers getting that first site online on a small budget.

Download the review kit

Download the AI app setup review kit (.md). It contains Phases 0 to 3, evidence based checks, templates T1 to T10, the backup script, restore ladder and sources. Start with the read only inventory and review. Compare the findings from two models, finish the owner checks, then approve specific fixes as small pull requests.

The kit retains tested template structure, with generalized placeholders and explicit limits. Syntax checks are not proof of a working deployment. Run its restore and cutoff exercises in your own isolated environment before relying on it. Keep that recovery record beside the deployment instructions so another person can take over.

Related reading

Fact-check notes and sources

All reads below are October 29, 2026; times are UTC. Labor, hosting and storage use the shared same-day research. Workloads, retention and administration hours are our planning assumptions. These are documentation checks, not a new production installation.

  1. Anthropic terms, section 3: 23:07 UTC.
  2. Claude credit rules: 23:08 UTC.
  3. OpenAI credit rules: 23:08 UTC.
  4. Claude pricing: 23:07 UTC.
  5. Max plan details: 23:08 UTC.
  6. Anthropic pricing: 23:07 UTC.
  7. OpenAI pricing: 23:07 UTC.
  8. OpenRouter's pricing page: 23:11 UTC.
  9. Intelligence law analysis: 23:08 UTC.
  10. LiteLLM's masking documentation: 23:08 UTC.
  11. Cloudflare's DLP documentation: 23:08 UTC.
  12. OWASP LLM Top 10: 23:08 UTC.
  13. Aliases and configuration: 23:08 UTC.
  14. fallbacks and retries: 23:08 UTC.
  15. Virtual keys and database requirements: 23:08 UTC.
  16. March incident report: 23:11 UTC.
  17. October report: 23:08 UTC.
  18. pricing page: 23:08 UTC.
  19. dynamic routes: 23:08 UTC.
  20. Gateway tokens: 23:09 UTC.
  21. Copying repositories: 23:08 UTC.
  22. retention and pruning: 23:08 UTC.
  23. rclone documentation: 23:08 UTC.
  24. soft delete policy: 23:08 UTC.
  25. CLI dump and restore sequence: 23:08 UTC.
  26. your plan's backups: 23:08 UTC.
  27. backup guidance: 23:09 UTC.
  28. IRS Publication 4557: 23:15 UTC.
  29. NIST HIPAA guide: 23:16 UTC.
  30. BLS administrator wages: 21:12 UTC.
  31. BLS wage share: 21:17 UTC.
  32. DigitalOcean's small tier: 21:10 UTC.
  33. Backblaze B2: 21:10 UTC.
  34. Supabase RLS: 23:08 UTC.
  35. Shopify webhook verification: 23:08 UTC.
  36. Dependabot options: 23:14 UTC.
  37. ChatGPT pricing: browser review around 23:27 UTC.
  38. Business seats: same browser review.
  39. Pro tiers: same browser review.
  40. OpenAI consumer terms: same browser review; effective January 1, 2026.

This post is informational, not legal, financial or medical advice. Product names identify the services discussed; no affiliation or endorsement is implied. Check current terms, prices and your own regulatory obligations before committing data or spend.

← Back to Blog

Accessibility Options

Text Size
High Contrast
Reduce Motion
Reading Guide
Link Highlighting
Accessibility Statement

J.A. Watte is committed to ensuring digital accessibility for people with disabilities. This site conforms to WCAG 2.1 and 2.2 Level AA guidelines.

Measures Taken

  • Semantic HTML with proper heading hierarchy
  • ARIA labels and roles for interactive components
  • Color contrast ratios meeting WCAG AA (4.5:1)
  • Full keyboard navigation support
  • Skip navigation link
  • Visible focus indicators (3:1 contrast)
  • 44px minimum touch/click targets
  • Dark/light theme with system preference detection
  • Responsive design for all devices
  • Reduced motion support (CSS + toggle)
  • Text size customization (14px–20px)
  • Print stylesheet

Feedback

Contact: jwatte.com/contact

Full Accessibility Statement • Privacy Policy

Last updated: April 2026