Skip to content

Give appraisal intake fields persistent, programmatic labels - #154

Merged
nish3451 merged 45 commits into
mainfrom
chore/intake-persistent-labels
Aug 19, 2026
Merged

Give appraisal intake fields persistent, programmatic labels#154
nish3451 merged 45 commits into
mainfrom
chore/intake-persistent-labels

Conversation

@nish3451

@nish3451 nish3451 commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

What

Both appraisal intake forms — the homepage and /audit — named their two fields (website, email) only with placeholder text plus an invisible aria-label. Placeholder text disappears the moment a buyer starts typing, and aria-label is programmatic but never visible: neither is a persistent label.

Each intake field now carries a visible <label> caption bound to the input via label[for] / input[id], so the field's name:

  • stays on screen no matter what the field contains (persistent), and
  • stays the field's accessible name for assistive tech and browser validation announcements (programmatic).

Changes

File Change
public/index.html Form fields wrapped in <label for=..><span>caption</span><input id=..></label>; email placeholder becomes a sample value (you@company.com) since the caption is now the name
public/audit.html Same restructure
public/shared.css .lead.two pill re-laid-out as label columns with caption rules (desktop two-up, stacked mobile); divider moves to the label boundary
scripts/check-site.mjs Intake-label guard upgraded: each intake input must now have an id bound to a non-empty <label for> on the same page (was: aria-label alone)

Verification

  • npm test — all 92 tests pass (check, headings, sitemap, worker, ui, contract)
  • npm run check:render-blocking — all six pages PASS (font stylesheet non-blocking under production CSP)
  • Headless Chromium on a local copy of public/:
    • both labels visible (non-zero geometry) and bound via el.labels to the right inputs on both pages
    • caption still visible after typing in the field
    • no horizontal overflow at 1280x900 or 390x844
    • screenshots: /tmp/opencode/{index,audit}-*-form.png

Closes the unreviewed-by-grok item: Give both appraisal intake fields persistent, programmatic labels — the homepage and /audit.

Summary by CodeRabbit

  • Accessibility Improvements
    • Added persistent, descriptive labels to website and email fields.
    • Improved label-to-input associations for easier form navigation and usability.
    • Retained website URL validation across intake forms.
  • Style
    • Updated field spacing, borders, and mobile layout to support visible labels.
    • Simplified the email placeholder text.
    • Improved field organization and readability on desktop and mobile displays.

Both intake forms (homepage and /audit) named their fields only with
placeholder text plus an invisible aria-label: the name vanished the
moment a buyer typed, and aria-label alone is not a persistent label.
Each website/email field now carries a visible <label> caption bound
to the input via label[for]/input[id], so the name stays on screen
and stays exposed to assistive tech and browser validation.

- index.html and audit.html: wrap each input in <label><span>..</span>
  <input id=..></label>; placeholders become samples (you@company.com)
- shared.css: label columns with caption rules inside the .lead.two
  pill, desktop and stacked mobile treatments, divider moved to the
  label boundary
- check-site.mjs: intake-label guard now requires the for/id binding
  (persistent AND programmatic) instead of an aria-label alone

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 49cba628-6242-4d44-af92-e616f964d59b

📥 Commits

Reviewing files that changed from the base of the PR and between 763b078 and 07d5716.

📒 Files selected for processing (1)
  • scripts/check-site.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/check-site.mjs

📝 Walkthrough

Walkthrough

The intake forms now use visible labels associated with website and email inputs. Shared CSS styles the labels and mobile layout. Site checks validate id and for associations instead of aria-label attributes.

Changes

Intake form labeling

Layer / File(s) Summary
Labeled intake controls
public/audit.html, public/index.html, public/shared.css
The homepage and audit forms add visible labels with matching input IDs. The email placeholder changes to you@company.com. Shared styles format labels, separators, spacing, and mobile stacking.
Label association checks
scripts/check-site.mjs
The intake-form guard now requires non-empty input IDs and matching non-empty label[for] attributes. It no longer requires aria-label attributes.

Estimated code review effort: 2 (Simple) | ~10 minutes

Mergeability Score: ⚪ Minimal · up to 07d57

The change adds persistent visible labels to the appraisal intake fields and updates the corresponding validation checks; no actionable merge-blocking risk remains beyond normal checks and review.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding persistent, programmatic labels to appraisal intake fields.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/intake-persistent-labels

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c0607b8cdf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread public/index.html Outdated
Comment on lines +75 to +76
<label for="intake-website"><span>Your website domain</span><input type="text" name="website" id="intake-website" required inputmode="url" autocomplete="url" placeholder="yourwebsite.com" pattern="(https?://)?([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}(:[0-9]+)?(/[^\s]*)?" title="Enter your domain, like example.com"></label>
<label for="intake-email"><span>Your work email</span><input type="email" name="email" id="intake-email" required placeholder="you@company.com"></label>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply the label layout to the homepage stylesheet

The homepage loads only index.css, while the new label-column rules were added exclusively to shared.css, which is used by /audit. Consequently, on / the existing form.two input rules still assume the inputs are direct flex children: the wrapper labels receive no flex sizing or grid layout, the captions remain unstyled inline content, and both nested inputs match input:first-of-type, producing incorrect dividers and sizing in the primary intake form. Mirror the label rules in index.css or load a stylesheet that supplies them.

Useful? React with 👍 / 👎.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0528571d1a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-site.mjs
const labelBody = pageHtml.match(
new RegExp(`<label\\b[^>]*\\bfor="${id}"[^>]*>([\\s\\S]*?)<\\/label>`, "i")
)?.[1] ?? "";
if (!labelBody.trim()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate visible label text instead of raw markup

When a caption is emptied or removed while the input remains inside its <label>, labelBody still contains the <input> markup and therefore passes this non-empty check. The guard would consequently accept an intake field with no persistent visible label, defeating the regression protection introduced here; strip tags and verify non-empty visible text, or explicitly validate the caption element's text.

Useful? React with 👍 / 👎.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/check-site.mjs`:
- Around line 1656-1660: Update the label validation near labelBody to strip
nested markup and evaluate the label’s text content, requiring non-whitespace
visible text rather than merely any captured HTML. Preserve the existing failure
message and add a regression case covering a label containing only a nested
input.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f0bac28a-f916-4aef-97fc-6523330d2b0d

📥 Commits

Reviewing files that changed from the base of the PR and between 0e357e0 and e2000ef.

📒 Files selected for processing (4)
  • public/audit.html
  • public/index.html
  • public/shared.css
  • scripts/check-site.mjs

Comment thread scripts/check-site.mjs
Comment on lines +1656 to +1660
const labelBody = pageHtml.match(
new RegExp(`<label\\b[^>]*\\bfor="${id}"[^>]*>([\\s\\S]*?)<\\/label>`, "i")
)?.[1] ?? "";
if (!labelBody.trim()) {
failures.push(`Intake input on ${pageName} must be bound to a persistent programmatic <label for="${id}"> (placeholder-only labels disappear as buyers type): ${tag}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate label text, not only label markup.

labelBody.trim() succeeds when the label contains only the nested <input>. A future input-only label can therefore pass without a visible caption. Extract the label's text content and require non-whitespace text. Add a regression case for an input-only label.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-site.mjs` around lines 1656 - 1660, Update the label validation
near labelBody to strip nested markup and evaluate the label’s text content,
requiring non-whitespace visible text rather than merely any captured HTML.
Preserve the existing failure message and add a regression case covering a label
containing only a nested input.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f0acbfa317

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-site.mjs
Comment on lines +1656 to +1658
const labelBody = pageHtml.match(
new RegExp(`<label\\b[^>]*\\bfor="${id}"[^>]*>([\\s\\S]*?)<\\/label>`, "i")
)?.[1] ?? "";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject duplicate intake IDs before accepting labels

If a future edit accidentally assigns the same id to both intake inputs, each iteration finds the same first matching <label for> and this guard still passes. In the browser, both explicit labels then resolve to the first element with that ID, leaving the second field without the intended programmatic label; verify IDs are unique (and that each matched label resolves to the current input) before accepting the association.

Useful? React with 👍 / 👎.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e9b85850f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-site.mjs
Comment on lines +1656 to +1658
const labelBody = pageHtml.match(
new RegExp(`<label\\b[^>]*\\bfor="${id}"[^>]*>([\\s\\S]*?)<\\/label>`, "i")
)?.[1] ?? "";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore labels inside HTML comments

If an intake form is commented out while its old markup remains in the page, both the input scan and this label lookup still inspect the commented markup, so the check reports success even though the browser serves no intake controls. Strip HTML comments before scanning, as the canonical-link check above already does, so only live inputs and labels can satisfy this regression guard.

Useful? React with 👍 / 👎.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@nish3451
nish3451 merged commit 66f7bd6 into main Aug 19, 2026
3 checks passed
nish3451 pushed a commit that referenced this pull request Aug 19, 2026
…und transitions (2026-08-15)

Rebased onto main. Kept main's persistent intake labels from #154 and the
2026-08-12 study figures from #156; kept this PR's 2026-08-15 evidence
payload, fixture and tests.
nish3451 added a commit that referenced this pull request Aug 19, 2026
…und transitions (2026-08-15) (#227)

Rebased onto main. Kept main's persistent intake labels from #154 and the
2026-08-12 study figures from #156; kept this PR's 2026-08-15 evidence
payload, fixture and tests.

Co-authored-by: nish3451 <nishant345@users.noreply.github.com>
nish3451 added a commit that referenced this pull request Aug 21, 2026
…on on current main (2026-08-21) (#272)

The review item "Put a real 'Request the appraisal' action inside the
pricing page's closing callout" is already fixed on origin/main 92d55c3 by
merged PR #194 (76fe17b, 2026-08-19), hardened by #154 (persistent labels)
and #251 (44px tap targets). Re-verification-only closeout: the closing
.band form, the check-site.mjs guard, and the suite are all green; the live
page's missing form is the documented deploy lag to the pre-fix release pin
(release-state-tinystudio-io.json b4d80f1, 2026-08-17), not a source
regression.

Co-authored-by: minimax-vps <minimax-vps@local>
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant