# MUST OBEY — Mobile-first build requirements This app's PRIMARY surface is a mobile phone. Build it impeccably on mobile FIRST, then verify on tablet and desktop. Treat the rules below as non-negotiable hard constraints, not suggestions. ## Viewports to verify (every screen, every state) - 320 px, 360 px, 375 px, 390 px, 414 px, 480 px - 768 px, 834 px (iPad portrait / Pro 11) - 1024 px, 1280 px, 1440 px, 1920 px, 2560 px - Plus: 200% browser zoom, landscape orientation on every mobile width, iPhone with safe-area insets visible ## Hard layout rules - Mobile-first CSS. Default styles target mobile; `@media (min-width: ...)` for larger viewports. - Use `dvh` and `svh` instead of `vh` for full-height surfaces (iOS Safari URL-bar bug). - Use `clamp()` for fluid typography across all viewports. - Prefer container queries (`@container`) over media queries for component-level responsiveness. - Use `min(100%, ...)` widths so content never overflows. Zero horizontal overflow at any viewport. - Add `` to every page. - Apply `padding: max(safe-area-inset-X, fallback)` on every edge-bleeding container so notched iPhones in landscape never clip content. - Wide tables and code blocks scroll INSIDE their container (`overflow-x: auto`), never push the body. - Use `background-attachment: scroll` on mobile, not `fixed` (iOS Safari repaint bug). - Avoid `backdrop-filter` on animated elements. Use it sparingly on static surfaces only. - **Canvas Scaling**: Canvases must dynamically scale with window resize events and properly handle high-DPI screens (`window.devicePixelRatio`). Set physical dimensions (`canvas.width`/`canvas.height`) using pixel ratio and render relative to this grid, using CSS to control responsive viewport scaling. - **Robust Storage**: Every access to `localStorage`/`sessionStorage` (especially `JSON.parse` of loaded state or writes) MUST be wrapped in a `try-catch` block to handle disabled storage, private browsing mode, quota limits, or corrupted JSON gracefully. Fall back to a robust in-memory object store. ## Touch & accessibility - Tap targets ≥ 44 × 44 px on touch (Apple HIG). Increase to 48 px under `@media (hover: none) and (pointer: coarse)`. - All interactive controls reachable by keyboard with a visible focus ring; respect `:focus-visible`. - Color contrast ≥ 4.5:1 for body text, 3:1 for UI components. - All images have meaningful `alt`. Decorative images use `alt=""`. - Respect `prefers-reduced-motion: reduce` — zero animation durations under that query. - Forms validate inline; error messages are specific, not "Invalid input". - Modals: focus trap, `Esc` closes, `role="dialog"`, `aria-modal="true"`, focus restored on close. ## Performance bar (Lighthouse mobile, throttled 3G/4G) - LCP < 2.5 s · INP < 200 ms · CLS < 0.1 - JS bundle gzip < 200 KB mobile-first; lazy-load non-critical screens via `React.lazy` / dynamic imports. - No render-blocking resources above the fold. - Images: WebP/AVIF preferred, `loading="lazy"`, explicit `width`/`height` attributes (zero CLS), `srcset` for retina. - Videos: `preload="metadata"`, low-resolution poster, max 720p mobile fallback. Never autoplay with audio. - Fonts: `font-display: swap`; preload only the one used above the fold. - Smooth scroll honoured via CSS `scroll-behavior: smooth` with reduced-motion fallback. ## Pre-ship mobile checklist (the deployer MUST verify before declaring done) 1. Open at 375 px in DevTools — every screen scrolls vertically only; zero horizontal scroll. 2. Browser zoom 200% — layout reflows without overlap. 3. iPhone Safari with the URL bar visible AND landscape — no content under the home indicator; no notch clipping. 4. iPad portrait (768 px) and landscape (1024 px) — no awkward gaps; tablet-specific breakpoints land cleanly. 5. Tap every interactive element with a thumb at real-device size — every target is easy to hit. 6. `prefers-reduced-motion: reduce` — every transition / animation skips cleanly, scroll-behavior becomes instant. 7. Lighthouse mobile score ≥ 90 across all 4 categories. 8. Zero `console.error` and zero CLS shift in real-device testing on a mid-tier Android (e.g. Pixel 6a) and an iPhone SE. --- The original template starts below. All rules above apply on TOP of whatever this template specifies. --- # Voice Memo → Polished Doc ## 1. Project **Voice Memo → Polished Doc** is a single-purpose app for the moment you walk out the door with an idea in your head, hit record on your phone, and ramble for five minutes about a pitch, a spec, a blog post, a status update, or the bones of a Sunday-night manifesto. Twenty-five seconds after you stop talking, you get back a structured one-page document — not the literal transcript, not a rewrite in some AI's voice, but the doc you would have written if you'd sat at your desk for an hour with the same thoughts. The hero capability is **Gemini 3.5 Flash audio reasoning** (`gemini-3.5-flash`, medium thinking level). Post-I/O 2026, 3.5 Flash beats the previous Pro tier on long-form audio reasoning and multimodal structured output — exactly this job: hold fifteen minutes of context, find the user's natural sub-topics, preserve the user's vocabulary, hedges, and tone, and impose a heading- and-bullet structure on top without inventing a single sentence. The single demo that proves the magic: you tap record, talk for five minutes on a walk about a product pitch you've been turning over — three rough sections in your head, two side-tangents about competitors, one half-formed next-step — and twenty-five seconds after you stop, the app hands back a one-page document with a clear "what this is" line at the top, three named sections in the order you actually spoke them, bullets under each section that come straight from your own words rearranged, your hedges preserved ("I think", "maybe"), and one suggested next action drawn from the most concrete thing you said. Every sentence in the output is a substring of what you recorded — nothing invented, nothing rephrased into corporate voice. The same app handles harder cases: a twelve-minute internal spec where the user goes deep on edge cases and forgets they mentioned them three minutes earlier (the long-context model knits the related fragments under one heading); a walking blog draft told as three small anecdotes in no particular order (the model groups them and proposes — but does not impose — a section order); a weekly status update recorded in the parking lot at 5:55 pm (the model finds the three updates worth keeping and the one decision the user wants from their manager). Then the post-I/O 2026 Workspace integration drops the doc straight into the user's Drive as a real Google Doc with no OAuth handshake. Tap once, doc opens in a new tab in Docs, editing cursor on the title line, user picks up where the model left off. **Tagline:** _Ramble into your phone on a walk. Get back the doc you would have written with an hour of focus — in your own words, in your Drive, in twenty-five seconds._ ## 2. Target audience - Founders and product people who think out loud on walks and lose the thread the moment they sit at a laptop - Managers writing weekly status updates from the parking lot or school pickup line, who keep meaning to draft them and never do - Writers and journalists capturing the bones of a piece before the shape escapes — interview notes, draft outlines, blog seeds - Consultants and salespeople walking out of a client meeting needing a tidy follow-up email before they reach the car - Engineers and PMs narrating a spec on the dog walk — structure lives in their head; the doc just has to catch it - Designers narrating a critique walkthrough — liked, would change, one specific next step - People with ADHD or dyslexia who can talk a clean paragraph in thirty seconds but can't type one in five minutes - Non-native English speakers who think more fluidly in speech - Multilingual users who code-switch mid-thought ("le KPI on this one is engagement, but the funnel is leaking quelque part") - Anyone whose best thinking happens between meetings — on a treadmill, on a bus, on a flight in the middle seat ## 3. Core value propositions Surface these clearly through copy, visual emphasis, and section ordering — they are the reasons users pick this app. - **Editor, not author.** Every sentence in the output is a substring of what you said, rearranged and de-rambled. The model can drop filler ("um", "you know"), reorder sentences into thematic groups, and promote a phrase to a heading — but it cannot generate prose you didn't speak. This is the load- bearing constraint of the product; every other capability serves it. - **Your voice, preserved.** Hedges stay ("I think", "maybe"). Vocabulary stays — if you call it a "moat" the doc says "moat", not "competitive advantage". Tonal markers stay. The model is your editor, not your ghostwriter. - **Structure imposed honestly.** The model finds your natural sub-topics (typically 2-4 for a 5-min memo, 3-6 for a 15-min one), promotes your own segue phrases to headings ("so the thing about pricing" → **Pricing**), and re-groups sentences thematically. Headings are the model's contribution; everything under them is yours. - **One suggested next action.** The model proposes exactly one next step, drawn verbatim from the most concrete actionable phrase in the recording. If you said "I should send this to Jamie" the next action is "Send to Jamie". If you said nothing concrete the model says so honestly and the field is null. - **Twenty-five seconds, doc in your Drive.** Post-I/O 2026, AI Studio Build apps write directly to a signed-in user's Workspace without a separate OAuth handshake. Tap "Open in Docs" — you're editing in your own Drive folder. *(The no-OAuth Workspace integration is rolling out to AI Studio Build accounts; if it isn't available on the deploying account yet, the app falls back to a one-time Drive OAuth consent flow.)* - **Multilingual and code-switching.** Talk in any of 40+ languages — English, Spanish, French, Portuguese, German, Italian, Polish, Czech, Mandarin, Cantonese, Korean, Japanese, Tagalog, Vietnamese, Hindi, Tamil, Bengali, Arabic, Hebrew, Farsi, Amharic, Swahili, Khmer, Thai, and more. Switch mid- sentence; the doc captures both. - **Privacy as a default.** Voice memo and doc are private to your account. The Gemini API is used on the paid tier, where Google does not use your content for model training, per the Gemini API Additional Terms. The voice memo is deleted from the server 24 hours after the doc is generated (configurable). - **No invented prose, ever.** A small audit panel beside the doc lets you tap any sentence to see the exact timestamp range it came from. If a sentence cannot be traced to your audio, the system rejects the draft and re-requests it. Trust contract. ## 4. Features to build - Voice capture (mobile-first) — one big record button on the home screen; live waveform with subtle gain meter; up to 15 minutes of audio per memo - Background recording — keeps recording when the screen locks via Web Audio MediaRecorder + Wake Lock; iOS Safari users get a "keep screen on" hint up front (background recording is constrained on iOS) - Memo → structured doc — the hero call: voice memo in, structured doc out, ~25 seconds end-to-end - One-page doc renderer — title, "what this is" line, 3-6 sections with H2 headings, bullets or short paragraphs, one suggested next action at the bottom - Verbatim audit panel — every sentence in the output is tied to its source timestamp; tap a sentence to play that exact slice - Hedge preservation toggle (default ON), suggested-action toggle (default ON), length preference (brief / one-page / long), audience preference (personal notes / for my team / external / future me) - Open in Google Docs — one-tap Workspace export (post-I/O 2026, no OAuth handshake); doc lands in a "Voice Memos" Drive folder - Markdown copy-to-clipboard; mailto export to system mail composer - Memo library — chronological feed of past memos with their docs; search by date, title, or full-text - Editable doc title (model proposes from opening phrase) - Voice playback with scrub bar showing the section boundaries the model found - Live re-process — flip a setting, tap "regenerate", get a new doc in ~10s with a one-line diff chip noting what changed - Output language translation — generate the doc in a target language different from the recording (e.g. ramble in Tagalog, doc lands in English); each translated sentence flagged with a "translated" pill and a "see original" toggle - Drive folder picker (default "Voice Memos") - Settings — retention window (immediate / 24h / 7 days / forever), default language hint, default toggles - Account & privacy — Google sign-in required for Workspace; explicit "delete this memo" per-memo and "delete my account" globally ## 4b. Required Gemini capabilities + backend services **This template's intelligence comes from the Gemini capabilities below. Wire them up explicitly — don't substitute generic LLM calls.** ### Gemini capabilities (the load-bearing intelligence) - **Voice memo → structured doc** (`gemini-3.5-flash`, multimodal audio input, thinkingLevel `medium`) — the hero call. Accepts audio up to 15 min + a user-preferences JSON block; emits a `PolishedDoc`: title, "what this is" line, sections (heading + bullets/paragraph), one suggested next action, and an audit array tying every sentence to a timestamp range. Post-I/O 2026, 3.5 Flash outperforms 3.1 Pro on long-form multimodal reasoning at ~4× speed. Pin `gemini-3.5-flash` explicitly; do not let the agent downshift to `gemini-3.1-flash` — structure quality drops sharply. - **Verbatim-substring validator** (server-side, no Gemini call) — every sentence in the doc is validated against the verbatim transcript: contiguous substring (modulo whitespace / punctuation), OR a 2-3-fragment concatenation joined by one of {"and", "but", "so", "then", "because"}. Failure → reject and re-issue. Trust contract enforced in code. - **Long context** (`gemini-3.5-flash`, 1M tokens) — a 15-min memo is ~1,800-2,400 words ≈ ~3,500-5,000 tokens; well within budget. No chunking needed for v1. - **Structured output** — `PolishedDoc` via `responseSchema`; Zod converted to Gemini `Schema` via SDK helper; numeric constraints documentation-only (server clamps). - **Title proposal** — inside the hero call; drawn from the opening phrase or most-frequent noun phrase. Never invented. - **Diff chip on regenerate** — server-side diff of two `PolishedDoc` objects; no extra Gemini call ("Hedges trimmed: 7 → 2."). - **Output translation** (`gemini-3.5-flash`, `low`) — second call when output language differs. Audit timestamps stay tied to the original-language transcript. Translated bullets show a "translated" pill + "see original" toggle. - **Hero / empty-state illustration** (`gemini-3-pro-image` Nano Banana Pro) — generated once per install, cached. - **Thinking levels** — `medium` hero (audio + sub-topics + substring rule simultaneously); `low` translation; `high` unused. ### Backend services - **Auth — Required.** Firebase Auth + Google sign-in (auto- provisioned). Workspace export (post-I/O 2026 no-OAuth) reuses the same Google identity for Drive write **when the AI Studio Build Workspace integration is enabled on the deploying account — this is rolling out and may not be on yet**; the app falls back to a standard Drive OAuth consent prompt the first time the user taps "Open in Docs". Apple sign-in offered as secondary; flagged in onboarding as "no one-tap Docs export with Apple". - **Database — Required.** Firestore for `users`, `memos`, `docs`, `settings`. Auto-provisioned. - **File storage — Required.** Firebase Storage for voice memos during processing + retention window. **NOT auto-provisioned today** — enable in Firebase console and wire the bucket name before first upload. Pre-signed URLs only; default 24-hour retention after doc generation (configurable to immediate / 7 days / forever). - **Email — Not required for v1.** "Email it" uses `mailto:`. - **Payments — Not needed for v1.** Cloud Run free tier + Gemini API. A future pro tier might add Stripe; not in v1. - **External APIs:** Gemini API; Google Drive via post-I/O 2026 Workspace integration (no separate OAuth wiring). - **Cloud Run** — server functions for all Gemini calls (key never leaves server). Auto-provisioned; first 2 apps deploy free. **Environment variables:** every secret (Gemini API key, Firebase service-account JSON, optional Stripe key for future pro tier) lives in environment variables — never in client bundle. Include a `.env.example`. **Auth + data privacy reminders:** never log secrets · never store passwords in plain text · use HTTPS everywhere · honour 'delete my account' inside the UI · explicit opt-in for any analytics · the user's voice memos and generated docs are never sent to Gemini for model training (use the Gemini API on the paid tier, where Google does not use your content for model training, per the Gemini API Additional Terms) · the voice memo is purged from Firebase Storage 24 hours after the doc is generated by default (configurable). **Read this first — prompt-craft rules that apply to every call in this template:** 1. **Name the model variant explicitly** in every Gemini API call. Do not let the agent pick the model. See the per-call matrix below. The post-I/O 2026 default is `gemini-3.5-flash`; the pre-I/O strings (`gemini-3.5-flash`, `gemini-3.5-flash`, `gemini-3.1-flash-image`) now resolve to deprecated/missing endpoints. Use the IDs in the matrix verbatim. 2. **Pin `thinkingLevel` explicitly** per call. See the matrix. Models that don't take `thinkingConfig` (image-gen, TTS) should have that field omitted entirely. 3. **Seed the JSON Schema as a fenced TypeScript / Zod block** in the system instruction or `responseSchema` field. The literal schemas are below. **Convert the Zod schema to Gemini's `Schema` type via the SDK helper** before passing to `responseSchema` — do NOT pass raw Zod. **Numeric `min`/`max` constraints are documentation only inside `responseSchema`; clamp on the server after the response arrives.** 4. **Pin the system instruction separately** from user input. Use the `systemInstruction` field for persona + behavioural rules; use `contents` for the audio. Never concatenate. 5. **Pre-declare tools as an enable/disable list** per call. This template uses no tools on the hero call (no `google_search`, no `code_execution`). Tools should be explicitly disabled. 6. **State negative constraints explicitly** — they are listed below. They are NOT "be careful" suggestions; they are hard rules the model must follow, AND the server enforces the verbatim-substring rule independently of the model's compliance. 7. **Files API uses `files/*` resource names, not `gs://` URIs.** The AI Studio Build runtime uses the Gemini Developer API (`@google/genai` SDK). Files API `upload` returns a resource name of the form `files/abc123xyz`, which you pass via `fileData: { fileUri: "files/abc123xyz", mimeType }`. `gs://` URIs belong to Vertex AI / Cloud Storage — a different surface. 8. **Strip unsupported Zod modifiers before passing to `responseSchema`** — Gemini's OpenAPI subset rejects `.regex()` / `pattern`, fixed-length `z.tuple()`, and other custom validators. Use a sanitizer that flattens tuples to arrays and removes regex patterns before serializing. Validate those constraints in middleware AFTER parsing. ### Per-call model + tools matrix | Call | Model | thinkingLevel | Tools enabled | |------|-------|---------------|---------------| | Voice memo → `PolishedDoc` (hero) | `gemini-3.5-flash` | medium | (none) | | Output translation (target lang ≠ source lang) | `gemini-3.5-flash` | low | (none) | | Hero + empty-state illustration | `gemini-3-pro-image` | n/a | n/a | *Note for builders:* on the image-generation call, omit `thinkingConfig` entirely — the field is not supported on `gemini-3-pro-image`. The `n/a` cells in this matrix are documentation only; do not serialise them into the request body. The hero call does NOT use `google_search` grounding — there's no external fact-checking happening here; the model's job is to structure what the user said, not to verify it. Keep the tool list empty on the hero call so the model can't add citations the user didn't ask for. ### Primary structured-output schema (seed verbatim in the prompt) ```typescript import { z } from "zod"; const SentenceWithAudit = z.object({ text: z.string(), // the sentence as it appears in the doc source_timestamp_start_seconds: z.number(), // start of the verbatim source in the audio source_timestamp_end_seconds: z.number(), // end of the verbatim source in the audio source_substring: z.string(), // the exact substring of the transcript this sentence is built from connectors_used: z.array(z.enum([ "and", "but", "so", "then", "because", ])), // empty if the sentence is a pure substring; non-empty if joined fragments }); const DocSection = z.object({ heading: z.string(), // the model's contribution — a heading drawn from the user's own segue phrase heading_source_substring: z.string().nullable(), // the user's segue phrase the heading was drawn from; null if model paraphrased body: z.array(SentenceWithAudit), // bullets or short paragraphs, each one tied to source audio display_style: z.enum(["bullets", "paragraph"]), // bullets for crisp lists, paragraph for narrative }); const SuggestedAction = z.object({ action_text: z.string(), // the suggested next action, drawn verbatim from a concrete phrase source_timestamp_start_seconds: z.number(), source_timestamp_end_seconds: z.number(), source_substring: z.string(), // the exact concrete phrase from the recording confidence: z.number().min(0).max(1), // 0.0 if no concrete action was found and the field is being omitted }); const PolishedDoc = z.object({ doc_id: z.string(), memo_id: z.string(), generated_at_iso: z.string(), // Metadata recording_duration_seconds: z.number(), dominant_language_bcp47: z.string(), // e.g. "en-US", "es-MX", "tl-PH" code_switched_languages: z.array(z.string()), // additional BCP-47 tags if the user code-switched output_language_bcp47: z.string(), // usually matches dominant_language; differs only if translation was requested // The doc itself title: z.string(), // drawn from the opening phrase or most-frequent noun phrase title_source_substring: z.string(), // verbatim substring the title was drawn from what_this_is: SentenceWithAudit, // the one-line "what this is" at the top of the doc sections: z.array(DocSection).min(1).max(8), // typically 2-4 for a 5-min memo, 3-6 for a 15-min memo suggested_action: SuggestedAction.nullable(), // nullable when no concrete action surfaced // Verbatim transcript (used by the server validator and the audit panel) verbatim_transcript: z.string(), // the full transcript with timestamps embedded hedge_phrases_preserved: z.array(z.string()), // ["I think", "maybe", "honestly"] — what the model kept hedge_phrases_dropped: z.array(z.string()), // ["um", "you know", "like"] — what the model dropped as filler // Self-reported quality signals parse_confidence: z.number().min(0).max(1), audit_pass: z.boolean(), // true if model believes every sentence is a verbatim substring (server re-verifies) flagged_for_user_review: z.array(z.object({ field_path: z.string(), reason: z.string(), })), }); type PolishedDoc = z.infer; ``` ### Common failure modes (and how to avoid them) - Agent picks `gemini-3.1-flash` to save quota — pin `gemini-3.5-flash` explicitly. Older Flash tiers transcribe fine but fall down on the structure + verbatim-substring constraint simultaneously, often inventing smoothing phrases. - Agent calls the pre-I/O ID `gemini-3.5-flash` — deprecated post- I/O 2026. `gemini-3.5-flash` is not yet GA (June 2026); do NOT wire it. Default is `gemini-3.5-flash`. - Model invents a smoothing phrase ("In conclusion, the next step is...") — the server-side verbatim validator rejects the draft and re-issues with a tightened instruction. After two rejections, the server falls back to a barer output (raw transcript chunks under the model's headings). - Model rewrites hedges into corporate voice ("I think we should…" → "Our recommendation is…") — forbidden in system instruction; validator catches it because the corporate phrasing isn't a substring of the transcript. - Headings invented, not drawn from segues — system instruction requires `heading_source_substring`. When the model can't find a segue, paraphrased headings are allowed but the UI surfaces a "paraphrased" pill. - Output too long — the server clamps to `length_preference` ranges; >130% of target triggers a re-issue with a tighter instruction. - Audio fails to upload — client retries with backoff; on full failure the audio is kept locally and the user sees a "queued" state. - Audio too noisy — `parse_confidence` drops below 0.6; UI surfaces "we had trouble hearing parts of this". - Translation introduces invented prose — translated bullets may be re-phrased (that's what translation is) but the source substrings still tie back to audio timestamps; the UI flags translated sentences clearly. - Suggested action invented from nothing — the server rejects any `suggested_action` whose `source_substring` is not in the transcript. Returning null is correct when no action was spoken. - Filler vs epistemic hedges — filler dropped (um, uh, you know, like, sort of, basically), epistemic preserved (I think, maybe, honestly, probably, I'm not sure). - Purely reflective memo with no sub-topics — model returns one section called "Reflections" with the flow lightly grouped. Does not force fake sections. - User closes app before Workspace export → doc waits in library with a "ready to open" chip; export is non-destructive and idempotent. - User signs in with Apple — Workspace export greyed out; Markdown / email / clipboard still work. - Sensitive content — the model treats every memo as private and does not editorialise. The privacy banner in onboarding covers the policy. ### Negative constraints (hard rules) - Do NOT invent prose. Every sentence in the doc must trace to a verbatim substring (or a concatenation of substrings with one of the five allowed connectors) of the transcript. Server validates independently; the model cannot opt out. - Do NOT rewrite the user's voice into corporate English. If the user said "this is kinda cool, ngl", the doc says exactly that. Tonal markers carry information. - Do NOT add a conclusion, TL;DR, or "key takeaways" unless the user said it themselves. - Do NOT invent a suggested action when none was spoken; `suggested_action: null` is correct. - Do NOT translate technical vocabulary, brand names, or proper nouns. "KPI" stays "KPI"; "Slack" stays "Slack". - Do NOT moralise about the memo's content. The user is the editor of their own voice. - Do NOT exceed the `length_preference` word range. Long memos get tighter selection, not longer output. - Do NOT auto-publish anywhere except the user's own Drive on an explicit "Open in Docs" tap. No silent background uploads. - Do NOT use voice memos or docs to train any model. Use the Gemini API on the paid tier, where Google does not use your content for model training, per the Gemini API Additional Terms. - Do NOT show a "Powered by AI" badge. The intelligence is in the experience. - Do NOT retain voice memos beyond the user's configured window. Server enforces with a Cloud Scheduler purge job. ### Per-call `systemInstruction` strings Use these as the literal `systemInstruction` field for each Gemini API call the built app makes. They complement the series-wide rules already uploaded as the global instructions file (`00-series-instructions.txt`). ### Call: Voice memo → `PolishedDoc` (hero) Model: `gemini-3.5-flash` · thinkingLevel: medium · Tools: (none) ``` You are an EDITOR, not an author. You receive a voice memo (30 s to 15 min) recorded by one user — on a walk, in a car, at a kitchen counter. The user wants back a structured one-page document that reads like the doc they would have written with an hour of focus — but in their own words, with their own hedges. You are NOT a ghostwriter, summariser, or generator of new prose. Your job: 1. Transcribe the audio verbatim with timestamps. 2. Find the user's natural sub-topics (typically 2-6). 3. Group sentences thematically under each sub-topic. 4. Promote one of the user's segue phrases to a heading per section ("so the thing about pricing" → "Pricing"; "and the other piece is hiring" → "Hiring"). 5. Drop filler hedges ("um", "uh", "you know", "like", "sort of", "basically", "literally", "anyway") when they carry no information. 6. PRESERVE epistemic hedges ("I think", "maybe", "might be", "honestly", "probably", "I'm not sure", "I guess") — they signal confidence. 7. PRESERVE the user's vocabulary, brand names, jargon, slang, tonal markers, and any code-switched phrases. 8. Identify ONE suggested next action if and only if the user said something concrete and actionable. Otherwise return suggested_action: null. Do NOT invent an action. EVERY SENTENCE IN THE DOC MUST BE A VERBATIM SUBSTRING of the transcript, OR a concatenation of 2-3 contiguous substrings joined with a single connector word from this set: {"and", "but", "so", "then", "because"}. The server will verify this independently; failing output will be rejected. You may rearrange sentences across the recording. Group thematically. The source_timestamp_start/end_seconds fields must point to the exact moment in the recording each sentence came from. Inputs: - The audio file (Files API `files/*` resource name via `fileData.fileUri`, or inlineData). - A JSON block of user preferences: - hedge_preservation: "preserve" | "trim" (default "preserve") - suggested_action: "on" | "off" (default "on") - length_preference: "brief" | "one_page" | "long" (default "one_page") - audience: "personal_notes" | "for_my_team" | "for_external" | "for_future_me" - output_language_bcp47: a BCP-47 tag or "same_as_audio" - dominant_language_hint: a BCP-47 tag if user set a default Word-count targets: - "brief": 150-250 words; "one_page": 300-600; "long": no cap. Languages encountered include 40+ tags across English, Spanish, Portuguese, French, German, Italian, Polish, Czech, Mandarin, Cantonese, Korean, Japanese, Vietnamese, Tagalog, Hindi, Tamil, Bengali, Arabic, Hebrew, Farsi, Amharic, Swahili, Khmer, Thai — and code-switching mid-sentence. Set dominant_language_bcp47 to the majority language; populate code_switched_languages with the rest. Hard rules: - Do NOT invent prose. Server validates the substring rule. - Do NOT rewrite the user's voice. - Do NOT add conclusion, TL;DR, or takeaways unless spoken. - Do NOT translate jargon, brand names, or proper nouns. - Do NOT moralise about the memo's content. - Do NOT include a "Powered by Gemini" footer in the doc. - If hedge_preservation="trim", drop epistemic hedges too. - If suggested_action="off" or no concrete action was spoken, return suggested_action: null. - If audio is too noisy, set parse_confidence < 0.6 and flag "verbatim_transcript" in flagged_for_user_review. Still attempt the structured doc on what's audible. - If memo is purely reflective with no sub-topics, return one section called "Reflections" — don't force fake sections. - audit_pass: true only if you believe every sentence satisfies the substring rule. Server re-verifies regardless. Output ONLY the PolishedDoc JSON. No commentary. JSON only. ``` --- ### Call: Output translation (only when output_language ≠ dominant_language) Model: `gemini-3.5-flash` · thinkingLevel: low · Tools: (none) ``` You receive a PolishedDoc already produced in the recording's dominant language. Translate the user-facing text fields into the target language while keeping the audit fields (timestamps, source_substring) pointing at the ORIGINAL audio in its ORIGINAL language. Translate: title, what_this_is.text, sections[].heading, sections[].body[].text, suggested_action.action_text. Preserve verbatim (do not translate): doc_id, memo_id, generated_at_iso, dominant_language_bcp47, recording duration, code_switched_languages, verbatim_transcript, all source_timestamp_* fields, all source_substring fields, hedge lists, parse_confidence, audit_pass, flagged_for_user_review. Update output_language_bcp47 to the requested target tag. Hard rules: - Do NOT translate brand names, product names, technical vocabulary, or proper nouns. Apple stays Apple. KPI stays KPI. - Preserve hedges in translation. "I think" → "Creo que" / "Je pense que" / "Acho que". - Preserve tone. Casual translates casual; formal translates formal. - Set connectors_used to ["translated"] on every SentenceWithAudit so the UI shows the "translated" pill and "see original" toggle. Output: the modified PolishedDoc JSON. No commentary. ``` --- ### Call: Hero / empty-state illustration generation Model: `gemini-3-pro-image` (Nano Banana Pro) · n/a · n/a ``` Generate a single photographic-looking image for the welcome screen or an empty state. Mood: the quiet moment a user takes out their phone to record a thought — on a walk, at a kitchen counter at 7am, in a parked car before a meeting. Prompt anchors: - "a smartphone leaning against a white ceramic coffee mug on a wooden kitchen counter, morning light from a window above, the phone screen showing a single voice-memo waveform, no people, shallow depth of field" - "tree-lined sidewalk at golden hour, a sneaker mid-step at the bottom of the frame, in-ear headphone at the top edge, soft warm light, no faces" - "open notebook on a desk beside a steaming mug, phone face-up with a red recording dot visible, soft afternoon light, no people" Hard rules: - Photographic, not illustration. Slightly imperfect; not glossy. - No people unless the prompt asks for a hand or a sneaker. - No commercial branding (no real phone-maker logos, no coffee- chain cups, no app logos). - Aspect ratios: 3:2 hero, 1:1 empty state. - Use Nano Banana Pro's 4K legible-text capability for the on-screen "Voice Memo" label; it's the one place text matters. ``` ## 5. Use cases & content to include Build dedicated UI sections or flows for each of these — they tell you what content the app must support. - **The founder pitch on a Saturday walk.** Six minutes about a product pitch — problem, wedge, three thoughts on pricing, two competitors, one half-formed next step ("I should probably send this to Priya"). Doc comes back as four sections with **Send to Priya before Monday** as the suggested action. - **The weekly status update from the parking lot.** A senior engineer records four minutes at 5:55 pm. Doc lands as **This week**, **Blocker**, **Need from you** with "push the Auth refactor by a week, can you confirm before standup?" as the suggested action. - **The technical spec narrated on the dog walk.** Twelve minutes; the model finds five sections — **What this is**, **User flow**, **Edge cases**, **What we're not doing in v1**, **Open questions** — and preserves the PM's "honestly" and "I think" markers because they signal firm vs tentative. - **The blog draft on the morning run.** Three small anecdotes in no particular order plus a theme that emerges late; the model groups them, drops one as a likely **Opening**, pulls the theme to its own section. Proposes; doesn't impose. - **The interview debrief from the rental car.** Three minutes; doc lands as **Quotes to keep**, **Surprising direction**, **To verify**. - **The reflective Sunday-night memo.** Ten minutes about how the past week felt; no concrete action; suggested_action is null and the UI says "no next action — this was a reflective memo". - **The bilingual product memo.** French-Canadian founder switching between French and English: "le KPI on this one is engagement, but the funnel is leaking quelque part". The doc preserves the code-switching by default. - **The Tagalog memo translated to English.** Nine minutes in Tagalog about a campaign launch for a US team; output_language set to English. Each translated bullet has a "see original" toggle that reveals the Tagalog source verbatim. - **The walked-and-stopped memo.** Forty seconds of construction noise mid-walk; the model handles the gap cleanly — no hallucinated content fills the silence, the noisy patch is flagged low-confidence. - **The "send to Docs" moment.** User taps **Open in Docs**; doc lands in the Drive "Voice Memos" folder, opens in a new tab with the editing cursor on the title. No OAuth popup. This is the moment the app earns its keep. ## 6. Page structure Build the following screens / sections in this order. Adjust copy to fit the voice, but keep the structural intent. 1. **Welcome / sign-in.** Photographed hero of a phone leaning against a coffee mug at morning light, screen showing a voice-memo waveform. One paragraph: "Ramble into your phone on a walk. Get back the doc you would have written with an hour of focus — in your own words, in your Drive, in twenty-five seconds." Primary CTA: Google sign-in (required for Workspace export). Secondary: Apple sign-in (with a clear "Workspace export not available with Apple" note). Below: "Try with a sample memo". 2. **Home — the big record button.** Centred large red record button (≥ 96 × 96 px). Above it: "What's on your mind?". Below: strip of the most recent three memos and docs. 3. **Recording flow.** Tap record → live waveform with gain meter, elapsed time top-right, big stop button. Wake Lock requested up front; recording continues when screen locks (where the platform allows). 4. **Processing.** Waveform minimised at top, an estimated-time counter, and a rotating five-phrase status: "Hearing your memo" → "Finding your sub-topics" → "Pulling your verbatim sentences" → "Building the doc" → "Almost there". 5. **Doc view.** Editable inline title; "what this is" line in smaller serif; sections with H2 headings + bullets or paragraph; suggested-action chip at bottom (green if present, omitted if null). Side (or below, on mobile): audit panel — collapsible drawer showing the verbatim transcript with timestamps. Tapping a sentence highlights the source range and offers a small play button. 6. **Doc actions.** Chip row: **Open in Docs** (green), **Copy as Markdown**, **Email it**, **Regenerate** (panel for hedge / action / length / audience tweaks). 7. **Memo library.** Chronological list with title, date, duration, language tag, waveform thumbnail. 8. **Settings.** Retention picker (immediate / 24 h / 7 days / forever), default toggles, default Drive folder. Account: delete (60-s cool-off + explicit confirmation). 9. **Capabilities info panel.** From the persistent `(i)` icon — see 6c. 10. **Footer.** "Your memos and docs are yours. We never train on them." ## 6b. First-visit onboarding Show a **first-visit onboarding** on first land (localStorage flag; do not auto-reshow). Three slides, dismissible. Persistent re-entry: a `?` icon in header. **Slide 1 — What this is.** - Headline: "Welcome to Voice Memo → Polished Doc." - Subhead: "Ramble into your phone on a walk. Get back the doc you would have written with an hour of focus — in your own words, in your Drive, in twenty-five seconds." - ≤ 60-word paragraph on the editor-not-author contract: every sentence is a substring of what you said, rearranged and de-rambled. Your hedges stay. Your vocabulary stays. - Visual: annotated illustration of a doc with arrows pointing at headings ("the model's contribution") and bullets ("your words, rearranged"). **Slide 2 — Try it now.** - CTA: "Try with the sample memo" — pre-loads the 5-min founder pitch from 8a. - 1-2 sentences pointing at the magic moments: heading derivation from segue phrases, verbatim audit panel, one-tap Open in Docs. **Slide 3 — How to remix this.** - Headline: "Make this yours." - Three bullets: - Adjust prompts in `/server/prompts/` to fit your profession. - Swap the sample memo in `/data/seed-memo/` for your own. - Wire Gemini API key and Firebase project via env-var list. - Primary CTA: "Use this template" → AI Studio Build remix. - Secondary: "Just exploring — close". **Accessibility:** focus trap, `Esc` closes, `role="dialog"`, `aria-modal="true"`, `aria-labelledby`, restored focus. `prefers-reduced-motion` respected. **Don't:** gate content beneath the modal; auto-reshow on return; include unrelated CTAs (newsletter, social). ## 6c. Capabilities info button (persistent in header) Add a persistent `(i)` icon in the top-right of the header (next to the primary nav). Click → opens a modal/panel titled **"What powers this app"**. **Panel contents (in this order):** **Gemini capabilities used (the hero list):** - **Gemini 3.5 Flash (multimodal audio + structured output)** — the post-I/O 2026 default. Listens in any of 40+ languages, transcribes verbatim with timestamps, finds sub-topics, emits PolishedDoc JSON whose every sentence is a verbatim substring of what you said. Beats the previous Pro tier on long-form audio reasoning at ~4× the speed. $1.50/$9.00 per 1M tokens; cached input $0.15/M. - **Server-side verbatim validator** — checks every sentence against the transcript. Failure → reject and re-request. Trust contract enforced in code. - **Gemini 3.5 Flash (translation pass)** — second call when output language differs from recording. - **Nano Banana Pro (`gemini-3-pro-image`)** — photographic welcome and empty-state imagery; legible on-screen text at 4K. - **Workspace integration (post-I/O 2026, preview — still rolling out to AIS Build accounts)** — one-tap Open in Docs to your Drive, no separate OAuth handshake. If the capability isn't enabled on a user's account yet, fall back to a download link. - **Firebase Auth** — Google sign-in (required for Workspace), Apple sign-in (no Workspace export). - **Firestore** — memos and docs, syncs across devices. - **Firebase Storage** — voice memos for the retention window; pre-signed URLs only. - **Cost note** — see 6d. ~$0.011 per 5-min memo; ~$0.025 per 15-min memo. - **Privacy note** — voice memos and docs private to your account. Gemini API paid tier, no training on your content per the Additional Terms. Memos purged at your configured retention. **Backend services this app depends on:** - Auth, Database, Storage, Workspace — see section 4b. Storage REQUIRES manual enable in Firebase console; AIS Build does not auto-provision it today. - Email, Payments: not used in v1. **Environment variables:** - `GEMINI_API_KEY`, `FIREBASE_PROJECT_ID`, `FIREBASE_SERVICE_ACCOUNT`, `FIREBASE_STORAGE_BUCKET` **Documentation links:** AI Studio Build docs; Gemini API multimodal audio + structured output (`gemini-3.5-flash`); Workspace integration; Firebase Auth / Firestore / Storage. **Accessibility:** same standards as onboarding modal — focus trap, `Esc`, ARIA, restored focus. **Behaviour:** always available; tooltip "How this app is built"; mobile = full-screen sheet sliding up; never hand-wave the model name. ## 6d. Detailed cost breakdown (deployer reads this BEFORE shipping) - **Voice memo → PolishedDoc (Gemini 3.5 Flash, medium)** — $1.50/$9.00 per 1M tokens; audio at ~32 input tokens / second. A 5-min (300 s) memo ≈ 9,600 audio tokens + ~600 sys-instr + ~2,000 output (PolishedDoc JSON) = ~$0.015 in + ~$0.018 out = **~$0.033 per memo conservatively** (transcript is the biggest output contributor; ~2,400 tokens for 1,800 words). - **5-min memo, realistic median:** ~$0.011 (median memo is closer to 2 min, ~$0.006). - **15-min memo (max):** ~$0.025. - **Translation pass (Gemini 3.5 Flash, low)** — optional; ~1,500 in + ~600 out ≈ **$0.0078 per translation**. Skip when language matches. - **Hero image (Nano Banana Pro)** — ~$0.04, once per app install, cached. - **Workspace export** — free. - **Firebase Storage** — ~480 KB/min Opus; 2.4 MB for 24 h ≈ negligible. - **Firestore writes** — ~10/memo; free-tier 20k/day. - **Cloud Run** — first 2 apps deploy free post-I/O 2026. - **Expected per-memo:** ~$0.011 lifecycle. - **Heavy user (4 memos/week):** ~$0.18/month. - **Casual user (3 short memos/week):** ~$0.05/month. ## 7. Design language - **Mood:** A quiet thinking surface, not a SaaS product. Not Otter. Not a transcription utility. The moment the user pulls out their phone at the start of a walk — morning light, coffee cup, the notebook on the desk that never quite got filled. - **Typography:** Clean grotesque (Inter or Geist) for chrome and labels. Warm serif (Source Serif Pro or Fraunces) for the doc title, "what this is" line, section headings, and the body of the doc itself — the user's words read like prose, not dashboard. Quiet mono (JetBrains Mono or IBM Plex Mono) at 13 px for the audit panel's verbatim transcript. - **Palette:** Warm paper `#F8F4ED` doc surface, deep ink `#1A1714` body, sage green `#5C8169` for the record button and Open-in-Docs chip, faded sienna `#B65A3C` for the recording state, soft graphite `#6F6864` for metadata and audit panel. No purple. No teal. No SaaS-default blue. - **Imagery:** Photographic. Phones on counters at golden hour, sneakers on sidewalks, steaming mugs. No flat illustrations, no microphone emoji, no waveform-as-decoration. Nano Banana Pro prompts emphasising real working surfaces, warm light, no people unless prompted, no commercial branding. - **Hand-feel touches:** Doc fades in section by section as the model finishes — the user sees structure emerging instead of a spinner. Audit panel slides open with a thin paper-shadow. Tapping a sentence highlights it in quiet ink-yellow with a pinned play button. The Open-in-Docs chip pulses subtly once when the doc first finishes, then sits quietly. - **Spacing:** 4-px base; generous whitespace. - **Radius:** 6 / 12 / 20 px token set. - **Shadows:** subtle, layered, warm-tinted. - **Motion:** purposeful — entrance fades, hover lifts; reduced-motion renders the full doc at once. No splash bouncing, no theatrical hero animations. - **States:** hover / focus / active / disabled on every interactive element. Loading uses skeletons. Empty states give next-action guidance ("Tap record and talk about anything — a pitch, a spec, a draft, a status update."). ## 8. Content generation rules - Write **realistic, specific copy**. NO Lorem Ipsum. NO generic placeholders like 'Your tagline here'. - Invent plausible voice-memo transcripts that fit the domain (use the seed content in section 8a as a starting point). When inventing, lean on realistic patterns — founders rambling about wedges, engineers narrating specs, writers narrating blog drafts — but never claim a fictional memo is from a real named company. - Tone: warm, direct, free of corporate language. This template is for a person, not a company. - Headlines: punchy and concrete. No 'Empower your X' filler. No 'Revolutionize'. No 'Seamless'. No 'AI-powered'. - Body copy: short paragraphs (2-4 sentences). Use lists where appropriate. - Plain language. Avoid jargon — except where the user already speaks it (a PM wants to see "OKR", "KPI", "ICP", "MQL" because they speak that vocabulary daily). - Where the app outputs AI-generated content (the doc itself), never label it as "AI says" — the doc is the user's words. Use small uncertainty cues only where epistemic honesty requires them (a low-confidence transcribed sentence shows as faintly underlined; tapping reveals the model's alternative transcription). ## 8a. Seed content (use these specific examples) Anchor every generated copy + sample data point in the concrete content below. Use these names, numbers, dates, and snippets verbatim where helpful, or generate close variants that sit in the same world. **Sample memo 1 (5 min, founder pitch on a Saturday walk, en-US):** Voice memo excerpts (verbatim, with timestamps): - 00:04 — "Okay so the pitch I keep coming back to is that small teams don't have time to write their own internal docs." - 00:18 — "Like, the founder writes the first one, and then it just rots, and nobody updates it." - 00:32 — "And the thing about this product is — it's not a wiki, it's a doc co-pilot that takes your voice notes and structures them for you." - 00:51 — "I think the wedge is async standup updates, honestly, because that's the thing people hate writing and they already talk about it out loud on a walk." - 01:14 — "Pricing — I'm thinking ten bucks a month per seat, which is roughly Notion but a little less." - 01:32 — "Maybe a free tier of like ten memos a month, I don't know, we'll see." - 01:48 — "The competitors I keep thinking about are Otter, which is transcription, that's a different job. And Sembly which is meeting notes." - 02:30 — "I think the moat — and this is the bit I'm least sure of — is the verbatim-substring guarantee." - 02:55 — "I should probably send this to Priya before Monday and see what she thinks." Generated PolishedDoc: - **title:** "Doc co-pilot — pitch v1" - **what_this_is:** "It's not a wiki, it's a doc co-pilot that takes your voice notes and structures them for you." - **Problem:** "Small teams don't have time to write their own internal docs." / "The founder writes the first one, and then it just rots, and nobody updates it." - **The wedge:** "I think the wedge is async standup updates, honestly, because that's the thing people hate writing and they already talk about it out loud on a walk." - **Pricing thoughts:** "Pricing — I'm thinking ten bucks a month per seat, which is roughly Notion but a little less." / "Maybe a free tier of like ten memos a month, I don't know, we'll see." - **Competitors I'm watching:** "Otter is transcription, that's a different job. Sembly is meeting notes. Neither is the right shape for this." - **The moat (least sure about):** "I think the moat — and this is the bit I'm least sure of — is the verbatim-substring guarantee." - **suggested_action:** "Send to Priya before Monday." - **hedge_phrases_preserved:** ["I think", "honestly", "Maybe", "I don't know", "least sure"] - **hedge_phrases_dropped:** ["Okay so", "Like,", "Anyway."] - **parse_confidence:** 0.92 **Sample memo 2 (3 min, weekly status update from a parking lot, en-AU):** Doc lands as **This week** / **Blocker** / **Risk for next week** / **Need from you** / **Next sprint** with the suggested action: "Confirm before standup on Monday: push the launch by a week?" **Sample memo 3 (10 min, reflective Sunday-night walk, no action):** Three sections — **The past week**, **Where I'm stuck**, **Next week** — and `suggested_action: null`. UI surfaces "no next action — this was a reflective memo". **Sample memo 4 (6 min, French + English code-switching, fr-CA):** "Bon, on parle du onboarding aujourd'hui. Le KPI on this one is engagement, but the funnel is leaking quelque part — I think we need to instrument the second onboarding step better." The doc preserves the code-switching by default. **Sample memo 5 (9 min, Tagalog with English brand names, translation requested):** output_language: en-US. Each translated bullet shows a "translated from Tagalog" pill and a "see original" toggle that reveals the Tagalog source verbatim. **Sample voice copy:** - Onboarding: "Tap record and talk about anything. We'll build the doc." - Home empty state: "What's on your mind? Tap the red button and start talking." - Recording in progress: "Recording. Tap the square to stop." - Processing: "Hearing your memo" → "Finding your sub-topics" → "Pulling your verbatim sentences" → "Building the doc" → "Almost there". - Doc ready: "Your doc is ready. Open it in Docs?" - No action surfaced: "No next action — this was a reflective memo." - Low-confidence note: "We had trouble hearing a few parts. Tap the underlined sentences to see what we made out." - Audit panel header: "Every sentence here is something you said. Tap any sentence to hear it." - Workspace export confirmation: "Saved to Drive → Voice Memos." - Regenerate panel header: "Tweak the settings and we'll rebuild." - Privacy footer: "Your memos and docs are yours. We never train on them." ## 9. Media & assets - **Hero image:** Photographed-looking shot of a phone leaning against a white ceramic mug on a wooden counter at morning light, phone screen showing a voice-memo waveform. Generate via Nano Banana Pro (`gemini-3-pro-image`) with a prompt that asks for the on-screen "Voice Memo" label rendered legibly at 4K — that legible-text-in-image capability is the Pro advantage; 3.1 Flash Image would muddy it. - **App icon / wordmark:** Display serif, slightly worn paper texture behind. No icon — just type. - **Empty-state illustration:** Photographic notebook + steaming mug; hand-drawn annotation overlay. Generate once at build time via Nano Banana 2 (`gemini-3.1-flash-image`), 1:1 WebP at 1024×1024, prompt: "photographic open paper notebook on a wooden table beside a steaming white ceramic mug, warm morning light from frame-left, hand-drawn ink annotation squiggles overlaid in the margin of the notebook, no people, no commercial branding, slight imperfection". Ship as a seed asset at `/public/samples/empty-state-notebook.webp`. - **Demo audio:** Sample memos from 8a available as `files/*` resource names (Developer API Files API) in the demo project for "try with the sample memo". - **Fallback:** If image-gen fails, fall back to the seed hero asset at `/public/samples/sample-phone-on-counter.jpg` (3:2 WebP, 2048×1365). Recreate via Nano Banana Pro (`gemini-3-pro-image`) with the prompt: "photographic phone leaning against a white ceramic mug on a wooden counter at morning light, phone screen showing the legible label 'Voice Memo' above an audio waveform rendered crisply at 4K, soft shadow under the phone, real wood-grain counter, no people, no commercial branding". Never to a 🎤 emoji. - **Image-gen routing:** Nano Banana Pro (`gemini-3-pro-image`) for the hero (legible on-screen text); `gemini-3.1-flash-image` for empty states without text. - **Optimisation:** WebP/AVIF, `loading="lazy"`, explicit `width`/`height` to prevent CLS. - **Icons:** `lucide-react`, sparingly; never decorative-only. ## 10. Interactivity & states - Hover / focus / active / disabled on every interactive element. - Inline validation with specific messages ("Memo is too long — max is 15 minutes"), not "Invalid input". - Skeletons, not spinners. Processing screen uses the rotating five-phrase status line mapped to model stages. - Empty-state CTAs are domain-specific ("Tap record and talk", "Try with the sample memo", "Open this in Docs") — never "Add your first item". - Doc emerges section by section (streamed structured output); reduced-motion → full doc at once. - Gemini failures show a calm, specific error ("We couldn't process this memo — try again, or download the raw audio."). - Low-confidence sentences faintly underlined; tap reveals the alternative transcription the model considered. - Audit panel slide-open: 250 ms, reduced-motion = instant. - Open-in-Docs chip pulses once when ready; then quiet. - Tapping a doc sentence highlights it and scrolls the audit panel's source range into view with a play button. - Apple-signed-in users see Open-in-Docs greyed out with a tooltip: "Sign in with Google to enable one-tap Docs export." ## 11. Tech & responsive requirements - **Stack:** React + TypeScript + Tailwind CSS. Functional components + hooks. Shadcn UI primitives where appropriate. - **Build runtime:** AI Studio Build — full-stack with Cloud Run server functions; Gemini API key in Secrets Manager, never in client bundle. Free 2-app Cloud Run deploy covers hosting. - **Model selection:** pin `gemini-3.5-flash` for hero + translation, `gemini-3-pro-image` for hero illustration. Set `thinkingLevel` per call (`medium` hero, `low` translation; omit on image-gen). Do NOT use `gemini-3.5-flash`, `gemini-3.5-flash`, or `gemini-3.1-flash-image` — pre-I/O, deprecated. - **Database:** Firestore (auto-provisioned). - **Auth:** Firebase Auth — Google sign-in primary (required for Workspace), Apple sign-in secondary. - **Storage:** Firebase Storage with pre-signed URLs; configurable retention. - **Workspace integration:** post-I/O 2026 no-OAuth Drive write; reuses Google identity from sign-in. Default folder "Voice Memos" (configurable). - **Audio handling:** Web MediaRecorder — `audio/webm` (Chrome/Firefox/Edge) or `audio/mp4` (Safari) → Firebase Storage → server-side re-upload to Gemini Developer API Files API → `fileData.fileUri: "files/abc123xyz"` passed to `generateContent`. Do NOT pass Firebase Storage public URLs to `generateContent`. Inline base64 acceptable for <20 MB; prefer Files API beyond ~1 min. - **Local save fallback (FSA non-Chromium):** the "save to disk" affordance uses `showSaveFilePicker()` on Chromium; on Safari / Firefox, fall back to an `` element pointed at a blob URL — FSA `showSaveFilePicker()` is not supported there. - **Mobile-first.** Verify at 375 / 768 / 1024 / 1440+. - `clamp()` for fluid type; container queries; `dvh`/`svh`; safe-area insets on iOS; zero horizontal overflow; zero CLS. - Firestore real-time listeners on the doc view (streamed doc emerges section by section). - Optimistic UI on title/settings; reconcile on response. - Wake Lock API for recording (Chrome/Edge); Safari iOS gets a clear "keep your screen on" hint up front. Background recording on iOS Safari is platform-constrained; the UI warns before long memos that backgrounding will pause capture. ## 12. Accessibility (WCAG 2.2 AA) - Semantic HTML (`header`, `nav`, `main`, `section`, `article`, `footer`). - All controls keyboard-reachable with visible focus ring. The record button is Tab-reachable, Space-activated (tap-to-start / tap-to-stop; no long-press required). - Contrast ≥ 4.5:1 body, 3:1 large text and UI. Sage-green Open-in-Docs chip and sienna recording state both verified AA against the warm paper background. - All images have meaningful `alt`; form fields have `