MobTranslate styleguide

Search and Refinement

Keep draft intent, request scope, actual returned results and accessible recovery distinct throughout a search task.

Define what is being searched

Name the corpus, fields, match policy and loaded/total distinction. This example searches the title and text of three public English fixtures plus page-memory local revisions; all whitespace-separated terms must match. It is lexical matching over declared fields, not a semantic translation or a language-wide dictionary search.

Use exact source-bearing lookup for attested language content. A no-match result must not trigger invented vocabulary or a silent switch to a larger/more permissive corpus. Interface search, content language and source authority are separate decisions.

Material search entry, focused results and web scope

The February 2025 reference unifies search bar/view as Search, recommending a contained style over divided baseline. Search can be a global app-bar function, a prominent local field or a secondary named icon. Keep its entry close to the content it searches, with a clear scope and up to two meaningful trailing actions; a decorative magnifier does not itself provide voice, location or remote search.

Native focused search may be docked with a scrim or compact full-screen, with an explicit Back action and predictive-back animation. This pattern instead supplies a named submitted web search task in document flow; the separate site search searches actual guide content. Neither claims a Material search-surface transition, native keyboard presentation or confidential search corpus.

Reference pointWeb choice and verification boundary
Native geometry and contrastReference unfocused width 360–720dp/height 56dp,30dp avatar and focus margins 24→12dp differ from the local field/form. Native docked focused content is 240dp to two-thirds screen height. Keep actual bounded web dimensions and contrasting surface roles; simply copying a surface-container label does not prove contrast.
Suggestions and resultsA search component supplies a container, not automatic data. Recent history, categories, suggestions and filter chips need real data ownership and effects. This lab searches declared loaded fields and revisions; it creates no invented vocabulary, query history, voice mode or attestations.
Typing versus submitted resultsThe source permits suggestions before typing, live results or explicit execution. This fixture snapshots on Search/Enter and labels draft versus requested/applied scope. Autocomplete has a different installed editing/selection model; do not mix arbitrary arrow handlers into this native form or move focus merely because a count changes.
Focus and clearPersistent visible labels identify the input. An actual clear/reset action must define whether it resets draft, applied filters or detail. The reference suggests removing input focus after submitted results; this lab deliberately returns focus to the surviving query field, announces actual scope and moves to detail only on Open. The choice is explicit rather than an accidental focus jump.
Loading and recoveryAnnounce genuine searching/received/empty/failure states without relabelling old results as a new query. Retain last success, reject stale responses, expose cancellation and retry, and keep scope/access constraints visible. A screen-reader announcement requires target-browser verification beyond a live-region attribute.
Placement and scrollingNative scroll text describes inconsistent up/down reveal behavior; this guide makes no automatic hide/reappear promise. Keep local results and controls accessible in document flow. A product implementing focused docked/full-screen search must prove Back/opener restoration, resizing, scrim modality, IME behavior and safe content bounds.

Anatomy and control specifications

PartActual composition
Search formNamed native form role=search, visible Input label, native submit Button. Enter submits the current draft without requiring a pointer.
RefinementThree labeled exported checkboxes: public/team audience and current local accepted decision. Draft changes wait for Search; Reset changes draft controls without erasing loaded results.
Request stateUnknown-total Progress only while fetching/apply-held. Requested query and last-applied query/role/count remain visible as separate scope.
ResultsNative list with stable-ID named Open controls and explicit audience/revision text; actual detail is independent from its presence in the filtered list.
Dimensions / directionWrapping controls with 44px minimum actions, native readable fields and logical RTL layout. English prose and user text use dir=auto.
RecoveryCancel returns to query focus; HTTP failure retains successful results and query. Correct the missing-URL control and Retry the actual fixture request.

Working search, revision and access workspace

This shared example fetches three publicly shipped English-only fixture records over HTTP, then applies a declared local UI policy. Every audience/role/review choice is a demonstration, not a credential, confidential dataset, dictionary attestation, qualified language approval or remote publication.

Search keeps draft controls, request snapshots, last successful results, opened detail, local revisions and review history separate. The source below is the exact compiled example.

All three HTTP fixture records are public, synthetic English-only examples. Audience labels and role choices demonstrate UI policy only. They are not real credentials, confidential content, publication consent or qualified language review.

No fixture search requested yet.

No search result applied.

    No local edit or review applied.

    Changing demo role cancels held proposals. Reader role removes team-audience results/details; the public fixture still remains public. Real access control must be enforced by the data service and authenticated identity, not a role picker or hidden DOM.

    tsx
    'use client';
    import {useEffect,useRef,useState,type CSSProperties} from 'react';
    import {Button,Checkbox,Input,Textarea,Progress,Badge} from '@mobtranslate/ui';
    type Role='reader'|'editor'|'reviewer';
    type Decision={revision:number;status:'accepted'|'changes';note:string};
    type RecordEntry={id:string;title:string;text:string;audience:'public'|'team';revision:number;sourceTitle:string;sourceHref:string;decisions:Decision[]};
    type RequestSnapshot={id:number;query:string;public:boolean;team:boolean;accepted:boolean;role:Role};
    type Candidate={request:RequestSnapshot;records:RecordEntry[]};
    type ReviewSnapshot={id:string;revision:number;note:string;status:'accepted'|'changes'};
    const action:CSSProperties={minHeight:44,height:'auto',minWidth:0,maxWidth:'100%',whiteSpace:'normal',overflowWrap:'anywhere'};
    function fixtureRecords(value:unknown):RecordEntry[]{
      if(!Array.isArray(value))throw Error('Fixture is not a record array.');
      const seen=new Set<string>();
      return value.map(row=>{
        if(!row||typeof row!=='object'||typeof row.id!=='string'||!row.id||seen.has(row.id)||typeof row.title!=='string'||typeof row.text!=='string'||(row.audience!=='public'&&row.audience!=='team')||!Number.isSafeInteger(row.revision)||row.revision<1||typeof row.sourceTitle!=='string'||typeof row.sourceHref!=='string'||!row.sourceHref.startsWith('/'))throw Error('Invalid fixture record shape or duplicate ID.');
        if(new URL(row.sourceHref,location.origin).origin!==location.origin)throw Error('Fixture source context must stay on this origin.');
        seen.add(row.id);return {...row,decisions:[]};
      });
    }
    export function GovernedWorkspaceExample(){
      const [interactive,setInteractive]=useState(false);
      const [role,setRole]=useState<Role>('reader');
      const [query,setQuery]=useState('');
      const [includePublic,setIncludePublic]=useState(true);
      const [includeTeam,setIncludeTeam]=useState(true);
      const [acceptedOnly,setAcceptedOnly]=useState(false);
      const [hold,setHold]=useState(false);
      const [fail,setFail]=useState(false);
      const [rtl,setRtl]=useState(false);
      const [phase,setPhase]=useState<'idle'|'fetching'|'held'|'ready'|'failed'|'cancelled'>('idle');
      const [records,setRecords]=useState<RecordEntry[]>([]);
      const [resultIds,setResultIds]=useState<string[]>([]);
      const [applied,setApplied]=useState<RequestSnapshot|null>(null);
      const [requested,setRequested]=useState<RequestSnapshot|null>(null);
      const [opened,setOpened]=useState<string|null>(null);
      const [editText,setEditText]=useState('');
      const [reviewNote,setReviewNote]=useState('');
      const [review,setReview]=useState<ReviewSnapshot|null>(null);
      const [message,setMessage]=useState('No fixture search requested yet.');
      const [task,setTask]=useState('No local edit or review applied.');
      const [reviewError,setReviewError]=useState('');
      const model=useRef<RecordEntry[]>([]);
      const drafts=useRef(new Map<string,{text:string;note:string}>());
      const roleInput=useRef<HTMLSelectElement>(null);
      const roleRef=useRef<Role>(role);
      const sequence=useRef(0);
      const controller=useRef<AbortController|null>(null);
      const candidate=useRef<Candidate|null>(null);
      const queryInput=useRef<HTMLInputElement>(null);
      const noteInput=useRef<HTMLTextAreaElement>(null);
      const arrival=useRef<HTMLHeadingElement>(null);
      const reviewArrival=useRef<HTMLParagraphElement>(null);
      const current=records.find(record=>record.id===opened);
      const currentDecision=current?.decisions.filter(decision=>decision.revision===current.revision).at(-1);
      const pending=phase==='fetching'||phase==='held';
      useEffect(()=>{setQuery(new URLSearchParams(location.search).get('record-q')??'');setInteractive(true);return()=>{sequence.current++;controller.current?.abort();};},[]);
      useEffect(()=>{if(opened)arrival.current?.focus();},[opened]);
      function store(next:RecordEntry[]){model.current=next;setRecords(next);}
      function cancel(messageText='Search cancelled. Last successful results and query remain.'){
        sequence.current++;controller.current?.abort();controller.current=null;candidate.current=null;setPhase('cancelled');setMessage(messageText);queryInput.current?.focus();
      }
      function apply(next:Candidate){
        if(next.request.id!==sequence.current||next.request.role!==roleRef.current)return;
        const merged=next.records.map(seed=>model.current.find(record=>record.id===seed.id)??seed);
        store(merged);
        const terms=next.request.query.toLocaleLowerCase('en').trim().split(/\s+/).filter(Boolean);
        const matches=merged.filter(record=>{
          const latest=record.decisions.filter(event=>event.revision===record.revision).at(-1);
          const allowed=record.audience==='public'?next.request.public:next.request.team&&next.request.role!=='reader';
          return allowed&&(!next.request.accepted||latest?.status==='accepted')&&terms.every(term=>`${record.title} ${record.text}`.toLocaleLowerCase('en').includes(term));
        });
        setResultIds(matches.map(record=>record.id));setApplied(next.request);setPhase('ready');setMessage(`Loaded ${matches.length} matching records from three public fixture records plus local revisions. Query: ${next.request.query||'(all)'}.`);candidate.current=null;queryInput.current?.focus();
      }
      async function search(){
        if(!interactive)return;
        controller.current?.abort();candidate.current=null;
        const request={id:++sequence.current,query,public:includePublic,team:includeTeam,accepted:acceptedOnly,role:roleRef.current};
        const abort=new AbortController();controller.current=abort;setRequested(request);setPhase('fetching');setMessage(`Fetching public fixture for query ${query||'(all)'}. Last successful results remain.`);
        const url=new URL(location.href);if(query)url.searchParams.set('record-q',query);else url.searchParams.delete('record-q');history.replaceState(null,'',url);
        try{
          const response=await fetch(fail?'/fixtures/governed-records-missing.json':'/fixtures/governed-records.json',{signal:abort.signal,cache:'no-store'});
          if(!response.ok)throw Error(`Fixture returned HTTP ${response.status}.`);
          const next={request,records:fixtureRecords(await response.json())};
          if(abort.signal.aborted||request.id!==sequence.current||request.role!==roleRef.current)return;
          if(hold){candidate.current=next;setPhase('held');setMessage('HTTP response received. Applying this candidate is held; last successful results remain.');}
          else apply(next);
        }catch(error){if(abort.signal.aborted||request.id!==sequence.current)return;setPhase('failed');setMessage(`${error instanceof Error?error.message:'Fixture request failed.'} Last successful results and draft query remain. Correct the failure setting and retry.`);queryInput.current?.focus();}
      }
      function changeRole(next:Role){
        if(next!=='reader'&&next!=='editor'&&next!=='reviewer'){setMessage('Unsupported demo role; current policy remains.');roleInput.current?.focus();return;}
        sequence.current++;controller.current?.abort();candidate.current=null;roleRef.current=next;setRole(next);setReview(null);setPhase(applied?'ready':'idle');
        if(next==='reader'){model.current.filter(record=>record.audience==='team').forEach(record=>drafts.current.delete(record.id));setResultIds(ids=>ids.filter(id=>model.current.find(record=>record.id===id)?.audience==='public'));if(current?.audience==='team'){setOpened(null);setEditText('');setReviewNote('');}}
        setMessage('Demo role changed; outstanding search/review proposals cancelled and displayed results reconciled. The fixture is public; this picker is not authentication.');setTask('Demo role changed; held local review cancelled. Existing content and history remain.');setReviewError('');roleInput.current?.focus();
      }
      function openRecord(record:RecordEntry){
        if(record.audience==='team'&&roleRef.current==='reader'){setTask('Team-audience view unavailable under Reader demo.');roleInput.current?.focus();return;}
        if(record.id===opened){arrival.current?.focus();return;}
        if(current)drafts.current.set(current.id,{text:editText,note:reviewNote});
        const draft=drafts.current.get(record.id);setOpened(record.id);setEditText(draft?.text??record.text);setReviewNote(draft?.note??'');setReviewError('');setReview(null);setTask('Opened local record; any prior held review proposal was cancelled. Per-record drafts remain in page memory.');
      }
      function edit(){
        if(!current||roleRef.current==='reader')return;
        if(!editText.trim()){setTask('Enter nonempty English-only local content before creating a revision.');return;}
        const next={...current,text:editText,revision:current.revision+1};store(model.current.map(record=>record.id===next.id?next:record));setTask(`Created local revision ${next.revision}; previous review history remains, current revision needs a new review.`);
      }
      function propose(status:ReviewSnapshot['status']){
        if(!current||roleRef.current!=='reviewer'||review)return;
        if(!reviewNote.trim()){setReviewError('Enter a review note for this local decision.');noteInput.current?.focus();return;}
        setReviewError('');setReview({id:current.id,revision:current.revision,note:reviewNote.trim(),status});setTask(`Local ${status} decision held for revision ${current.revision}. This is not qualified language review.`);
      }
      function resolveReview(complete:boolean){
        if(!review)return;
        const latest=model.current.find(record=>record.id===review.id);
        if(!complete)setTask('Local review cancelled; record and history remain.');
        else if(roleRef.current!=='reviewer'||!latest||latest.revision!==review.revision)setTask('Review snapshot is out of date or unavailable. No decision applied; current revision remains.');
        else{store(model.current.map(record=>record.id===latest.id?{...record,decisions:[...record.decisions,{revision:review.revision,status:review.status,note:review.note}]}:record));setTask(`Applied local ${review.status} decision to revision ${review.revision}. No qualified language approval or publication is claimed.`);}
        setReview(null);reviewArrival.current?.focus();
      }
      return <div data-governed-lab style={{overflowWrap:'anywhere'}} lang="en" dir={rtl?'rtl':'ltr'} className="space-y-4">
        <p dir="auto">All three HTTP fixture records are public, synthetic English-only examples. Audience labels and role choices demonstrate UI policy only. They are not real credentials, confidential content, publication consent or qualified language review.</p>
        <label htmlFor="governed-role" className="block">Simulated workspace role</label><select ref={roleInput} id="governed-role" className="mt-input" value={role} onChange={event=>changeRole(event.target.value as Role)}><option value="reader">Reader demo</option><option value="editor">Editor demo</option><option value="reviewer">Reviewer demo</option></select>
        <form role="search" aria-label="Public fixture records" onSubmit={event=>{event.preventDefault();void search();}} className="space-y-3">
          <label htmlFor="governed-query" className="block">Search loaded English title and content fields</label><Input ref={queryInput} id="governed-query" dir="auto" value={query} readOnly={!interactive} onChange={event=>setQuery(event.target.value)} />
          <div className="flex flex-wrap gap-3"><Checkbox label="Include public-audience examples" checked={includePublic} onCheckedChange={setIncludePublic} /><Checkbox label="Include team-audience examples" checked={includeTeam} onCheckedChange={setIncludeTeam} /><Checkbox label="Current local accepted decision only" checked={acceptedOnly} onCheckedChange={setAcceptedOnly} /></div>
          <div className="flex flex-wrap gap-3"><Button style={action} type="submit" disabled={!interactive}>Search fixture records</Button><Button style={action} type="button" variant="outline" onClick={()=>{setQuery('');setIncludePublic(true);setIncludeTeam(true);setAcceptedOnly(false);}}>Reset draft filters</Button></div>
        </form>
        <div className="flex flex-wrap gap-3"><Button style={action} type="button" variant="outline" aria-pressed={hold} onClick={()=>setHold(value=>!value)}>Hold received search responses</Button><Button style={action} type="button" variant="outline" aria-pressed={fail} onClick={()=>setFail(value=>!value)}>Use missing fixture URL</Button><Button style={action} type="button" variant="outline" aria-pressed={rtl} onClick={()=>setRtl(value=>!value)}>Use RTL governed workspace</Button></div>
        {pending&&<div className="flex flex-wrap gap-3"><Progress value={null} aria-label="Fixture search progress" />{phase==='held'&&<Button style={action} type="button" onClick={()=>{if(candidate.current)apply(candidate.current);}}>Apply held search response</Button>}<Button style={action} type="button" variant="outline" onClick={()=>cancel()}>Cancel fixture search</Button></div>}
        {phase==='failed'&&<Button style={action} type="button" onClick={()=>void search()}>Retry fixture search</Button>}
        <p role="status" dir="auto" data-governed-search-status>{message}</p>
        <p dir="auto" data-governed-applied>{applied?`Last applied query: ${applied.query||'(all)'}. Applied role snapshot: ${applied.role}. Current displayed result count: ${resultIds.length}.`:'No search result applied.'}{pending||phase==='failed'?' Last successful result is retained while its replacement is unresolved.':''}</p>
        {requested&&<p dir="auto">Requested query: {requested.query||'(all)'}. Draft controls can change separately; a new search supersedes the old request.</p>}
        <ul data-governed-results className="space-y-3">{resultIds.map(id=>{const record=records.find(row=>row.id===id);return record?<li key={id}><Button style={action} type="button" variant="outline" onClick={()=>openRecord(record)}>Open {record.title}</Button><p dir="auto">{record.audience} audience demo; local revision {record.revision}.</p></li>:null;})}</ul>
        {applied&&!resultIds.length&&<p dir="auto">No accessible fixture records match this applied scope. Reset draft filters, then search again. This does not mean a language has no entries.</p>}
        {current&&<section aria-labelledby="governed-detail-title" className="space-y-3">
          <h3 ref={arrival} id="governed-detail-title" tabIndex={-1} dir="auto" className="font-semibold">{current.title}</h3><p dir="auto" data-governed-detail>{current.text}</p>
          <p dir="auto">Source context: <a href={current.sourceHref} className="underline">{current.sourceTitle}</a>. This is a real guide link for the authored example, not a dictionary attestation.</p>
          <p dir="auto" data-governed-review-state><Badge variant="outline">Local revision {current.revision}</Badge> Current local decision: {currentDecision?.status??'not reviewed'}. Language authority: not established.</p>
          <p id="governed-capability-help" dir="auto">{role==='reader'?'Reader demo can inspect public examples. Editing and local review are unavailable.':role==='editor'?'Editor demo can create local revisions. Review proposals require Reviewer demo.':'Reviewer demo can create revisions and propose local workflow decisions; these do not confer language authority.'}{review?' A review proposal is held; finish or cancel it before changing its note or proposing another decision.':''}</p>
          <label htmlFor="governed-edit" className="block">Local English-only revision draft</label><Textarea id="governed-edit" aria-describedby="governed-capability-help" dir="auto" value={editText} readOnly={role==='reader'} onChange={event=>{setEditText(event.target.value);drafts.current.set(current.id,{text:event.target.value,note:reviewNote});}} /><Button style={action} type="button" disabled={role==='reader'} onClick={edit}>Create newer local revision</Button>
          <label htmlFor="governed-review-note" className="block">Local workflow review note</label><Textarea ref={noteInput} id="governed-review-note" dir="auto" value={reviewNote} readOnly={role!=='reviewer'||!!review} aria-invalid={!!reviewError} aria-describedby={'governed-capability-help'+(reviewError?' governed-review-error':'')} onChange={event=>{setReviewNote(event.target.value);drafts.current.set(current.id,{text:editText,note:event.target.value});}} />{reviewError&&<p id="governed-review-error" dir="auto" role="alert">{reviewError}</p>}
          <div className="flex flex-wrap gap-3"><Button style={action} type="button" disabled={role!=='reviewer'||!!review} onClick={()=>propose('accepted')}>Propose local acceptance</Button><Button style={action} type="button" variant="outline" disabled={role!=='reviewer'||!!review} onClick={()=>propose('changes')}>Request local changes</Button></div>
          {review&&<div className="flex flex-wrap gap-3"><Button style={action} type="button" onClick={()=>resolveReview(true)}>Complete held local review</Button><Button style={action} type="button" variant="outline" onClick={()=>resolveReview(false)}>Cancel held local review</Button></div>}
          <ol data-governed-review-history className="guidance-list">{current.decisions.map((decision,index)=><li dir="auto" key={index}>Revision {decision.revision}: {decision.status}; {decision.note}. {decision.revision!==current.revision?'Historical decision; not current approval.':''}</li>)}</ol>
        </section>}
        <p ref={reviewArrival} tabIndex={-1} role="status" dir="auto" data-governed-task-status>{task}</p>
        <p dir="auto">Changing demo role cancels held proposals. Reader role removes team-audience results/details; the public fixture still remains public. Real access control must be enforced by the data service and authenticated identity, not a role picker or hidden DOM.</p>
      </div>;
    }
    

    Draft, submitted query and response lifetime

    • Typing or changing a checkbox does not relabel an old result. Search snapshots the query, audience filters, review filter and current demo role. The URL record-q stores the last requested query, not a claim of saved filters or authentication.
    • A new search aborts the preceding fetch and increments request identity. Even a late response that ignores abort must not replace a newer request or a role change. Cleanup aborts on unmount.
    • The Hold control holds application after the real HTTP response arrives. Its status says response received; it does not pretend that transport is still pending. Applying uses the captured query and current local record overlays.
    • Successful application returns focus to the persistent query field; routine result arrivals do not force focus into every row. An explicit Open action focuses the actual detail heading.

    State matrix and honest recovery

    StateRequired behavior
    Idle / draftState the searchable scope; no fake result count before a request.
    FetchingName requested scope and unknown progress; retain and label the last successful result.
    Received / heldDistinguish transport completion from result application; Apply/Cancel have real effects.
    Ready / emptyCount actual visible IDs. Empty under filters/access does not mean the full language corpus is empty.
    FailureDisplay actual HTTP failure and retained result/query; retry only after correcting the request conditions.
    Cancelled / supersededReject the abandoned candidate; preserve prior useful results and independent opened detail.

    Refinement and access relationships

    • User-selected audience filters cannot grant access. The current role’s UI policy further restricts matching records; explain both limits rather than claiming no records exist.
    • A current-review filter matches the latest decision for the current revision. A historical acceptance or populated badge must not silently pass that filter.
    • After role change, cancel outstanding requests and reconcile displayed IDs/details immediately. Do not apply a candidate captured under an older, more privileged role.
    • Keep Reset filters separate from clearing loaded detail, deleting selections and clearing an audit history. The fixture explicitly retains opened content through ordinary query refinements.

    Implementation and API ownership

    OwnerActual contract
    Input / Button / Checkbox / ProgressExported primitives and native form events; no undocumented Search package export or implicit suggestion engine.
    Fixture loaderSame-origin fetch, response.ok and validated owned JSON shape/unique IDs. Source context URLs stay on the current origin.
    Request coordinatorAbortController plus monotonically increasing identity/current-role check; candidate and applied-result owners are separate.
    Local modelRecord overlays preserve local revisions through fixture reload. This is not a backend merge or remote version protocol.
    URLNative history.replaceState for record-q only. Roles, authorization and qualified review never come from URL text.

    Exact public fixture and evidence boundary

    The fixture is a real same-origin HTTP resource. Its source links open actual guidance pages as authored context; they are not dictionary evidence spans. It contains no confidential or Indigenous vocabulary. UI role filtering does not make its bytes private.

    json
    [
      {"id":"reading","title":"Local reading example","text":"English-only reading notes for the styleguide task.","audience":"public","revision":1,"sourceTitle":"Accessibility guidance","sourceHref":"/guides/accessibility"},
      {"id":"comparison","title":"Local comparison example","text":"English-only comparison notes for the styleguide task.","audience":"public","revision":1,"sourceTitle":"Data display guidance","sourceHref":"/patterns/data-display"},
      {"id":"team","title":"Local team example","text":"Publicly shipped English-only fixture representing a team audience in the UI demo. This is not confidential content.","audience":"team","revision":1,"sourceTitle":"Composition guidance","sourceHref":"/guides/composition"}
    ]
    

    Failure cases and adaptation

    • Avoid changing a count to the new query before its result exists, treating cancellation as a failure, or destroying successful results when a replacement request fails.
    • Keep error/retry/filter controls reachable at narrow widths. Do not put the only clear action inside a transient suggestion popup.
    • Do not infer source correctness from result ranking, locale, a model score or a positive color. Declare lexical/semantic matching honestly and keep exact attestation separate.
    • Large/remote datasets need paging/cursor/freshness policies and measured latency; this fixture proves only its three-record loaded scope.

    Acceptance and verification scope

    • Run test:governed-patterns, checked-source/token freshness, lint/types/build and the complete route/fragment crawl. Verify actual loaded records, submitted versus draft filters, HTTP failure/retry, held replacement/cancel/supersession, revision-bound decisions, permission availability and real focus targets.
    • Inspect all three guides in both themes at 320px, with RTL geometry, readable source/status text and at least 44px action targets.
    • Real authenticated access, external dictionary source retrieval, qualified human review, durable writes, hardware and spoken assistive-technology behavior require their own evidence. This public fixture establishes none of those outcomes.