{
  "version": "0.2.0-preview.1",
  "content_digest": "70ac710f4d22dce040e7ac593379ba8aca9dcb59a0b9c0f839819cae0e2bb721",
  "status": "preview",
  "authority": {
    "repository": "cloakedinc/design",
    "path": "packages/design-system",
    "catalog": "packages/design-system/catalog.json",
    "status": "preview"
  },
  "provenance": {
    "repo": "cloakedinc/automation",
    "commit": "f96f416e1c3bfbfaffcd155a88b87b18b8bb25f1",
    "path": "packages/design-system",
    "imported_spec_status": "approved"
  },
  "adaptations": [
    {
      "id": "button-content-gap",
      "status": "preview",
      "description": "Use the specification's 4px content gap instead of the inherited 8px implementation gap."
    },
    {
      "id": "keyboard-focus",
      "status": "preview",
      "description": "Add visible Button and Input keyboard focus and an overridable inset focus default for shared button resets, including FAQ cards and ListItem rows."
    },
    {
      "id": "supporting-text-contrast",
      "status": "preview",
      "description": "Map light secondary text to the existing grey-04-strong primitive for readable helper text on white and cream."
    },
    {
      "id": "danger-text-contrast",
      "status": "preview",
      "description": "Separate readable danger text/borders from destructive fills; preserve the primary danger-button fill and label pair."
    },
    {
      "id": "preview-status",
      "status": "preview",
      "description": "Local components, specs and token adaptations await human sign-off; upstream approved status is provenance only."
    },
    {
      "id": "motion-comparison-accessibility",
      "status": "preview",
      "description": "Preserve the original MotionShowcase comparisons while requiring explicit replay, responding to live reduced-motion changes, and keeping duration tracks usable on small screens."
    },
    {
      "id": "list-item-ownership",
      "status": "preview",
      "description": "List owns listitem wrappers for its content rows, while section labels stay outside the row count and standalone rows retain their existing semantics."
    },
    {
      "id": "card-delta-text-contrast",
      "status": "preview",
      "description": "Mix Card.Delta foregrounds from 60% existing tone solid and 40% primary text for readable contrast in both themes; preserve the four original tone fills."
    },
    {
      "id": "carousel-keyboard-access",
      "status": "preview",
      "description": "Keep all native-scrolling carousel slide controls exposed to assistive technology and keyboard navigation; pause autoplay while focus is inside the carousel."
    }
  ],
  "id": "protected-email",
  "name": "Create a protected email",
  "summary": "A local simulation of choosing a recognizable label, validating input, creating an address, and confirming the result.",
  "components": [
    "field",
    "input",
    "button"
  ],
  "synthetic_data": true,
  "states": [
    "default",
    "invalid",
    "loading",
    "success"
  ],
  "constraints": [
    "No address is created or sent.",
    "Keep labels and validation messages associated with the input.",
    "Announce pending and successful results."
  ],
  "examples": [
    {
      "id": "protected-email-flow",
      "title": "Create a protected email",
      "source": "packages/design-system/examples/ProtectedEmailFlow.tsx",
      "export": "ProtectedEmailFlow",
      "components": [
        "button",
        "field",
        "input"
      ],
      "description": "A local-only sample flow with validation, loading, success and restart. No data is sent or saved.",
      "synthetic_data": true,
      "storybook_id": "patterns-protected-email--create",
      "code": "import { useEffect, useLayoutEffect, useRef, useState, type FormEvent } from 'react';\nimport { Button, Field, Input } from '../src';\nimport { DemoFrame } from './DemoFrame';\nimport { createSampleIdentity, validateIdentity, type IdentityDraft, type IdentityErrors } from './protected-email';\n\nconst EMPTY_DRAFT: IdentityDraft = { name: '', website: '' };\n\nexport function ProtectedEmailFlow() {\n  const [draft, setDraft] = useState<IdentityDraft>(EMPTY_DRAFT);\n  const [errors, setErrors] = useState<IdentityErrors>({});\n  const [stage, setStage] = useState<'editing' | 'loading' | 'success'>('editing');\n  const form = useRef<HTMLFormElement>(null);\n  const success = useRef<HTMLHeadingElement>(null);\n  useEffect(() => {\n    if (stage !== 'loading') return;\n    const timer = window.setTimeout(() => setStage('success'), 700);\n    return () => window.clearTimeout(timer);\n  }, [stage]);\n  useEffect(() => { if (stage === 'success') success.current?.focus(); }, [stage]);\n  useLayoutEffect(() => {\n    if (Object.keys(errors).length) form.current?.querySelector<HTMLInputElement>('[aria-invalid=\"true\"]')?.focus();\n  }, [errors]);\n  const restart = () => {\n    setDraft(EMPTY_DRAFT); setErrors({}); setStage('editing');\n    requestAnimationFrame(() => form.current?.querySelector<HTMLInputElement>('input')?.focus());\n  };\n  const submit = (event: FormEvent) => {\n    event.preventDefault();\n    if (stage !== 'editing') return;\n    const nextErrors = validateIdentity(draft);\n    setErrors(nextErrors);\n    if (Object.keys(nextErrors).length) return;\n    setStage('loading');\n  };\n  return <DemoFrame><section className=\"demo-flow\" aria-label=\"Create a protected email example\">\n    <p className=\"demo-sample-note\">Interactive example · Sample data only. Nothing is sent or saved.</p>\n    {stage === 'success' ? <FlowSuccess draft={draft} headingRef={success} restart={restart} /> :\n      <form ref={form} noValidate onSubmit={submit} aria-busy={stage === 'loading'}>\n        <FlowHeading />\n        <FlowFields draft={draft} errors={errors} loading={stage === 'loading'} change={setDraft} submit={() => form.current?.requestSubmit()} />\n        <Button variant=\"primary\" size=\"md\" fullWidth loading={stage === 'loading'} onPress={() => form.current?.requestSubmit()}>Create protected email</Button>\n        <p className=\"demo-feedback\" role=\"status\">{stage === 'loading' ? 'Creating your sample address…' : 'Your personal email stays yours.'}</p>\n      </form>}\n  </section></DemoFrame>;\n}\n\nfunction FlowHeading() {\n  return <div className=\"demo-flow-heading\">\n    <span className=\"demo-symbol\" aria-hidden=\"true\">@</span>\n    <span className=\"demo-eyebrow\">A little more privacy</span>\n    <h2>An email for this part of your life.</h2>\n    <p>Give it a name so you know where you used it.</p>\n  </div>;\n}\n\nfunction FlowFields({ draft, errors, loading, change, submit }: {\n  draft: IdentityDraft; errors: IdentityErrors; loading: boolean;\n  change: (draft: IdentityDraft) => void; submit: () => void;\n}) {\n  return <div className=\"demo-flow-fields\">\n    <Field label=\"Name\" helperText=\"For example, shopping or a newsletter.\" error={errors.name} required disabled={loading}>\n      <Input value={draft.name} onChange={name => change({ ...draft, name })} placeholder=\"Shopping\"\n        name=\"identity-name\" autoComplete=\"off\" maxLength={80} enterKeyHint=\"next\" />\n    </Field>\n    <Field label=\"Website (optional)\" helperText=\"A reminder of where you'll use this address.\" error={errors.website} disabled={loading}>\n      <Input value={draft.website} onChange={website => change({ ...draft, website })} placeholder=\"example.com\"\n        name=\"identity-website\" autoComplete=\"off\" inputMode=\"url\" autoCapitalize=\"none\" maxLength={200}\n        enterKeyHint=\"done\" enterBehavior=\"callback\" onEnter={submit} />\n    </Field>\n  </div>;\n}\n\nfunction FlowSuccess({ draft, headingRef, restart }: {\n  draft: IdentityDraft; headingRef: React.RefObject<HTMLHeadingElement>; restart: () => void;\n}) {\n  const identity = createSampleIdentity(draft);\n  return <div className=\"demo-flow-success\">\n    <span className=\"demo-symbol demo-symbol-success\" aria-hidden=\"true\">✓</span>\n    <span className=\"demo-eyebrow\">Ready to use</span>\n    <h2 ref={headingRef} tabIndex={-1}>A fresh address for {identity.name}.</h2>\n    <p>This sample address demonstrates the result. It cannot receive email.</p>\n    <div className=\"demo-email-result\"><span>Protected email</span><strong>{identity.email}</strong></div>\n    <Button variant=\"secondary\" size=\"md\" fullWidth onPress={restart}>Try the flow again</Button>\n  </div>;\n}\n"
    }
  ],
  "links": {
    "human": "/pattern-protected-email",
    "json": "/data/patterns/protected-email.json"
  }
}
