Appearance
Trial 001 — delivery notes
Per BRIEF.md §8.3. Produced 2026-07-02 from exactly two inputs: BRIEF.md and assets/tokens.json. Everything below is a place the brief made me propose, guess, or deviate — listed candidly, since surfacing these is the point of the trial.
1. Proposed values inside the 40 (flagged /* proposed */ in theme.css)
| Token | Value | Rationale |
|---|---|---|
--ns-color-accent-soft | #e6f2f4 | The teal scale has no tint — teal-100 #00a4c2 is fully saturated, unusable as a soft fill. Light tint of brand teal. |
--ns-color-danger-soft | #fbecee | Red exists only as red.500. ~6% tint over white. |
--ns-color-danger-border | #eba4af | ~40% tint of red.500. |
--ns-color-warning | #8f6400 | No amber/yellow anywhere in tokens.json. Calm ochre; 5.3:1 on white, 4.7:1 on warning-soft. Harmonized with the warm gray-01 family. |
--ns-color-warning-soft | #f8f0dd | Companion tint. |
--ns-color-warning-border | #e0c88d | Companion mid tint. |
--ns-color-text-faint | #9ea2a2 | Value is brand (gray-08) but only extracted as border.dark; the role is my proposal. 2.9:1 — decorative/disabled only, never meaning-bearing text. |
--ns-color-success-border | #c4e2a2 | Value is brand (green-02); the pairing with the success role is mine. |
--ns-font-mono | system mono stack | No mono in tokens.json. System stack chosen because §7 bans font CDNs and demands self-hostable fonts. |
--ns-radius-lg | 20px | Only sm 11px / md 13px / full 50% extracted; continued the step. |
--ns-radius-full | 999px | Deviation. Brand border.radius.full is 50%, which is circle-only — on a pill (progress track, tier badge) it renders elliptical corners. Used 999px and kept 50%-style circles working (they still render round at 999px). |
2. Proposed tokens beyond the 40
--ns-radius-none: 0px— the brand's own buttons and form controls are square (button.border-radius: 0px,form.control.border-radius: 0px), but the 40-token contract offers no zero radius and bans radius literals. As delivered, buttons use--ns-radius-sm(11px) — i.e. the contract makes the brand's own button shape unbuildable. Either add radius-none or state that NanaSelect buttons are intentionally rounded.- A font-size/line-height scale (
--ns-font-size-sm/lg/xl,--ns-leading-*) — §3.1 says hardcoded font literals fail the build, yet the only size token is--ns-font-size-base(19px). The brief itself specifies a 19–31px type scale plus 15–17px small print; every one of those sizes in my mocks is a px literal because there is no token to reference. The contract contradicts its own coverage. - A public-tier mid shadow (
--ns-shadow-mdre-tiered, or--ns-shadow-lg) — extractedshadow.mdis0 3px 9px rgba(0,0,0,0.5): a modal-grade shadow (tokens.json uses it formodal.dialog.shadow). On a "calm, confident" public card it is oppressive. I kept the brand value per §3's "use it" rule and simply never used it in the mocks — which means the theme ships a token the design refuses to touch. --ns-color-selected-control(or similar) — brand radios/checkboxes fill green (form.radio.checked-fill: #74a63a), but the 40 tokens offer no form-control color. I used--ns-color-accent(teal) for selection, which reads well but deviates from the extracted brand control color. Green selection would also collide semantically with the success/nudge register.
3. Content the brief lacked (every guess, named)
Stepper (stepper.html)
- All education copy. The brief supplies exactly one line ("STC 45 means normal speech next door is inaudible"). The three paragraphs are mine, including the claim that STC ~35 blurs conversation — plausible acoustics, but unverified by any brief data.
- The option list. Names, count (4), order, thresholds (STC 35 / STC 45), and the existence of a "Not sure yet" skip option are all invented. The brief names the factor but carries zero factor options.
- Step position. "Step 6 of 14" assumes the §6 factor list is in canonical order and that "interior + exterior acoustic control" is two factors (the only way the list yields 14). Never stated.
- The factor's one-line description — mine.
- Whether an answer is pre-selected on revisit — I show one selected to demonstrate the selected state; unspecified.
- Keyboard toggle-clear. "Re-click clears" is specified for click only; clearing via keyboard (Space on a checked radio) fights native radio semantics. The mock handles Space; arrow-key behavior is left native. The brief should state the intended keyboard contract.
Results (results.html)
- Tier assignments. 645 = Premium, 640 = Mid, SL45 = Budget, 545 = Premium, 840 = Mid — all invented. The brief names the four tiers and the 24 systems but never maps one to the other, even for its own hero example.
- The answer set driving the recommendation. The rationale ("interior, commercial, speech privacy, stack to one side") is a plausible invention.
- What the cheaper alternatives still satisfy. No per-system attribute data exists in the package (no STC per system, no duty ratings), so the nudge copy is qualitative ("everything except certified speech privacy") — asserted, not derived. This is the hero element and I had to make up its central factual claim.
- Shortlist membership. NW Acoustical 545 and NW Aluminum 840 as "close matches" — invented.
- System descriptions — all one-liners are mine.
- No photography was attached, so the "photo · name · tier" anatomy cannot be shown with a photo; both mocks render the required no-photo collapsed state instead. Fortunate that §5 demands that state, but the package cannot produce the primary presentation at all.
- Link targets — configurator deep-link shape and resources URLs unknown; all
href="#".
Global
- Header/chrome. The brief never describes the app's header: wordmark? logo? nav? exit link? I invented a minimal "NanaSelect by NanaWall" text wordmark. No logo asset was attached.
- Footer content — invented one sentence.
- No font files or @font-face guidance — §7 requires self-hosted fonts but the package includes none; mocks declare the families and fall back to system fonts. Also note tokens.json encodes weights as separate family names ('Source Sans Pro Light/Semi-Bold' — legacy webfont naming) and as numeric weights; I used single family + numeric weights.
4. Ambiguities and contradictions in the brief itself
- §3.1 vs tokens.json on
success-soft. The brief lists success soft/border among "known gaps with no extracted source," but tokens.json plainly carriescolor.background.highlight/ green-01#f0f8e8— a natural success-soft (it is even used as the brand sidebar active fill). I brand-sourced it; the brief contradicts its own attachment. bgvssurface. Both map naturally tobackground.primary(white); the brief never says whether the page ground is white or the warm#f4f2ed. I chose white ground + white cards separated by borders, withsurface-muted=#f4f2edfor the education callout. A different reading (warm ground, white cards) is equally defensible.text-mutedvstext-subtle. The extracted scale offers#6e6e6eand#707070— visually identical (2 RGB points apart). A four-step text ramp cannot be built from tokens.json without proposing values; the two middle steps are effectively one color.- Focus color = accent color (
#00798ffor both). A focus ring on a teal primary button is invisible; I compensated withoutline-offset: 2pxso the page background creates the gap. The brief should say whether focus must contrast against accent fills. - "One primary action per screen" vs "the nudge has its own action." On results, the configurator CTA and the nudge CTA are both card-level buttons. I resolved it by register — one teal primary, one green success button — but the brief's two rules pull against each other on its own payoff screen.
- "Compare these 3" — 3 = recommendation + 2 nudge alternatives, or the shortlist? I assumed the former; unstated.
- Nudge scope. Does the call-out present one cheaper alternative or the whole 645 → 640 → SL45 chain? I rendered the chain as one card with two alternative rows and one shared action — a guess.
- Long education vs mobile fold. "Never collapsed" education plus 3 paragraphs (H4 explicitly tests 3-paragraph education) pushes the options well below the fold on a phone. I complied literally; the brief should state its mobile stance for long education (it forbids collapsing but doesn't address scroll cost on the P1 phone flow).
- Tier presentation. "Equal-weight fit descriptors" — I rendered every tier as an identical neutral outline pill. Whether tier may be color-coded at all, or should be more prominent, is unstated.
- Radii vs brand geometry. tokens.json is emphatic that interactive brand elements are square; the 40-token contract forbids a 0px radius (see §2 above). Which wins — brand fidelity or contract expressibility — is the brief's call to make, not mine.
--ns-color-overlayis untestable in this trial — defined per contract, but public surfaces use no modals and admin is out of trial scope; nothing in the P1 deliverables can exercise it.- Progress semantics. "Announces N-of-M to screen readers" — I used
role="progressbar"+aria-valuetext; a step-list witharia-currentis an equally valid reading. Unspecified. - tokens.json breakpoints (375/540/768/1024/1366/1600) disagree with §7's breakpoints (480/768/1024/1280). I followed §7 as the app contract, but the two sets should be reconciled or the divergence acknowledged.
5. Deviations from principle, and why
- Buttons rounded at
--ns-radius-sminstead of brand-square — forced by the missing zero-radius token (§2, item 1). --ns-radius-full= 999px, not brand50%— 50% breaks pills; 999px preserves both pills and circles.--ns-shadow-mdretained at the brand's heavy value but unused — the "use the brand source" rule and the "calm" aesthetic could not both be satisfied by using it, so it ships accurate and idle.- Teal (accent) selection state on radios instead of the brand's green control fill — no control token exists, and green selection would blur into the nudge's success register on the same screens.