{
  "LoginPage": {
    "titleAccept": "Sign in to accept",
    "titleWelcome": "Welcome back",
    "descAccept": "Sign in and we'll take you to the invitation.",
    "descWelcome": "Sign in to your account",
    "emailLabel": "Email",
    "emailPlaceholder": "you@example.com",
    "passwordLabel": "Password",
    "forgotPassword": "Forgot password?",
    "passwordPlaceholder": "Enter your password",
    "signingIn": "Signing in...",
    "signIn": "Sign in",
    "noAccount": "Don't have an account?",
    "createAccount": "Create account",
    "linkExpired": "That link has expired. For a password reset, use “Forgot password?” to request a new one; if you were confirming your email, sign up again.",
    "linkInvalid": "That link couldn’t be used to sign you in. If you were confirming your email, it may already be verified — just sign in below. For a password reset, request a new link and open it in the same browser you requested it from."
  },
  "Sidebar": {
    "title": "CRM Template for WhatsApp",
    "primaryNav": "Primary",
    "dashboard": "Dashboard",
    "inbox": "Inbox",
    "notifications": "Notifications",
    "contacts": "Contacts",
    "pipelines": "Pipelines",
    "broadcasts": "Broadcasts",
    "automations": "Automations",
    "flows": "Flows",
    "aiAgents": "AI Agents",
    "settings": "Settings",
    "beta": "Beta",
    "unreadConversations": "{count} unread {count, plural, =1 {conversation} other {conversations}}",
    "unreadNotifications": "{count} unread {count, plural, =1 {notification} other {notifications}}",
    "roleOwner": "Owner",
    "roleAdmin": "Admin",
    "roleAgent": "Agent",
    "roleViewer": "Viewer",
    "closeMenu": "Close menu",
    "defaultUser": "User",
    "defaultAvatar": "Avatar",
    "menuProfile": "Profile",
    "menuSettings": "Settings",
    "menuSignOut": "Sign out"
  },
  "Header": {
    "dashboard": "Dashboard",
    "inbox": "Inbox",
    "notifications": "Notifications",
    "contacts": "Contacts",
    "pipelines": "Pipelines",
    "broadcasts": "Broadcasts",
    "automations": "Automations",
    "settings": "Settings",
    "openMenu": "Open menu",
    "openAccountMenu": "Open account menu",
    "defaultUser": "User",
    "defaultAvatar": "Avatar",
    "menuProfile": "Profile",
    "menuSettings": "Settings",
    "menuSignOut": "Sign out"
  },
  "ModeToggle": {
    "switchMode": "Switch to {mode} mode"
  },
  "AccountAccess": {
    "unlinkedTitle": "This user is not linked to an account",
    "unlinkedBody": "Nothing you change will be saved while this is unresolved — the database rejects every write from a user with no account or role. If you were invited to a team, ask the owner to re-send the invitation. On a self-hosted install, check that the account-bootstrap migration ran for this user.",
    "errorTitle": "Could not load your permissions",
    "errorBody": "Your account role did not load, so every action is treated as read-only and changes will not save. Check your connection and try again.",
    "retry": "Retry"
  },
  "Dashboard": {
    "page": {
      "title": "Dashboard",
      "description": "Live analytics across conversations, contacts, deals, broadcasts, and automations.",
      "activeConversations": "Active Conversations",
      "newContactsToday": "New Contacts Today",
      "openDealsValue": "Open Deals Value",
      "messagesSentToday": "Messages Sent Today",
      "newTodayVsYesterday": "new today vs yesterday",
      "vsYesterday": "vs yesterday",
      "openDeals": "{count} open {count, plural, =1 {deal} other {deals}}",
      "noChange": "No change {suffix}"
    },
    "quickActions": {
      "newContact": "New Contact",
      "newDeal": "New Deal",
      "newBroadcast": "New Broadcast",
      "newAutomation": "New Automation"
    },
    "activityFeed": {
      "title": "Recent Activity",
      "viewAll": "View all →",
      "noActivity": "No activity yet",
      "noActivityHint": "Activity from messages, deals, broadcasts, and automations will appear here.",
      "showingOf": "Showing {visible} of {totalLoaded}{plus}",
      "show": "Show",
      "timeS": "{sec}s ago",
      "timeM": "{min}m ago",
      "timeH": "{hr}h ago",
      "timeD": "{day}d ago",
      "items": {
        "newMessage": "New message from {who}",
        "newContact": "New contact: {name}",
        "dealInStage": "Deal \"{title}\" in {stage}",
        "dealUpdated": "Deal \"{title}\" updated",
        "broadcastSent": "Broadcast \"{name}\" sent to {count} contacts",
        "broadcastStatus": "Broadcast \"{name}\" {status} ({count} recipients)",
        "broadcastStatusNames": {
          "draft": "draft",
          "scheduled": "scheduled",
          "sending": "sending",
          "sent": "sent",
          "failed": "failed"
        },
        "automationFailed": "Automation \"{name}\" failed for {who}",
        "automationTriggered": "Automation \"{name}\" triggered for {who}",
        "unknown": "Unknown",
        "aContact": "a contact",
        "automationFallback": "Automation"
      }
    },
    "conversationsChart": {
      "title": "Conversations Over Time",
      "description": "Daily message volume by direction",
      "days": "{count} days",
      "noActivity": "No message activity in this range",
      "noActivityHint": "Send or receive messages to start populating this chart.",
      "incoming": "Incoming",
      "outgoing": "Outgoing",
      "tooltipIncoming": "{count} incoming",
      "tooltipOutgoing": "{count} outgoing",
      "ariaLabel": "Conversations per day"
    },
    "pipelineDonut": {
      "title": "Pipeline Value",
      "description": "Open deals by stage",
      "noOpenDeals": "No open deals yet",
      "noOpenDealsHint": "Create deals in Pipelines to see stage breakdowns here.",
      "dealCount": "{count} {count, plural, =1 {deal} other {deals}}",
      "total": "Total",
      "ariaLabel": "Pipeline value by stage"
    },
    "responseTimeChart": {
      "title": "Average First Response Time",
      "description": "Minutes to reply to a customer's first unreplied message, by weekday",
      "target": "target {minutes}m",
      "thisWeek": "This week:",
      "lastWeek": "Last week:",
      "noReplies": "No replies recorded yet",
      "noRepliesHint": "This chart fills in as you reply to customer messages.",
      "avgMinutes": "Avg minutes"
    },
    "emptyState": {
      "title": "Not enough data yet"
    }
  },
  "Inbox": {
    "page": {
      "whatsappNotConnected": "WhatsApp® is not connected. Go to Settings to connect your account."
    },
    "conversationList": {
      "searchPlaceholder": "Search conversations...",
      "filterAll": "All",
      "filterUnread": "Unread",
      "filterOpen": "Open",
      "filterPending": "Pending",
      "filterClosed": "Closed",
      "tags": "Tags",
      "company": "Company",
      "allCompanies": "All companies",
      "clearAll": "Clear all",
      "noConversations": "No conversations found",
      "noMessagesYet": "No messages yet",
      "unknown": "Unknown"
    },
    "messageThread": {
      "backToConversations": "Back to conversations",
      "hideContactPanel": "Hide contact panel",
      "showContactPanel": "Show contact panel",
      "hideContact": "Hide contact",
      "showContact": "Show contact",
      "refresh": "Refresh",
      "refreshConversation": "Refresh conversation",
      "status": "Status",
      "statusOpen": "Open",
      "statusPending": "Pending",
      "statusClosed": "Closed",
      "assign": "Assign",
      "assigned": "Assigned",
      "unassign": "Unassign",
      "noTeammates": "No teammates available",
      "me": " (me)",
      "noMessagesYet": "No messages yet",
      "sendTemplateHint": "Send a template to start the conversation",
      "selectConversation": "Select a conversation",
      "selectConversationHint": "Choose a conversation from the left to start messaging",
      "today": "Today",
      "yesterday": "Yesterday",
      "customer": "Customer",
      "unknown": "Unknown",
      "sendFailed": "Failed to send: {reason}",
      "sendTemplateFailed": "Failed to send template: {reason}",
      "waitForSending": "Wait for the message to finish sending",
      "reactionFailed": "Reaction failed: {reason}",
      "assignmentUpdateFailed": "Failed to update assignment",
      "networkError": "network error",
      "documentFallback": "Document",
      "you": "You"
    },
    "sessionTimer": {
      "expired": "Expired",
      "xhRemaining": "{hours}h remaining",
      "xmRemaining": "{minutes}m remaining",
      "noCustomerMessages": "No customer messages"
    },
    "composer": {
      "draftHint": "Tap the ✨ to draft a reply with AI — you can edit it before sending",
      "sessionExpiredHint": "24-hour session expired. Use a template to re-engage.",
      "templates": "Templates",
      "readOnlyPlaceholder": "Read-only — viewers can browse but not reply",
      "sessionExpiredPlaceholder": "Session expired - use a template",
      "typeMessagePlaceholder": "Type a message... (Shift+Enter for new line)",
      "readOnlyTitle": "Read-only — your role can't send messages",
      "recording": "Recording… {current} / {max}",
      "cancel": "Cancel",
      "stopAndAttach": "Stop and attach",
      "attachMedia": "Attach media",
      "photo": "Photo",
      "video": "Video",
      "document": "Document",
      "voiceNote": "Voice note",
      "sendTemplate": "Send template",
      "aiNotConfigured": "AI isn't set up yet — enable it in Settings → AI Assistant.",
      "draftFailed": "Couldn't draft a reply.",
      "draftEmpty": "The assistant didn't return a reply.",
      "aiUnreachable": "Couldn't reach the AI assistant.",
      "recordingTooLong": "Recording is too long (over 16 MB).",
      "recordingUnsupported": "Voice recording isn't supported in this browser.",
      "microphoneDenied": "Microphone access denied or unavailable.",
      "draftWithAI": "Draft a reply with AI",
      "addCaption": "Add a caption…",
      "removeAttachment": "Remove attachment",
      "moreActions": "More",
      "interactiveMessage": "Interactive message",
      "quickReplies": "Quick replies",
      "quickRepliesEmpty": "No quick replies yet. Add some in Settings → Quick replies.",
      "saveAsQuickReply": "Save as quick reply",
      "send": "Send",
      "quickReplyNamePrompt": "Name this quick reply:",
      "quickReplySaved": "Saved as a quick reply.",
      "quickReplySaveError": "Couldn't save the quick reply.",
      "fileTooLarge": "File is {size} MB — {kind} limit is {max} MB.",
      "mediaKind": {
        "image": "image",
        "video": "video",
        "document": "document",
        "audio": "audio"
      },
      "uploadFailed": "Upload failed."
    },
    "bubble": {
      "photo": "Photo",
      "video": "Video",
      "audio": "Audio",
      "unavailable": "{label} unavailable",
      "document": "Document",
      "locationShared": "Location shared",
      "template": "Template",
      "buttonReply": "Button reply",
      "interactiveReply": "[Interactive reply]",
      "unsupported": "[Unsupported message type]",
      "aiBadge": "AI",
      "aiBadgeTitle": "Sent automatically by the AI assistant",
      "notDelivered": "Not delivered",
      "download": "Download",
      "downloadFailed": "Couldn't download the attachment",
      "viewImage": "View image",
      "expandVideo": "Expand video",
      "imageAlt": "Shared image"
    },
    "mediaViewer": {
      "counter": "{index} of {total}",
      "previous": "Previous",
      "next": "Next",
      "zoomIn": "Zoom to full size",
      "zoomOut": "Fit to screen",
      "openOriginal": "Open original",
      "download": "Download",
      "downloadFailed": "Couldn't download the attachment",
      "failed": "This attachment is no longer available",
      "imageAlt": "Shared image",
      "you": "You"
    },
    "actions": {
      "reply": "Reply",
      "copyText": "Copy text",
      "delete": "Delete",
      "react": "React",
      "reactWith": "React with {emoji}",
      "nothingToCopy": "Nothing to copy",
      "copied": "Copied",
      "copyFailed": "Copy failed"
    },
    "replyQuote": {
      "photo": "[Photo]",
      "video": "[Video]",
      "document": "[Document]",
      "audio": "[Audio]",
      "voiceMessage": "[Voice message]",
      "location": "[Location]",
      "template": "[Template]",
      "message": "[Message]",
      "cancelReply": "Cancel reply"
    },
    "templatePicker": {
      "sendTemplate": "Send template",
      "fillPlaceholders": "Fill in the placeholders to render this template. Meta requires every variable to be set.",
      "pickTemplate": "Pick an approved WhatsApp template to send to this contact.",
      "noApprovedTemplates": "No approved templates",
      "noApprovedTemplatesHint": "Approve a template in Meta WhatsApp Manager, then sync it from Settings → Templates.",
      "preview": "Preview",
      "headerValuePlaceholder": "Value for the header variable",
      "bodyValuePlaceholder": "Value for {val}",
      "urlSuffixValuePlaceholder": "URL suffix value",
      "finalUrl": "Final URL: {url}",
      "back": "Back",
      "cancel": "Cancel",
      "send": "Send template",
      "headerVarLabel": "Header {var}",
      "bodyVarLabel": "Body {var}",
      "urlButtonVarLabel": "URL button \"{text}\" — value for {var}"
    },
    "sidebar": {
      "contactInfo": "Contact info",
      "tags": "Tags",
      "notes": "Notes",
      "deals": "Deals",
      "noTags": "No tags",
      "noDeals": "No deals",
      "addNotePlaceholder": "Add a note..."
    },
    "aiBanner": {
      "pausedTitle": "AI assistant is paused here",
      "activeText": "AI assistant is replying automatically",
      "takeOver": "Take over",
      "resume": "Resume AI",
      "tookOver": "You’ve taken over this chat.",
      "resumed": "AI resumed.",
      "updateError": "Couldn’t update the AI assistant.",
      "networkError": "Couldn’t reach the server."
    }
  },
  "Contacts": {
    "page": {
      "title": "Contacts",
      "subtitle": "Manage your contact list. {count} total contacts.",
      "subtitleZero": "Manage your contact list.",
      "customFieldsBtn": "Custom fields",
      "selectAllOnPage": "Select all contacts on this page",
      "importBtn": "Import",
      "addContactBtn": "Add Contact",
      "searchPlaceholder": "Search by name, phone, or email...",
      "filterByTags": "Filter by tags",
      "clearAll": "Clear all",
      "noTagsYet": "No tags yet.",
      "selectedCount": "{count} selected",
      "clearSelection": "Clear",
      "deleteSelected": "Delete selected",
      "tableColumns": {
        "name": "Name",
        "phone": "Phone",
        "email": "Email",
        "company": "Company",
        "tags": "Tags",
        "createdAt": "Created"
      },
      "loading": "Loading contacts...",
      "noContactsMatch": "No contacts match your filters.",
      "noContactsYet": "No contacts yet.",
      "addFirstContact": "Add your first contact",
      "unnamed": "Unnamed",
      "editAction": "Edit",
      "deleteAction": "Delete",
      "showingPagination": "Showing {start}-{end} of {total}",
      "pageCount": "Page {page} of {total}",
      "deleteContactTitle": "Delete Contact",
      "deleteContactDesc": "Are you sure you want to delete {name}? This action cannot be undone.",
      "cancel": "Cancel",
      "deleteBtn": "Delete",
      "deleteBulkTitle": "Delete Contacts",
      "deleteBulkDesc": "Are you sure you want to delete {count} selected contacts? This action cannot be undone.",
      "toastFailedLoad": "Failed to load contacts",
      "toastFailedDelete": "Failed to delete contact",
      "toastDeleted": "Contact deleted",
      "toastBulkFailedDelete": "Failed to delete contacts",
      "toastBulkDeleted": "{count} contacts deleted",
      "filterByTag": "Filter by {name}",
      "removeTagFilter": "Remove {name} filter",
      "selectContact": "Select {name}"
    },
    "form": {
      "addTitle": "Add Contact",
      "addDesc": "Create a new contact. Name is required.",
      "editTitle": "Edit Contact",
      "editDesc": "Update contact details and tags.",
      "nameLabel": "Name",
      "namePlaceholder": "Jane Doe",
      "phoneLabel": "Phone Number",
      "phonePlaceholder": "+1234567890",
      "phoneHint": "Include country code, e.g. +1 for US",
      "emailLabel": "Email",
      "emailPlaceholder": "jane@example.com",
      "companyLabel": "Company",
      "companyPlaceholder": "Acme Corp",
      "tagsLabel": "Tags",
      "tagsPlaceholder": "Select tags...",
      "noTagsFound": "No tags found.",
      "createTagAction": "Create tag \"{value}\"",
      "cancel": "Cancel",
      "save": "Save Contact",
      "update": "Update",
      "create": "Create",
      "toastSuccessAdd": "Contact created successfully",
      "toastSuccessEdit": "Contact updated successfully",
      "toastError": "Failed to save contact",
      "toastConflict": "A contact with this phone number already exists",
      "viewExisting": "View {name}",
      "dupExact": "A contact with this phone number already exists.",
      "dupSimilar": "A contact with a very similar number already exists.",
      "loadingTags": "Loading tags...",
      "noTagsAvailable": "No tags available. Create tags in Settings.",
      "phoneRequired": "Phone number is required",
      "phoneNeedsCountryCode": "Include the country code — the number must start with + (e.g. +14155550123)",
      "notAuthenticated": "Not authenticated",
      "notLinkedToAccount": "Your profile is not linked to an account."
    },
    "detailView": {
      "tabs": {
        "details": "Details",
        "activity": "Activity",
        "notes": "Notes",
        "custom": "Custom Fields",
        "deals": "Deals",
        "tags": "Tags",
        "noTags": "No tags",
        "noDeals": "No deals",
        "addNotePlaceholder": "Add a note..."
      },
      "actions": {
        "edit": "Edit",
        "message": "Message",
        "delete": "Delete"
      },
      "contactInfo": "Contact Information",
      "unnamed": "Unknown",
      "contactDetailsDesc": "Contact details",
      "name": "Name",
      "phone": "Phone",
      "email": "Email",
      "company": "Company",
      "createdAt": "Created At",
      "customFields": "Custom Fields",
      "noCustomFields": "No custom fields defined. Create them in Settings.",
      "manageFields": "Manage fields",
      "enterCustomField": "Enter {name}...",
      "activityTab": {
        "title": "Activity History",
        "noActivity": "No activity yet."
      },
      "notesTab": {
        "title": "Internal Notes",
        "placeholder": "Write a note...",
        "save": "Add Note",
        "noNotes": "No notes yet."
      },
      "dealsTab": {
        "noDeals": "No deals yet"
      },
      "tagsTab": {
        "clickTagDesc": "Click a tag to add or remove it from this contact.",
        "noTagsAvailable": "No tags available. Create tags in Settings."
      },
      "sendTemplateBtn": "Send template",
      "saveChangesBtn": "Save Changes",
      "saveCustomFieldsBtn": "Save Custom Fields",
      "toastPhoneRequired": "Phone number is required",
      "toastPhoneNeedsCountryCode": "Include the country code — the number must start with + (e.g. +14155550123)",
      "toastUpdateFailed": "Failed to update contact",
      "toastUpdated": "Contact updated",
      "toastNotAuthenticated": "Not authenticated",
      "toastNoteAddFailed": "Failed to add note",
      "toastNoteAdded": "Note added",
      "toastNoteDeleteFailed": "Failed to delete note",
      "toastNoteDeleted": "Note deleted",
      "toastCustomFieldsSaved": "Custom fields saved",
      "toastCustomFieldsFailed": "Failed to save custom fields",
      "toastTemplateSent": "Template \"{name}\" sent",
      "toastTemplateFailed": "Failed to send template: {reason}",
      "networkError": "network error"
    },
    "importModal": {
      "title": "Import Contacts",
      "desc": "Upload a CSV with a required <phoneCode>phone</phoneCode> column. Optional: <nameCode>name</nameCode>, <emailCode>email</emailCode>, <companyCode>company</companyCode>, <tagsCode>tags</tagsCode> (comma-separated; quote multi-tag cells).",
      "uploadDropzone": "Click to choose a CSV file",
      "uploadHint": ".csv up to your browser limit",
      "rowsReady": "{count} row ready",
      "rowsReady_plural": "{count} rows ready",
      "preview": "Preview · first {count}",
      "previewTags": "{tags} tag · {contacts} contact",
      "previewTags_plural": "{tags} tags · {contacts} contacts",
      "moreRows": "+ {count} more row not shown",
      "moreRows_plural": "+ {count} more rows not shown",
      "importComplete": "Import complete",
      "resultImported": "{count} imported",
      "resultTags": "{count} tag assigned",
      "resultTags_plural": "{count} tags assigned",
      "resultSkipped": "{count} skipped",
      "resultInvalidPhone": "{count} invalid phone",
      "resultInvalidPhone_plural": "{count} invalid phones",
      "resultFailed": "{count} failed",
      "invalidPhoneHint": "Phone numbers must start with + and a country code (e.g. +14155550123). Numbers without one would be delivered to the wrong country.",
      "failedRowsHeading": "Failed rows",
      "unknownReason": "Unknown error",
      "willBeCreated": "{name} (will be created on import)",
      "columns": {
        "phone": "Phone",
        "name": "Name",
        "email": "Email",
        "company": "Company",
        "tags": "Tags"
      },
      "cancel": "Cancel",
      "close": "Close",
      "importBtn": "Import {count} contact",
      "importBtn_plural": "Import {count} contacts",
      "toastNoValidRows": "No valid rows found. Ensure CSV has a \"phone\" column header.",
      "toastTagsWarning": "Contacts imported, but some tag assignments failed.",
      "toastImported": "{count} contact imported",
      "toastImported_plural": "{count} contacts imported",
      "toastTagsAssigned": "{count} tag assignment applied",
      "toastTagsAssigned_plural": "{count} tag assignments applied",
      "toastTagsSkipped": "Unknown tags skipped (create them in Settings first): {sample}{more}",
      "toastSkipped": "{count} duplicate skipped",
      "toastSkipped_plural": "{count} duplicates skipped",
      "toastInvalidPhone": "{count} contact had no usable phone number",
      "toastInvalidPhone_plural": "{count} contacts had no usable phone number",
      "toastFailed": "{count} contact failed to import",
      "toastFailed_plural": "{count} contacts failed to import",
      "toastError": "Import failed",
      "notAuthenticated": "Not authenticated",
      "notLinkedToAccount": "Your profile is not linked to an account.",
      "toastTagsSkippedMore": " (+{count} more)"
    },
    "customFields": {
      "title": "Custom fields",
      "desc": "Define extra contact fields (e.g. ZIP code, lead source). They appear on every contact and in the “Update Contact Field” automation action.",
      "addField": "Add",
      "fieldName": "New field name…",
      "loading": "Loading…",
      "empty": "No custom fields yet.",
      "renameAria": "Rename {name}",
      "deleteTitle": "Delete field",
      "deleteConfirm": "Delete \"{name}\"? This also removes its stored value on every contact. This cannot be undone.",
      "toastNoAccount": "Your profile is not linked to an account.",
      "toastDuplicate": "A field named \"{name}\" already exists.",
      "toastCreateFailed": "Could not create field. You may not have permission.",
      "toastCreated": "Created \"{name}\".",
      "toastRenameFailed": "Could not rename field.",
      "toastDeleteFailed": "Could not delete field.",
      "toastDeleted": "Deleted \"{name}\"."
    }
  },
  "Pipelines": {
    "page": {
      "selectPipeline": "Select Pipeline",
      "noPipelinesYet": "No pipelines yet",
      "managePipelines": "Manage Pipelines",
      "addPipeline": "Add Pipeline",
      "addDeal": "Add Deal",
      "createToStartTracking": "Create a pipeline to start tracking deals",
      "createPipeline": "Create Pipeline",
      "newPipeline": "New Pipeline",
      "pipelineName": "Pipeline Name",
      "pipelineNamePlaceholder": "e.g., Enterprise Sales",
      "defaultStagesDesc": "Default stages (New Lead → Won) will be created automatically.",
      "cancel": "Cancel",
      "creating": "Creating...",
      "createPipelineBtn": "Create Pipeline",
      "toastFailedLoadPipelines": "Failed to load pipelines",
      "toastFailedMoveDeal": "Failed to move deal",
      "toastFailedCreatePipeline": "Failed to create pipeline",
      "toastPipelineCreated": "Pipeline created",
      "toastNotLinkedToAccount": "Your profile is not linked to an account.",
      "defaultPipelineName": "Sales Pipeline",
      "defaultStages": {
        "newLead": "New Lead",
        "qualified": "Qualified",
        "proposalSent": "Proposal Sent",
        "negotiation": "Negotiation",
        "won": "Won"
      }
    },
    "board": {
      "dropDealHere": "Drop a deal here",
      "addDeal": "Add Deal"
    },
    "card": {
      "noContact": "No contact",
      "won": "Won",
      "lost": "Lost"
    },
    "form": {
      "editDeal": "Edit Deal",
      "newDeal": "New Deal",
      "title": "Title",
      "titlePlaceholder": "Deal title",
      "contact": "Contact",
      "selectContact": "Select a contact",
      "linkToConversation": "Link to Conversation",
      "value": "Value",
      "currency": "Currency",
      "expectedCloseDate": "Expected Close Date",
      "stage": "Stage",
      "assignedTo": "Assigned To",
      "unassigned": "Unassigned",
      "notes": "Notes",
      "notesPlaceholder": "Add notes...",
      "status": "Status",
      "markAsWon": "Mark as Won",
      "markAsLost": "Mark as Lost",
      "reopenDeal": "Reopen deal",
      "cancel": "Cancel",
      "saving": "Saving...",
      "saveChanges": "Save Changes",
      "createDeal": "Create Deal",
      "deletePrompt": "Delete this deal?",
      "confirm": "Confirm",
      "deleting": "Deleting...",
      "deleteDeal": "Delete Deal",
      "toastRequired": "Title, contact, and stage are required",
      "toastFailedSave": "Failed to save deal",
      "toastNotSignedIn": "Not signed in",
      "toastNotLinked": "Your profile is not linked to an account.",
      "toastFailedCreate": "Failed to create deal",
      "toastUpdated": "Deal updated",
      "toastCreated": "Deal created",
      "toastFailedStatus": "Failed to update deal status",
      "toastMarkedWon": "Marked as won",
      "toastMarkedLost": "Marked as lost",
      "toastReopened": "Deal reopened",
      "toastFailedDelete": "Failed to delete deal",
      "toastDeleted": "Deal deleted"
    },
    "settings": {
      "managePipeline": "Manage Pipeline",
      "deletePipeline": "Delete Pipeline",
      "deletePipelineDesc": "This will archive all deals in this pipeline. This cannot be undone.",
      "cancel": "Cancel",
      "deleting": "Deleting...",
      "deletePipelineBtn": "Delete Pipeline",
      "pipelineName": "Pipeline Name",
      "stages": "Stages",
      "newStageNamePlaceholder": "New stage name",
      "add": "Add",
      "createNewPipeline": "Create a new pipeline",
      "saving": "Saving...",
      "saveChanges": "Save Changes",
      "dragToReorder": "Drag to reorder",
      "changeColor": "Change color",
      "toastFailedSave": "Failed to save pipeline",
      "toastSaved": "Pipeline saved",
      "toastFailedAddStage": "Failed to add stage",
      "toastMoveOrDeleteDeals": "Move or delete deals in this stage first",
      "toastFailedDeleteStage": "Failed to delete stage",
      "toastFailedDeletePipeline": "Failed to delete pipeline",
      "toastDeleted": "Pipeline deleted",
      "pickColor": "Pick color {color}"
    },
    "analytics": {
      "totalDeals": "Total Deals",
      "totalDealsTooltip": "Count of every deal in this pipeline that isn't marked as Lost. Won deals are still included.",
      "pipelineValue": "Pipeline Value",
      "pipelineValueTooltip": "Sum of the dollar values of all deals in this pipeline, excluding deals marked as Lost.",
      "avgDealSize": "Avg Deal Size",
      "avgDealSizeTooltip": "Pipeline Value divided by Total Deals — the average value of a single non-lost deal.",
      "weightedValue": "Weighted Value",
      "weightedValueTooltip": "Expected revenue: each open deal's value × its stage probability. First stage ≈ 10%, stages progress up to 90%, Won = 100%. Lost deals are excluded.",
      "wonThisMonth": "Won This Month",
      "wonThisMonthTooltip": "Deals marked as Won since the first day of the current month.",
      "lostThisMonth": "Lost This Month",
      "lostThisMonthTooltip": "Deals marked as Lost since the first day of the current month.",
      "howCalculated": "How {label} is calculated"
    }
  },
  "Broadcasts": {
    "page": {
      "title": "Broadcasts",
      "subtitle": "Send bulk messages to your contacts using approved templates.",
      "newBroadcast": "New Broadcast",
      "noBroadcastsYet": "No broadcasts yet",
      "createFirst": "Create your first broadcast to reach your contacts at scale.",
      "table": {
        "name": "Name",
        "template": "Template",
        "recipients": "Recipients",
        "delivery": "Delivery",
        "read": "Read",
        "status": "Status",
        "date": "Date"
      },
      "errorLoad": "Failed to load broadcasts",
      "broadcastInProgress": "Broadcast in progress",
      "retry": "Retry"
    },
    "status": {
      "draft": "Draft",
      "scheduled": "Scheduled",
      "sending": "Sending",
      "sent": "Sent",
      "failed": "Failed",
      "pending": "Pending",
      "delivered": "Delivered",
      "read": "Read",
      "replied": "Replied",
      "unknown": "Unknown"
    },
    "detail": {
      "backToBroadcasts": "Back to Broadcasts",
      "notFound": "Broadcast not found",
      "template": "Template: {name}",
      "createdAt": "Created {date}",
      "deletePrompt": "Delete this broadcast?",
      "cancel": "Cancel",
      "confirm": "Confirm",
      "deleting": "Deleting…",
      "delete": "Delete",
      "cannotDeleteSending": "Cannot delete while a broadcast is actively sending",
      "deleteHover": "Delete this broadcast",
      "funnel": "Funnel",
      "recipientsHeader": "Recipients ({filtered} of {total})",
      "recipientsHeaderAll": "Recipients ({total})",
      "allStatuses": "All statuses",
      "exportCsv": "Export CSV",
      "noRecipients": "No recipients found.",
      "noRecipientsFilter": "No recipients match this filter.",
      "table": {
        "contact": "Contact",
        "phone": "Phone",
        "status": "Status",
        "sent": "Sent",
        "delivered": "Delivered",
        "read": "Read",
        "error": "Error"
      },
      "stats": {
        "totalRecipients": "Total Recipients",
        "sent": "Sent",
        "delivered": "Delivered",
        "read": "Read",
        "replied": "Replied",
        "failed": "Failed"
      },
      "toastFailedDelete": "Failed to delete: {error}",
      "toastDeleted": "Broadcast deleted",
      "resumeTitle": "Some recipients need another attempt",
      "resumeStalledTitle": "This campaign stopped part-way",
      "resumeHint": "{count} recipients failed. Retrying sends them again from the server.",
      "resumeStalledHint": "{count} recipients were never sent — the browser tab running this campaign was closed before it finished. Resuming completes it from the server.",
      "resumePending": "Resume sending ({count})",
      "retryFailed": "Retry failed ({count})",
      "toastResumeStarted": "Sending {count} recipients in the background.",
      "toastResumeStartedCapped": "Sending {count} recipients in the background. {remaining} more will need another run.",
      "toastResumeFailed": "Could not resume: {error}",
      "unknownError": "Unknown error",
      "unknownContact": "Unknown"
    },
    "new": {
      "title": "New Broadcast",
      "subtitle": "Create and send a broadcast message to your contacts.",
      "steps": {
        "template": "Template",
        "audience": "Audience",
        "personalize": "Personalize",
        "send": "Send"
      },
      "toastGiveName": "Give the broadcast a name before saving a draft.",
      "toastNotSignedIn": "Not signed in.",
      "toastNotLinked": "Your profile is not linked to an account.",
      "toastFailedDraft": "Failed to save draft: {error}",
      "toastDraftSaved": "Draft saved",
      "broadcastFailed": "Broadcast failed"
    },
    "wizard": {
      "next": "Next",
      "back": "Back",
      "cancel": "Cancel",
      "chooseTemplate": {
        "title": "Choose a Template",
        "subtitle": "Select an approved message template for your broadcast.",
        "noTemplates": "No templates available.",
        "createFirst": "Create a template in Settings first.",
        "errorLoad": "Failed to load templates"
      },
      "selectAudience": {
        "title": "Select Audience",
        "subtitle": "Choose who will receive this broadcast.",
        "method": {
          "all": "All Contacts",
          "tags": "Filter by Tags",
          "customField": "Custom Field",
          "csv": "Upload CSV"
        },
        "allDesc": "Send to all {count} contacts in your database.",
        "allDescLoading": "Send to all contacts in your database.",
        "tagDesc": "Send to contacts matching specific tags.",
        "customFieldDesc": "Send to contacts matching a custom field rule.",
        "csvDesc": "Upload a CSV with phone numbers (and optional names).",
        "selectTags": "Select Tags",
        "searchTags": "Search tags...",
        "noTagsFound": "No tags found.",
        "excludeTags": "Exclude Tags (Optional)",
        "searchExcludeTags": "Search tags to exclude...",
        "field": "Field",
        "selectField": "Select a field...",
        "operator": "Operator",
        "operatorIs": "Is",
        "operatorIsNot": "Is not",
        "operatorContains": "Contains",
        "value": "Value",
        "valuePlaceholder": "Value to match",
        "uploadCsv": "Upload CSV File",
        "csvFormatDesc": "Must contain a 'phone' column (E.164 format). 'name' column is optional.",
        "csvContactsFound": "{count} valid contact(s) found in CSV.",
        "csvInvalidPhones": "{count} row(s) skipped: phone numbers must start with + and a country code (e.g. +14155550123).",
        "errorLoadTags": "Failed to load tags",
        "errorLoadFields": "Failed to load custom fields",
        "errorCsvParse": "Could not parse CSV file.",
        "errorCsvMissingPhone": "CSV must have a 'phone' column.",
        "audienceSummary": "Audience Summary",
        "calculating": "Calculating…",
        "estimatedRecipients": "estimated recipients",
        "selectTypeForEstimate": "Select an audience type to see the estimate."
      },
      "personalize": {
        "title": "Personalize Variables",
        "subtitle": "Map your template variables to contact fields or provide static values.",
        "headerImage": "Header Image",
        "headerImageDesc": "This template requires a header image.",
        "imageUrl": "Image URL",
        "imageUrlPlaceholder": "https://example.com/image.jpg",
        "variables": "Variables",
        "varDesc": "Set values for {{name}}",
        "type": "Type",
        "typeStatic": "Static Value",
        "typeContact": "Contact Field",
        "typeCustom": "Custom Field",
        "staticValue": "Static Value",
        "contactField": "Contact Field",
        "selectContactField": "Select field...",
        "customField": "Custom Field",
        "selectCustomField": "Select custom field...",
        "preview": "Preview",
        "previewSample": "Showing preview with sample data.",
        "noPreview": "Preview not available.",
        "headerPreviewAlt": "Header preview",
        "mediaUrlRequired": "A media URL is required to send this template.",
        "mediaUrlInvalid": "Enter a valid http(s) URL.",
        "enterValue": "Enter value...",
        "loadingFields": "Loading…",
        "noCustomFields": "No custom fields",
        "unmappedWarning": "Map every placeholder before continuing — still missing <mono>{keys}</mono>. Otherwise those placeholders will ship to Meta as empty strings.",
        "fieldMap": {
          "name": "Name",
          "phone": "Phone",
          "email": "Email"
        },
        "sampleName": "John Doe",
        "sampleCompany": "Acme Corp"
      },
      "scheduleSend": {
        "title": "Review & Send",
        "subtitle": "Give your broadcast a name and confirm sending.",
        "broadcastName": "Broadcast Name",
        "broadcastNamePlaceholder": "e.g., Summer Promo",
        "summary": "Summary",
        "template": "Template:",
        "audience": "Audience:",
        "audienceAll": "All contacts",
        "audienceTags": "Filtered by tags",
        "audienceField": "Filtered by custom field",
        "audienceCsv": "CSV upload",
        "variables": "Variables:",
        "variablesMapped": "{count} mapped",
        "saveDraft": "Save as Draft",
        "sendNow": "Send Broadcast",
        "sending": "Sending...",
        "preparing": "Preparing...",
        "progressDesc": "Processing {current} of {total} recipients...",
        "toastFailedPreview": "Failed to load preview data",
        "estimatedReach": "Estimated Reach",
        "language": "Language",
        "confirmTitle": "Confirm Broadcast",
        "confirmDesc": "You are about to send this broadcast to <b>{count, number}</b> {count, plural, =1 {contact} other {contacts}} using the <b>{template}</b> template. This action cannot be undone."
      }
    },
    "sending": {
      "notSignedIn": "You are not signed in.",
      "notLinkedToAccount": "Your profile is not linked to an account.",
      "lookupCsvContactsFailed": "Failed to look up CSV contacts: {error}",
      "createCsvContactsFailed": "Failed to create CSV contacts: {error}",
      "noContactsForAudience": "No contacts found for this audience.",
      "createBroadcastFailed": "Failed to create broadcast: {error}",
      "unknownErrorLower": "unknown error",
      "insertRecipientBatchFailed": "Failed to insert recipient batch {batch}: {error}",
      "fetchRecipientsFailed": "Failed to fetch broadcast recipients",
      "apiRequestFailed": "Broadcast API request failed",
      "noPhoneOnContact": "No phone number on contact",
      "unknownError": "Unknown error"
    }
  },
  "Automations": {
    "list": {
      "title": "Automations",
      "subtitle": "Build workflows that react to WhatsApp® events automatically.",
      "create": "Create Automation",
      "retry": "Retry",
      "templatesTitle": "Quick-start templates",
      "emptyTitle": "No automations yet",
      "emptyDesc": "Pick a template above or create one from scratch.",
      "runs": "{count} run",
      "runsPlural": "{count} runs",
      "lastRun": "last {time}",
      "activate": "Activate",
      "deactivate": "Deactivate",
      "edit": "Edit",
      "duplicate": "Duplicate",
      "viewLogs": "View Logs",
      "delete": "Delete",
      "cancel": "Cancel",
      "deleteTitle": "Delete automation",
      "deleteDesc": "This permanently removes {name} and its execution history. This cannot be undone.",
      "activeIndicator": "active",
      "openMenu": "Open menu",
      "toasts": {
        "activated": "Automation activated",
        "paused": "Automation paused",
        "duplicated": "Automation duplicated",
        "deleted": "Automation deleted",
        "updateError": "Failed to update",
        "duplicateError": "Failed to duplicate",
        "deleteError": "Failed to delete"
      },
      "loadFailed": "Failed to load automations"
    },
    "edit": {
      "loading": "Loading...",
      "loadError": "Failed to load ({status})",
      "back": "Back to Automations"
    },
    "logs": {
      "title": "Execution logs",
      "loadError": "Failed to load logs",
      "emptyTitle": "No executions yet",
      "emptyDesc": "Trigger this automation to see runs here.",
      "unknownContact": "Unknown contact",
      "step": "{count} step",
      "stepPlural": "{count} steps",
      "noSteps": "No steps recorded.",
      "status": {
        "success": "success",
        "partial": "partial",
        "failed": "failed"
      },
      "back": "Back",
      "backAria": "Back"
    },
    "relative": {
      "never": "never",
      "justNow": "just now",
      "minutesAgo": "{n}m ago",
      "hoursAgo": "{n}h ago",
      "daysAgo": "{n}d ago"
    },
    "builder": {
      "steps": {
        "send_message": "Send Message",
        "send_buttons": "Send Buttons",
        "send_list": "Send List",
        "send_template": "Send Template",
        "add_tag": "Add Tag",
        "remove_tag": "Remove Tag",
        "assign_conversation": "Assign Conversation",
        "update_contact_field": "Update Contact Field",
        "create_deal": "Create Deal",
        "wait": "Wait",
        "condition": "Condition (If/Else)",
        "send_webhook": "Send Webhook",
        "close_conversation": "Close Conversation"
      },
      "triggers": {
        "new_message_received": {
          "label": "New Message Received",
          "hint": "Any incoming message"
        },
        "first_inbound_message": {
          "label": "First Message from Contact",
          "hint": "First time this contact ever messages you (works for manually-added contacts too)"
        },
        "keyword_match": {
          "label": "Keyword Match",
          "hint": "Message contains specific keyword(s)"
        },
        "interactive_reply": {
          "label": "Button / List Reply",
          "hint": "Customer taps a button or list row whose id matches — chain menus across automations"
        },
        "new_contact_created": {
          "label": "New Contact Created",
          "hint": "When a contact is auto-created from an incoming message"
        },
        "conversation_assigned": {
          "label": "Conversation Assigned",
          "hint": "When assigned to an agent"
        },
        "tag_added": {
          "label": "Tag Added",
          "hint": "When a tag is added to a contact"
        },
        "time_based": {
          "label": "Time-Based",
          "hint": "On a recurring schedule"
        }
      },
      "trigger": "Trigger",
      "triggerType": "Trigger type",
      "keywords": "Keywords",
      "keywordsHint": "Comma-separated list (e.g. hello, help, buy)",
      "replyIds": "Reply IDs",
      "replyIdsHint": "yes, no, more_info",
      "replyIdsHelp": "Comma-separated button/list-row ids to match, exact. Use the same ids you set on a Send Buttons / Send List step.",
      "schedule": "Schedule",
      "scheduleHint": "Cron expression (e.g. 0 9 * * 1-5)",
      "schedulePlaceholder": "Cron expression or HH:mm",
      "active": "Active",
      "activeAria": "Active",
      "save": "Save",
      "saveDraft": "Save Draft",
      "untitled": "Untitled automation",
      "backToAutomations": "Back to automations",
      "toasts": {
        "saved": "Automation saved",
        "created": "Automation created",
        "saveFailed": "Save failed",
        "issueAt": "at {path}"
      },
      "tags": {
        "select": "Select a tag…",
        "placeholder": "Tag id",
        "unknown": "{id} (unknown tag)"
      },
      "fields": {
        "name": "Name",
        "email": "Email",
        "company": "Company",
        "customFields": "Custom fields",
        "unknown": "{id} (unknown field)"
      },
      "agents": {
        "select": "Select an agent…",
        "placeholder": "Agent id",
        "unknown": "{id} (unknown agent)"
      },
      "pipelines": {
        "pipelineLabel": "Pipeline",
        "pipelineIdLabel": "Pipeline id",
        "stageLabel": "Stage",
        "stageIdLabel": "Stage id",
        "selectPipeline": "Select a pipeline…",
        "selectStage": "Select a stage…",
        "selectPipelineFirst": "Select a pipeline first…",
        "unknownPipeline": "{id} (unknown pipeline)",
        "unknownStage": "{id} (unknown stage)"
      },
      "templates": {
        "templateLabel": "Template",
        "templateNameLabel": "Template name",
        "languageLabel": "Language",
        "select": "Select a template…",
        "unknown": "{name} ({lang}) — not in approved list",
        "unknownLang": "unknown"
      },
      "branches": {
        "yes": "Yes",
        "no": "No"
      },
      "addStep": "Add step",
      "moveUp": "Move up",
      "moveDown": "Move down",
      "kindCondition": "Condition",
      "kindWait": "Wait",
      "kindAction": "Action",
      "delete": "Delete",
      "config": {
        "messageText": "Message text",
        "placeholderMessageText": "Hi! Thanks for reaching out…",
        "tagLabel": "Tag",
        "modeLabel": "Mode",
        "modes": {
          "round_robin": "Round-robin",
          "specific": "Specific agent"
        },
        "agentLabel": "Agent",
        "fieldLabel": "Field",
        "valueLabel": "Value",
        "placeholderValue": "Text or {{ vars.x }} / {{ message.text }}",
        "titleLabel": "Title",
        "amountLabel": "Amount",
        "unitLabel": "Unit",
        "units": {
          "minutes": "Minutes",
          "hours": "Hours",
          "days": "Days"
        },
        "subjectLabel": "Subject",
        "subjects": {
          "tag_presence": "Tag presence",
          "contact_field": "Contact field",
          "message_content": "Message content",
          "time_of_day": "Time of day"
        },
        "operandLabel": "Operand",
        "placeholderTime": "HH:mm-HH:mm",
        "placeholderContact": "name / email / company",
        "placeholderTag": "tag id",
        "urlLabel": "URL",
        "headersLabel": "Headers",
        "placeholderHeaders": "{\"Authorization\": \"Bearer ...\"}",
        "bodyTemplateLabel": "Body template",
        "placeholderBody": "{\"id\": \"{{ contact.id }}\"}",
        "matchType": "Match type",
        "matchContains": "Contains",
        "matchWord": "Whole word",
        "matchWordHint": "Matches the keyword only as a standalone word, so \"k\" no longer fires on \"thanks\". Best for short keywords in space-separated languages; use Contains for languages written without spaces.",
        "matchExact": "Exact",
        "waitForReply": "Wait for reply before continuing",
        "waitForReplyHint": "Pauses here until the customer taps a button or replies (up to 24h). The steps after this one, including If/Else on message content, then use their reply.",
        "closeConversationHint": "Sets the conversation status to \"closed\". No configuration needed."
      },
      "preview": {
        "noText": "no text yet",
        "noBody": "no body yet",
        "withWaitForReply": "{preview} · waits for reply",
        "pickTemplate": "pick a template",
        "wait": "{amount} {unit}",
        "units": {
          "minutes": "minutes",
          "hours": "hours",
          "days": "days"
        },
        "when": "when {subject}",
        "noUrl": "no url"
      }
    }
  },
  "Flows": {
    "list": {
      "title": "Flows",
      "beta": "Beta",
      "description": "Build branching, button-driven WhatsApp conversations. Useful for menus, FAQs, and triage before a human steps in.",
      "newFlow": "New flow",
      "statusDraft": "Draft",
      "statusActive": "Active",
      "statusArchived": "Archived",
      "loadError": "Couldn't load flows.",
      "createError": "Couldn't create flow.",
      "cloneError": "Clone failed",
      "deleteConfirm": "Delete \"{name}\"? Any active runs will end immediately.",
      "deleteSuccess": "Flow deleted.",
      "deleteError": "Couldn't delete flow.",
      "emptyTitle": "No flows yet",
      "emptyDesc": "Build your first conversation — a welcome menu, an order lookup, an FAQ bot. Customers tap buttons; the bot routes them to the right answer (or the right agent).",
      "createFirst": "Create your first flow",
      "createTitle": "Create a new flow",
      "createDesc": "Start from a template or build from scratch.",
      "startTemplate": "Start from a template",
      "nodeCount": "{count} {count, plural, =1 {node} other {nodes}}",
      "startBlank": "Or start blank",
      "placeholderName": "e.g. Welcome menu",
      "cancel": "Cancel",
      "createBlank": "Create blank flow",
      "runCount": "{count} {count, plural, =1 {run} other {runs}}",
      "edit": "Edit",
      "delete": "Delete",
      "triggerKeywordNone": "Triggers on keyword (none set)",
      "triggerKeyword": "Triggers on: {keywords}",
      "triggerFirstInbound": "Triggers on a contact's first-ever inbound message",
      "triggerManual": "Manual trigger",
      "cloneFailedStatus": "Clone failed: {status}"
    },
    "edit": {
      "notFound": "Flow not found.",
      "backToFlows": "← Back to flows",
      "loadError": "Couldn't load flow."
    },
    "logs": {
      "title": "Runs",
      "description": "The 50 most recent times this flow ran. Expand a row to see the engine's per-step log.",
      "emptyState": "No runs yet. Trigger the flow from a personal WhatsApp number to see it appear here.",
      "loadError": "Couldn't load runs.",
      "unknownContact": "Unknown contact",
      "atNode": "at {node}",
      "started": "Started {time}",
      "reprompts": "{count} re-prompts",
      "ranFor": "ran for {duration}",
      "capturedVars": "Captured vars ({count})",
      "noEvents": "No events recorded for this run.",
      "statusActive": "Active",
      "statusCompleted": "Completed",
      "statusHandedOff": "Handed off",
      "statusTimedOut": "Timed out",
      "statusPaused": "Paused by agent",
      "statusFailed": "Failed"
    },
    "builder": {
      "triggerTitle": "Trigger",
      "whenLabel": "When…",
      "triggerKeywordTitle": "A message contains a keyword",
      "triggerFirstInboundTitle": "Customer's first ever inbound message",
      "triggerManualTitle": "Manual only (no auto-trigger)",
      "keywordsLabel": "Keywords (comma-separated)",
      "keywordsPlaceholder": "support, help, hi",
      "entryNodeTitle": "Entry node:",
      "entryNodePlaceholder": "Pick the first node…",
      "nodesTitle": "Nodes ({count})",
      "nodesEmpty": "Add a <strong>Start</strong> node, then a <strong>Send buttons</strong> node, then a <strong>Handoff</strong> — that's the welcome-menu shape from the brief.",
      "addNode": "Add node",
      "setAsEntry": "Set as entry",
      "removeNode": "Remove node",
      "showAdvanced": "Show advanced",
      "hideAdvanced": "Hide advanced",
      "nodeKeyLabel": "Node key (internal identifier — keep stable for analytics)",
      "replyIdsHint": "Reply IDs for each option are shown inline above. They're returned by WhatsApp when a customer taps; you usually don't need to touch them.",
      "badgeEntry": "Entry",
      "noNodesYet": "No nodes yet.",
      "deleteNode": "Delete node",
      "canvasView": "Canvas",
      "listView": "List",
      "noNodeSelected": "No node selected",
      "noNodeDesc": "Select a node on the canvas to edit its configuration.",
      "editorView": "Editor view",
      "form": {
        "advancesTo": "Advances to",
        "textToCustomer": "Text sent to the customer",
        "promptToCustomer": "Prompt sent to the customer",
        "varKeyLabel": "Variable key (stored in flow_runs.vars; alphanumeric + underscore)",
        "varKeyPlaceholder": "e.g. name, email, company",
        "varKeyHelp": "Interpolate in downstream prompts and handoff notes with",
        "advanceAfterCapture": "After capturing, advance to",
        "internalNote": "Internal note (for the agent picking up)",
        "endNodeHelp": "Terminal node. When the runner reaches this node the run is marked complete. No config needed.",
        "bodyText": "Body text",
        "footerText": "Footer (optional, 60 chars)",
        "buttonsHelp": "Buttons (1–3) — each one routes to a different next node",
        "optionTitlePlaceholder": "Visible title (≤20 chars)",
        "nextNodePlaceholder": "Next node…",
        "addButton": "Add button",
        "buttonLabel": "Tap-to-expand button label (≤20 chars)",
        "rowsHelp": "Rows (1–10 total across all sections)",
        "sectionTitlePlaceholder": "Section {count} title (optional)",
        "rowTitlePlaceholder": "Row title (≤24)",
        "addRow": "Add row",
        "addSection": "Add section",
        "ifLabel": "If",
        "capturedVariable": "Captured variable",
        "contactHasTag": "Contact has tag",
        "contactField": "Contact field",
        "varName": "var name",
        "tagLabel": "Tag",
        "fieldLabel": "Field",
        "pickTag": "Pick a tag…",
        "pickField": "Pick a field…",
        "operatorLabel": "Operator",
        "isPresent": "is present",
        "isAbsent": "is absent",
        "equals": "equals",
        "contains": "contains",
        "valueLabel": "Value",
        "ifTrueAdvance": "If true → advance to",
        "ifFalseAdvance": "If false → advance to",
        "actionLabel": "Action",
        "addTag": "Add tag",
        "removeTag": "Remove tag",
        "tagUuidPlaceholder": "Tag UUID",
        "thenAdvanceTo": "Then advance to",
        "mediaTypeLabel": "Media type",
        "imageLabel": "Image (PNG, JPEG, WebP)",
        "videoLabel": "Video (MP4, 3GP)",
        "documentLabel": "Document (PDF, Word, Excel, PowerPoint, TXT)",
        "fileLabel": "File",
        "removeFile": "Remove file",
        "uploading": "Uploading…",
        "clickToUpload": "Click to upload (max 16 MB)",
        "captionLabel": "Caption (optional, shown under the media)",
        "filenameLabel": "Filename shown to the customer (documents only)",
        "filenamePlaceholder": "invoice.pdf",
        "advanceAfterSending": "After sending, advance to",
        "pickNextNode": "Pick a next node…",
        "none": "— None —",
        "removeSection": "Remove section",
        "fileUploaded": "File uploaded.",
        "uploadFailed": "Upload failed.",
        "fileTooLarge": "File is {size} MB — limit is 16 MB.",
        "defaultOptionTitle": "Option",
        "optionN": "Option {n}"
      },
      "categories": {
        "messaging": "Messaging",
        "logic": "Logic & data",
        "flow": "Flow control"
      },
      "nodes": {
        "start": {
          "label": "Start",
          "blurb": "Entry point of the flow"
        },
        "send_message": {
          "label": "Send message",
          "blurb": "Sends a WhatsApp text message"
        },
        "send_buttons": {
          "label": "Send buttons",
          "blurb": "Sends quick-reply buttons"
        },
        "send_list": {
          "label": "Send list",
          "blurb": "Sends a tappable list of options"
        },
        "send_media": {
          "label": "Send media",
          "blurb": "Sends an image, video, or document"
        },
        "collect_input": {
          "label": "Collect input",
          "blurb": "Asks a question, saves the reply"
        },
        "condition": {
          "label": "If / else",
          "blurb": "Branches on a rule"
        },
        "set_tag": {
          "label": "Tag contact",
          "blurb": "Adds or removes a contact tag"
        },
        "handoff": {
          "label": "Handoff to agent",
          "blurb": "Hands the conversation to a human"
        },
        "end": {
          "label": "End",
          "blurb": "Ends the flow"
        }
      }
    },
    "validation": {
      "noIssues": "No issues. Ready to activate.",
      "summary": "{errorCount} {errorCount, plural, =1 {error} other {errors}}, {warningCount} {warningCount, plural, =1 {warning} other {warnings}}",
      "jumpToNode": "Jump to node {key}"
    },
    "editorState": {
      "saved": "Saved.",
      "fixIssues": "Fix the issues below before activating.",
      "statusActivated": "Flow activated.",
      "statusArchived": "Archived.",
      "statusDraft": "Saved as draft.",
      "deleteConfirm": "Delete \"{name}\"? Any active runs end immediately. This can't be undone.",
      "defaultYes": "Yes",
      "defaultListButton": "View options",
      "saveFailedStatus": "Save failed: {status}",
      "saveFailed": "Save failed",
      "statusUpdateFailedStatus": "Status update failed: {status}",
      "statusUpdateFailed": "Status update failed",
      "deleteFailedStatus": "Delete failed: {status}",
      "deleteFailed": "Delete failed"
    },
    "summary": {
      "options": "{count} {count, plural, =1 {option} other {options}}",
      "optionsAcrossSections": "{rowCount} {rowCount, plural, =1 {option} other {options}} across {sectionCount} {sectionCount, plural, =1 {section} other {sections}}",
      "noFile": "{label} (no file uploaded)",
      "media": "Media",
      "image": "Image",
      "video": "Video",
      "document": "Document",
      "audio": "Audio",
      "hasTag": "has tag {tag}",
      "opContains": "contains",
      "opExists": "exists",
      "opMissing": "missing",
      "modeAdd": "Add",
      "modeRemove": "Remove",
      "tagPicked": "{mode} tag {tag}…",
      "tagNone": "{mode} tag (none picked)"
    },
    "header": {
      "backToFlows": "Back to Flows",
      "namePlaceholder": "Flow name",
      "unsavedHint": "Unsaved changes — hit Save to persist",
      "edited": "Edited",
      "runs": "Runs",
      "delete": "Delete",
      "pause": "Pause",
      "activate": "Activate",
      "fixIssues": "Fix the issues below before activating",
      "save": "Save",
      "descriptionPlaceholder": "Add a short description (internal — customers don't see this)",
      "descriptionLabel": "Flow description"
    }
  },
  "Settings": {
    "pageTitle": "Settings",
    "pageDesc": "Everything in one place — your account and your workspace. Pick a section to manage it.",
    "sectionsNav": "Settings sections",
    "overview": {
      "notSetup": "Not set up yet",
      "connected": "Connected",
      "needsReconnecting": "Needs reconnecting",
      "viewTeamMembers": "View team members",
      "membersCount": "{count} {count, plural, =1 {member} other {members}}",
      "pendingInvites": "{count} pending {count, plural, =1 {invite} other {invites}}",
      "manageTemplates": "Manage message templates",
      "templatesCount": "{count} {count, plural, =1 {template} other {templates}}",
      "pendingReview": "{count} pending review",
      "tagsAndFields": "Tags and custom fields",
      "tagsCount": "{count} {count, plural, =1 {tag} other {tags}}",
      "fieldsCount": "{count} custom {count, plural, =1 {field} other {fields}}",
      "appearance": "{mode} mode · {theme} accent",
      "yourAccount": "Your account",
      "loading": "Loading…"
    },
    "members": {
      "title": "Team members",
      "description": "People with access to this account. Roles control what each teammate can do.",
      "inviteMember": "Invite member",
      "online": "online",
      "away": "away",
      "offline": "offline",
      "memberCount": "{count} {count, plural, =1 {member} other {members}}",
      "you": "You",
      "unnamed": "Unnamed",
      "joined": "Joined {date}",
      "remove": "Remove",
      "removedToast": "Removed {name}",
      "updatedToast": "Updated {name} to {role}",
      "pendingInvitations": "Pending invitations",
      "inviteHint": "The plaintext invite URL is only shown once at creation for security — to re-share, revoke the invite below and create a new one.",
      "noPendingTitle": "No pending invitations.",
      "noPendingDesc": "Click <bold>Invite member</bold> above to generate a shareable link.",
      "untitledInvite": "Untitled invite",
      "created": "Created {date}",
      "expiresInDays": "expires in {days} {days, plural, =1 {day} other {days}}",
      "expiresInHours": "expires in {hours} {hours, plural, =1 {hour} other {hours}}",
      "expired": "expired",
      "revoke": "Revoke",
      "revokedToast": "Invitation revoked",
      "loadFailed": "Failed to load members",
      "loadInvitationsFailed": "Failed to load invitations",
      "updateRoleFailed": "Failed to update role",
      "removeFailed": "Failed to remove member",
      "revokeFailed": "Failed to revoke invitation",
      "networkError": "Could not reach the server",
      "memberAlt": "Member",
      "removeDialogTitle": "Remove member",
      "removeDialogDesc": "Remove <bold>{name}</bold> from the account? They'll be signed out of this account and given a fresh personal account on their next sign-in. Their login isn't deleted.",
      "cancel": "Cancel",
      "removing": "Removing...",
      "removeBtn": "Remove member"
    },
    "invite": {
      "inviteCreated": "Invite created",
      "inviteCreatedDesc": "Share this link with your new teammate. They'll be able to sign up (or sign in) and join the account as <bold>{role}</bold>. The link is valid for <bold>{days} {days, plural, =1 {day} other {days}}</bold>.",
      "inviteLink": "Invite link",
      "copy": "Copy",
      "saveLinkNow": "Save this link now.",
      "saveLinkHint": "We never store the plaintext — once you close this dialog the URL is gone. To re-share, revoke this invite and create a new one.",
      "sendViaWhatsApp": "Send via WhatsApp",
      "done": "Done",
      "dialogTitle": "Invite a teammate",
      "networkError": "Could not reach the server. Try again?",
      "fallbackAccountName": "our wacrm account",
      "dialogDesc": "Generate a one-time invite link. Share it via WhatsApp, Slack, or any channel you like — no email service required.",
      "roleLabel": "Role",
      "validForLabel": "Link valid for",
      "days1": "1 day",
      "days7": "7 days",
      "days30": "30 days",
      "labelTitle": "Label",
      "optional": "(optional)",
      "labelPlaceholder": "e.g. Sara — support team",
      "labelHint": "Helps you remember who you sent the link to in the pending list below.",
      "cancel": "Cancel",
      "creating": "Creating...",
      "generateLink": "Generate link",
      "labelTooLong": "Label must be {max} characters or fewer",
      "copied": "Invite link copied",
      "clipboardBlocked": "Clipboard blocked — copy the link manually",
      "whatsappMessage": "Join {accountName} on wacrm using this link (valid for {expiresInDays} days): {url}",
      "createFailed": "Failed to create invitation"
    },
    "tagsAndFields": {
      "title": "Fields & tags",
      "description": "Two ways to organize contacts: colour-coded tags for quick grouping, and custom fields for structured data.",
      "tagsTitle": "Tags",
      "tagsDesc": "Colour-coded labels for grouping and filtering contacts.",
      "fieldsTitle": "Custom fields",
      "fieldsDesc": "Extra contact fields (e.g. ZIP code, lead source). They appear on every contact and in the “Update Contact Field” automation action.",
      "adminRole": "Admin",
      "failedToLoadTags": "Failed to load tags",
      "nameRequired": "Tag name is required",
      "notAuthenticated": "Not authenticated",
      "tagCreated": "Tag created",
      "failedToCreateTag": "Failed to create tag",
      "tagDeleted": "Tag deleted",
      "failedToDeleteTag": "Failed to delete tag",
      "deleteAria": "Delete {name}",
      "noTags": "No tags yet — create your first one below.",
      "placeholder": "e.g. Newsletter",
      "useColor": "Use {color}",
      "addTag": "Add tag",
      "deleteTag": "Delete tag",
      "deleteConfirm": "Delete the tag \"{name}\"? This removes it from all contacts and cannot be undone.",
      "cancel": "Cancel",
      "deleting": "Deleting...",
      "colors": {
        "red": "Red",
        "orange": "Orange",
        "amber": "Amber",
        "emerald": "Emerald",
        "cyan": "Cyan",
        "blue": "Blue",
        "violet": "Violet",
        "pink": "Pink"
      }
    },
    "templates": {
      "title": "Message templates",
      "description": "Create templates and submit them to Meta for approval. Use \"Sync from Meta\" to pull templates approved elsewhere.",
      "syncFromMeta": "Sync from Meta",
      "qualityScoreTitle": "Meta quality score",
      "headerTextLabel": "Header text",
      "editFailedHttp": "Edit failed (HTTP {status})",
      "submitFailedHttp": "Submit failed (HTTP {status})",
      "syncing": "Syncing…",
      "syncTitle": "Pull approved templates from your Meta WhatsApp Business Account",
      "newTemplate": "New Template",
      "noTemplates": "No templates yet.",
      "createFirst": "Create your first message template to get started.",
      "editTitle": "Editing triggers Meta re-review — status flips to PENDING.",
      "editLabel": "Edit template",
      "edit": "Edit",
      "resubmitTitle": "Edit the template and resubmit to Meta for review.",
      "resubmitLabel": "Edit and resubmit template",
      "resubmit": "Resubmit",
      "deleteMetaLocallyAria": "Delete template from Meta and locally",
      "deleteLocallyAria": "Delete template locally",
      "deleteMetaLocallyTitle": "Delete from Meta and locally",
      "deleteLocallyTitle": "Delete locally",
      "dialogEditTitle": "Edit Message Template",
      "dialogNewTitle": "New Message Template",
      "dialogEditDesc": "Save your changes to re-submit to Meta. Status will flip back to PENDING during review.",
      "dialogNewDesc": "Build a template and submit it to Meta for approval. Once approved, you can use it in broadcasts and the inbox.",
      "authWarning": "AUTHENTICATION templates have a fixed body + OTP button shape that needs a different builder. Create them in Meta WhatsApp Manager for now and use <bold>Sync from Meta</bold> to bring them in.",
      "templateName": "Template Name",
      "namePlaceholder": "e.g. order_confirmation",
      "nameFixed": "Name is fixed once a template exists on Meta — create a new template to change it.",
      "nameHint": "Lowercase letters, digits, and underscores only.",
      "category": "Category",
      "language": "Language",
      "langFixed": "Language is fixed once a template exists on Meta.",
      "langHint": "Must match the exact code on Meta — <code>en_US</code> and <code>en</code> are distinct.",
      "header": "Header",
      "headerNone": "None",
      "headerText": "Text",
      "headerImage": "Image",
      "headerVideo": "Video",
      "headerDocument": "Document",
      "headerTextPlaceholder": "Header text (max 60 chars, optional {{1}})",
      "headerSampleAria": "Sample value for header variable",
      "headerSamplePlaceholder": "Sample value for {{1}} (required for Meta review)",
      "uploadImage": "Upload image",
      "uploadVideo": "Upload video",
      "uploadDocument": "Upload document",
      "uploadHint": "JPEG or PNG, ≤5 MB",
      "uploadHintVideo": "MP4 or 3GPP, ≤16 MB",
      "uploadHintDocument": "PDF, Word, PowerPoint, Excel or text, ≤16 MB",
      "mediaUrlPlaceholder": "https://… (or paste a public {format} link)",
      "imageHint": "Upload a JPEG/PNG (≤5 MB, ≥800×418 px recommended) or paste a public HTTPS link — we upload it to Meta for review automatically.",
      "mediaHint": "Upload a file or paste a public HTTPS link — we upload it to Meta for review automatically.",
      "videoHint": " MP4 or 3GPP, ≤16 MB, ≤60 seconds recommended.",
      "documentHint": " PDF, Word, PowerPoint, Excel or text, ≤100 MB via link (≤16 MB when uploaded here).",
      "bodyText": "Body Text",
      "bodyPlaceholder": "Hello {{1}}, your order {{2}} is confirmed.",
      "bodyHint": "Use {{1}}, {{2}} for variables (must be contiguous starting at {{1}}).",
      "sampleValues": "Sample values (Meta uses these to review your template)",
      "sampleAria": "Sample value for body variable {var}",
      "samplePlaceholder": "Sample for {var}",
      "footer": "Footer (optional)",
      "footerPlaceholder": "Optional footer text (max 60 chars)",
      "buttons": "Buttons (optional)",
      "addButton": "Add Button",
      "buttonsLimit": "Up to {max} buttons. QUICK_REPLY buttons must come before URL / phone / copy-code buttons.",
      "btnQuickReply": "Quick Reply",
      "btnUrl": "URL",
      "btnPhone": "Phone",
      "btnCopyCode": "Copy Code",
      "btnLabelPlaceholder": "Button label",
      "urlPlaceholder": "https://example.com/path or with {{1}} suffix",
      "urlSamplePlaceholder": "Example value for {{1}} (required when URL has a variable)",
      "phonePlaceholder": "+15551234567",
      "codePlaceholder": "Example code (e.g. SUMMER20)",
      "cancel": "Cancel",
      "saving": "Saving…",
      "submitting": "Submitting…",
      "saveResubmit": "Save & Resubmit",
      "submitApproval": "Submit for Approval",
      "deleteDialogTitle": "Delete template?",
      "deleteMetaDesc": "\"{name}\" will be deleted from Meta and from wacrm. Active broadcasts using this template will start failing on their next send. This can't be undone.",
      "deleteLocalDesc": "\"{name}\" will be deleted from wacrm. It was never submitted to Meta, so no remote cleanup is needed.",
      "deleting": "Deleting…",
      "delete": "Delete",
      "toastLoadFailed": "Failed to load templates",
      "toastSubmitFailed": "Failed to submit",
      "toastSubmitEditSuccess": "Edit submitted — Meta typically reviews within 24 hours.",
      "toastSubmitNewSuccess": "Submitted to Meta — typical review time is 24 hours. Status updates automatically.",
      "toastSaveEditDry": "Template updated (dry-run — no Meta call)",
      "toastSaveNewDry": "Template saved (dry-run — no Meta call)",
      "toastSyncCount": "Synced {total} {total, plural, =1 {template} other {templates}} from Meta",
      "toastSyncDetails": " ({inserted} new, {updated} updated)",
      "toastSyncFailed": "Failed to sync: {preview}",
      "toastSyncTruncated": "Synced the first 2000 templates only — your account has more. Sync again to continue, or contact support if this persists.",
      "toastSyncError": "Failed to sync templates",
      "toastDeleteSuccess": "Template deleted",
      "toastDeleteError": "Failed to delete template",
      "toastInvalidImage": "Header image must be a JPEG or PNG.",
      "toastInvalidVideo": "Header video must be an MP4 or 3GPP file.",
      "toastInvalidDocument": "Header document must be a PDF, Word, PowerPoint, Excel or text file.",
      "toastMediaTooLarge": "File is {size} MB — the upload limit is {max} MB.",
      "toastUploadSuccess": "File uploaded.",
      "toastUploadFailed": "Upload failed.",
      "syncFailedHttp": "Sync failed (HTTP {status})",
      "deleteFailedHttp": "Delete failed (HTTP {status})",
      "syncMoreSuffix": ", +{count} more",
      "headerSampleAlt": "Header sample",
      "categoryLabels": {
        "Marketing": "Marketing",
        "Utility": "Utility",
        "Authentication": "Authentication"
      }
    },
    "roles": {
      "admin": "Admin",
      "adminHint": "Manage members + everything",
      "agent": "Agent",
      "agentHint": "Use features; no settings",
      "viewer": "Viewer",
      "viewerHint": "Read-only across the app",
      "owner": "Owner",
      "ownerHint": "Full control over account and billing"
    },
    "whatsapp": {
      "title": "WhatsApp connection",
      "description": "Connect your Meta WhatsApp Business API. Credentials, webhook, and setup steps all live here.",
      "tokenCorrupted": "Stored token can't be decrypted",
      "resetting": "Resetting...",
      "resetConfig": "Reset Configuration",
      "credentialsValid": "Credentials valid",
      "notConnected": "Not Connected",
      "connectedDesc": "Your access token authenticates with Meta. See Registration status below for whether webhooks are actually wired.",
      "notConnectedDesc": "Configure your Meta API credentials below to connect your WhatsApp Business account.",
      "registered": "Registered — Meta will deliver events to wacrm",
      "notRegistered": "Not registered — Meta will not deliver events",
      "verifyWithMeta": "Verify with Meta",
      "subscribedSince": "Subscribed since {date}. Click Verify with Meta if events stop arriving.",
      "unknownDate": "unknown",
      "lastAttemptFailed": "Last attempt failed with: ",
      "retryHint": "Enter (or correct) the 2-step PIN below and click Save Configuration to retry.",
      "noRegistrationHint": "This number was saved before registration tracking existed, or registration was skipped. Enter the 2-step PIN below and click Save Configuration to subscribe it.",
      "diagnosticLastRun": "Diagnostic — last run: ",
      "live": "live",
      "notLive": "not live",
      "apiCredentialsTitle": "API Credentials",
      "apiCredentialsDesc": "Enter your Meta WhatsApp Business API credentials.",
      "phoneNumberId": "Phone Number ID",
      "wabaId": "WhatsApp Business Account ID",
      "accessToken": "Permanent Access Token",
      "accessTokenPlaceholder": "Enter your access token",
      "tokenHidden": "Token is hidden for security. Re-enter it to update configuration.",
      "webhookVerifyToken": "Webhook Verify Token",
      "webhookVerifyTokenPlaceholder": "Create a custom verify token",
      "webhookVerifyTokenHint": "A custom string you create. Must match the token you set in Meta webhook settings.",
      "webhookVerifyTokenSaved": "Saved. Leave as is to keep it, or enter a new value to rotate.",
      "twoStepPin": "Two-step verification PIN",
      "optional": "(optional)",
      "pinPlaceholder": "6-digit PIN from Meta WhatsApp Manager",
      "pinHint": "Needed only to wire inbound messages for a production number. Set it in Meta Business Manager → WhatsApp Accounts → Phone Numbers → Two-step verification, then paste it here so wacrm can subscribe the number — otherwise Meta routes inbound events to whichever app last claimed it (the symptom that hits second numbers under a shared WABA). Meta test numbers have no PIN and are pre-registered — leave this blank for them. Leaving it blank also keeps an existing registration untouched.",
      "webhookTitle": "Webhook Configuration",
      "webhookDesc": "Use this URL as your webhook callback in the Meta App Dashboard.",
      "webhookUrl": "Webhook Callback URL",
      "mediaTitle": "Attachment Storage",
      "mediaDesc": "Meta deletes received media about 30 days after it arrives. Attachments can be copied to your own storage so they stay viewable.",
      "mirrorInbound": "Keep inbound attachments",
      "mirrorInboundDesc": "Save a copy of every photo, video, voice note and document customers send. Uses your Supabase storage; files over 16 MB are skipped.",
      "mirrorInboundOffWarning": "New attachments will stop being copied and will become unavailable about 30 days after they arrive.",
      "mirrorInboundSaveFailed": "Could not update the attachment setting.",
      "loadFailed": "Failed to load WhatsApp configuration",
      "phoneNumberIdRequired": "Phone Number ID is required",
      "accessTokenRequired": "Access Token is required for initial setup",
      "reenterAccessToken": "Please re-enter the Access Token to save changes",
      "saveFailed": "Failed to save configuration",
      "savedButRegistrationFailed": "Saved, but Meta couldn't register the number: {error}",
      "savedRegistrationSkipped": "Credentials saved and verified. Inbound registration was skipped (no PIN) — see Registration status below.",
      "liveWithName": "Live — {name} can now receive events.",
      "connectedGeneric": "WhatsApp connected. Events will start flowing within a minute.",
      "connectedTo": "Connected to {name}",
      "apiConnectionOk": "API connection successful",
      "apiConnectionFailed": "API connection failed",
      "connectionTestFailed": "Connection test failed. Check network and try again.",
      "fullyWired": "Number is fully wired — Meta is delivering events.",
      "notFullyRegistered": "Number is not fully registered. See the checks below for which step failed.",
      "verifyEndpointUnreachable": "Could not reach the verification endpoint.",
      "resetConfirm": "This will delete the current WhatsApp config so you can re-enter it. Continue?",
      "resetFailed": "Failed to reset configuration",
      "resetDone": "Configuration cleared. You can now re-enter your credentials.",
      "webhookCopied": "Webhook URL copied to clipboard",
      "phoneNumberIdPlaceholder": "e.g. 100234567890123",
      "wabaIdPlaceholder": "e.g. 100234567890456",
      "saving": "Saving...",
      "saveConfig": "Save Configuration",
      "testing": "Testing...",
      "testConnection": "Test API Connection",
      "setupInstructions": "Setup Instructions",
      "setupInstructionsDesc": "Follow these steps to connect your WhatsApp Business API.",
      "step1": "Create a Meta App",
      "step1_1": "Go to developers.facebook.com",
      "step1_2": "Click \"My Apps\" and then \"Create App\"",
      "step1_3": "Select \"Business\" as the app type",
      "step1_4": "Fill in app details and create",
      "step2": "Add WhatsApp Product",
      "step2_1": "In your app dashboard, click \"Add Product\"",
      "step2_2": "Find \"WhatsApp\" and click \"Set Up\"",
      "step2_3": "Follow the setup wizard to link your business",
      "step3": "Get API Credentials",
      "step3_1": "Go to WhatsApp > API Setup",
      "step3_2": "Copy your <strong class=\"text-foreground\">Phone Number ID</strong>",
      "step3_3": "Copy your <strong class=\"text-foreground\">WhatsApp Business Account ID</strong>",
      "step3_4": "Generate a <strong class=\"text-foreground\">Permanent Access Token</strong> from Business Settings > System Users",
      "step4": "Configure Webhooks",
      "step4_1": "Go to WhatsApp > Configuration",
      "step4_2": "Click \"Edit\" on the Webhook section",
      "step4_3": "Paste the <strong class=\"text-foreground\">Webhook Callback URL</strong> from above",
      "step4_4": "Enter the same <strong class=\"text-foreground\">Verify Token</strong> you set here",
      "step4_5": "Subscribe to \"messages\" webhook field",
      "metaDocs": "Meta WhatsApp API Documentation",
      "lastSaveFailed": "Last save failed",
      "metaErrorStep": "Step",
      "metaErrorCode": "Meta error code",
      "metaErrorTrace": "Trace ID",
      "metaErrorMessage": "Meta said",
      "metaErrorDetailsHint": "Quote these details when contacting Meta support.",
      "phoneNumberIdNotNumeric": "Phone Number ID must contain only digits. Copy the numeric id from Meta → WhatsApp → API Setup, not the phone number itself.",
      "wabaIdNotNumeric": "WhatsApp Business Account ID must contain only digits. Copy it from Meta → WhatsApp → API Setup.",
      "wabaSubscribed": "The WhatsApp Business Account is subscribed to this app — inbound webhooks can be delivered.",
      "wabaNotSubscribed": "The WhatsApp Business Account is not subscribed to this app, so Meta will not deliver inbound webhooks. Re-enter the access token and save again to subscribe it."
    },
    "sections": {
      "overview": "Overview",
      "profile": "Your profile",
      "security": "Login & security",
      "appearance": "Appearance",
      "whatsapp": "WhatsApp",
      "templates": "Templates",
      "quick-replies": "Quick replies",
      "fields": "Fields & tags",
      "deals": "Deals & currency",
      "members": "Team members",
      "api": "API keys"
    },
    "groups": {
      "account": "Account",
      "workspace": "Workspace"
    },
    "profile": {
      "title": "Your profile",
      "description": "How you show up across the app. Your avatar and name appear in the header, sidebar, and anywhere your teammates see you.",
      "changePhoto": "Change photo",
      "uploadPhoto": "Upload photo",
      "remove": "Remove",
      "photoHint": "PNG, JPG, WebP, or GIF. Up to 2 MB.",
      "unknownError": "Unknown error",
      "displayName": "Display name",
      "email": "Email",
      "emailChangeHint": "Check the inbox for <bold>{oldEmail}</bold> and <bold>{newEmail}</bold> — both need to confirm before the change takes effect.",
      "accountDetails": "Account details",
      "role": "Role",
      "joined": "Joined",
      "userId": "User ID",
      "loading": "Loading your profile…",
      "saving": "Saving…",
      "saveChanges": "Save changes",
      "unsupportedImage": "Unsupported image type",
      "unsupportedImageDesc": "Use PNG, JPG, WebP, or GIF.",
      "imageTooLarge": "Image is too large",
      "imageTooLargeDesc": "Maximum 2 MB.",
      "nameRequired": "Display name is required",
      "invalidEmail": "Enter a valid email address",
      "uploadFailed": "Upload failed: {message}",
      "saveFailed": "Save failed: {message}",
      "profileSaved": "Profile saved",
      "emailChangeFailed": "Email change failed: {message}",
      "profileSavedEmailCheck": "Profile saved — check your email to confirm the address change",
      "passwordTitle": "Password",
      "passwordDesc": "Use at least {min} characters. You will stay signed in on this device after changing it.",
      "currentPassword": "Current password",
      "newPassword": "New password",
      "confirmPassword": "Confirm new password",
      "updating": "Updating…",
      "updatePassword": "Update password",
      "cannotChangeNoEmail": "Cannot change password without a current email",
      "passwordTooShort": "Password must be at least {min} characters",
      "passwordMismatch": "New password and confirmation do not match",
      "currentPasswordIncorrect": "Current password is incorrect",
      "passwordUpdateFailed": "Password update failed: {message}",
      "passwordUpdated": "Password updated",
      "sessionsTitle": "Active sessions",
      "sessionsDesc": "Sign out of every device where you're logged in — including this one. Useful if you lost a laptop or shared your password.",
      "signOutAll": "Sign out of all devices",
      "signOutConfirmTitle": "Sign out everywhere?",
      "signOutConfirmDesc": "Every device logged into this account will be signed out and will need to log in again. You will be redirected to the login page.",
      "cancel": "Cancel",
      "signingOut": "Signing out…",
      "signOutEverywhere": "Sign out everywhere",
      "signOutFailed": "Sign-out failed: {message}",
      "avatarAlt": "Avatar",
      "fullNamePlaceholder": "Ada Lovelace"
    },
    "appearance": {
      "title": "Appearance",
      "description": "Set the mode and accent colour used across the app. Saved to this device — try it, it changes live.",
      "mode": "Mode",
      "colorMode": "Color mode",
      "useMode": "Use {mode} mode",
      "active": "Active",
      "accentColor": "Accent color",
      "useTheme": "Use {name} theme",
      "themeId": "Theme id: {id}"
    },
    "security": {
      "title": "Login & security",
      "description": "Change your password and sign out of your devices. These keep your account safe."
    },
    "browserNotifications": {
      "title": "Browser notifications",
      "description": "Get a desktop alert for every new customer message, even while you're on another page. Saved to this device.",
      "toggleLabel": "Notify me about new customer messages",
      "toggleDesc": "Works only while the app is open in a browser tab.",
      "statusGranted": "Allowed by your browser.",
      "statusDefault": "Turning this on will ask your browser for permission.",
      "statusDenied": "Blocked in browser settings",
      "deniedHint": "Allow notifications for this site in your browser's site settings (usually the lock icon next to the address bar), then reload the page.",
      "unsupported": "This browser doesn't support desktop notifications.",
      "sendTest": "Send test notification",
      "testTitle": "Test notification",
      "testBody": "Notifications are working. New customer messages will show up like this.",
      "permissionDeniedToast": "Your browser blocked notifications",
      "labels": {
        "fallbackTitle": "New message",
        "image": "📷 Photo",
        "audio": "🎤 Voice message",
        "video": "🎬 Video",
        "document": "📄 Document",
        "location": "📍 Location",
        "template": "📋 Template"
      }
    },
    "apiKeys": {
      "title": "API keys",
      "description": "Keys authenticate the public REST API (<apiCode>/api/v1</apiCode>) so you can build your own automations. Send them as <headerCode>Authorization: Bearer &lt;key&gt;</headerCode>.",
      "newApiKey": "New API key",
      "noApiKeys": "No API keys yet.",
      "createOneHint": "Click <bold>New API key</bold> to create one.",
      "askAdminHint": "Ask an admin to create one.",
      "revoked": "Revoked",
      "expired": "Expired",
      "noScopes": "No scopes",
      "created": "Created {date}",
      "lastUsed": "last used {date}",
      "neverUsed": "never used",
      "expires": "expires {date}",
      "revoke": "Revoke",
      "revokeSuccess": "Revoked \"{name}\"",
      "revokeFailed": "Failed to revoke key",
      "loadFailed": "Failed to load API keys",
      "createError": "Failed to create key",
      "nameRequired": "Give the key a name",
      "nameLabel": "Name",
      "namePlaceholder": "e.g. Zapier automation",
      "scopesLabel": "Scopes",
      "scopesHint": "A key with no scopes can still call <code>GET /api/v1/me</code> to verify it works.",
      "cancel": "Cancel",
      "creating": "Creating…",
      "createKey": "Create key",
      "copyTitle": "Copy your API key",
      "copyDesc": "This is the only time the full key is shown. Store it somewhere safe — if you lose it, revoke it and create a new one.",
      "apiKeyLabel": "API key",
      "copy": "Copy",
      "copySuccess": "API key copied",
      "copyFailed": "Copy failed — select and copy manually",
      "newKeyTitle": "New API key",
      "newKeyDesc": "Name it after the integration that will use it, and grant only the scopes it needs.",
      "done": "Done",
      "networkError": "Could not reach the server"
    },
    "deals": {
      "title": "Deals & currency",
      "description": "The currency used for new deals and for pipeline and dashboard totals.",
      "defaultCurrency": "Default currency",
      "defaultCurrencyDesc": "New deals default to this currency, and pipeline and dashboard totals are shown in it. Existing deals keep the currency they were saved with.",
      "currencyLabel": "Currency",
      "adminOnlyHint": "Only account admins can change the default currency.",
      "save": "Save",
      "saving": "Saving...",
      "saveFailed": "Failed to save default currency",
      "saveSuccess": "Default currency updated"
    },
    "aiConfig": {
      "title": "Agent setup",
      "description": "Bring your own OpenAI, Anthropic, or OpenAI-compatible API key. wacrm calls the provider directly with your key — no per-seat AI fees, and your data stays yours. This powers AI-drafted replies in the inbox, the auto-reply bot, and the Playground.",
      "adminOnlyConfig": "Only admins and owners can change the AI configuration.",
      "loadFailed": "Failed to load AI configuration",
      "providerAndKey": "Provider & key",
      "encryptionNotice": "Your key is encrypted at rest (AES-256-GCM) and never shown again after saving.",
      "provider": "Provider",
      "model": "Model",
      "apiKey": "API key",
      "testKey": "Test key",
      "testSuccess": "Key works — the provider responded.",
      "testRejected": "The provider rejected the request.",
      "testNetworkError": "Could not reach the provider.",
      "embeddingsKey": "Embeddings key",
      "optionalSemanticSearch": "(optional — enables semantic knowledge-base search)",
      "embeddingsHint": "An OpenAI key used only to embed your knowledge base (text-embedding-3-small){sameKeyText}. Leave blank to use keyword search instead. Clear it to turn semantic search off.",
      "sameKeyText": " — can be the same key as above",
      "behaviour": "Behaviour",
      "behaviourDesc": "Tell the assistant about your business — products, tone, what it may and may not promise. This context feeds both drafts and auto-replies.",
      "businessContext": "Business context & instructions",
      "promptPlaceholder": "e.g. We are Acme, a coffee-equipment store. Be warm and concise. Never quote prices or delivery dates — hand off to a human for those.",
      "enableAssistant": "Enable AI assistant",
      "enableAssistantDesc": "Master switch. Turns on the “Draft with AI” button in the inbox.",
      "autoReply": "Auto-reply to inbound messages",
      "autoReplyDesc": "The bot answers new inbound messages automatically (only when no flow handles them and no agent is assigned). Hands off to a human when it can’t help.",
      "maxAutoReplies": "Max auto-replies per conversation",
      "maxAutoRepliesDesc": "After this many bot replies in one thread, the bot goes quiet.",
      "handoffTo": "Hand off to",
      "handoffToDesc": "When the bot can’t help — or hits the reply cap — it pauses and routes the chat here, with a short note on what happened.",
      "handoffQueue": "Unassigned queue (any agent can pick it up)",
      "remove": "Remove",
      "save": "Save",
      "missingModel": "Enter a model name.",
      "missingApiKey": "Enter your API key.",
      "saveSuccess": "AI assistant saved.",
      "saveFailed": "Failed to save.",
      "removeSuccess": "AI configuration removed.",
      "removeFailed": "Failed to remove.",
      "providerOpenAiCompatible": "OpenAI-compatible API",
      "baseUrl": "Base URL",
      "baseUrlHint": "Base URL for the OpenAI-compatible API, for example https://api.groq.com/openai/v1. /chat/completions is added automatically unless you include that path yourself.",
      "missingBaseUrl": "Enter the Base URL for the OpenAI-compatible API."
    },
    "aiKnowledge": {
      "loadFailed": "Failed to load knowledge base",
      "openFailed": "Failed to open document",
      "titleContentRequired": "Title and content are required.",
      "saveSuccessNew": "Document added.",
      "saveSuccessUpdate": "Document updated.",
      "saveFailed": "Failed to save.",
      "removeSuccess": "Document removed.",
      "removeFailed": "Failed to remove.",
      "reindexSuccess": "Reindexed {count} document(s).",
      "reindexFailed": "Reindex failed.",
      "title": "Knowledge base",
      "description": "Add FAQs, policies, or product details. The assistant retrieves the relevant pieces when drafting and auto-replying, so it can answer instead of handing off.{searchType}",
      "semanticSearchOn": " Semantic search is on (embeddings key set).",
      "keywordSearchOn": " Using keyword search — add an embeddings key above for semantic search.",
      "noDocs": "No documents yet.",
      "editDocTitle": "Title",
      "editDocTitlePlaceholder": "e.g. Returns & refunds policy",
      "editDocContent": "Content",
      "editDocContentPlaceholder": "Paste the FAQ answer, policy text, or product details…",
      "cancel": "Cancel",
      "saveDoc": "Save document",
      "addDoc": "Add document",
      "reindex": "Reindex",
      "reindexTooltip": "Re-embed all documents (e.g. after adding an embeddings key)",
      "editDoc": "Edit",
      "deleteDoc": "Delete",
      "loading": "Loading…"
    },
    "quickReplies": {
      "nameRequired": "Give the quick reply a name.",
      "saveError": "Couldn't save the quick reply.",
      "updated": "Quick reply updated.",
      "created": "Quick reply created.",
      "deleteConfirm": "Delete this quick reply?",
      "deleteError": "Couldn't delete the quick reply.",
      "title": "Quick replies",
      "description": "Reusable snippets — plain text or a saved interactive message — that agents can insert from the inbox composer.",
      "new": "New quick reply",
      "edit": "Edit quick reply",
      "empty": "No quick replies yet. Create one to reuse it across conversations.",
      "nameLabel": "Name",
      "namePlaceholder": "e.g. Business hours",
      "kindText": "Text",
      "kindInteractive": "Interactive",
      "textPlaceholder": "The message text to insert",
      "cancel": "Cancel",
      "save": "Save"
    }
  },
  "SignupPage": {
    "passwordsMismatch": "Passwords do not match",
    "passwordTooShort": "Password must be at least 6 characters",
    "checkEmailTitle": "Check your email",
    "checkEmailDesc": "We've sent a confirmation link to <strong>{email}</strong>. Please check your inbox and click the link to verify your account.",
    "backToSignIn": "Back to sign in",
    "titleJoin": "Create account & join",
    "title": "Create account",
    "descJoin": "Verify your email, then accept the invitation to join your team.",
    "desc": "Get started with CRM Template for WhatsApp",
    "fullNameLabel": "Full name",
    "fullNamePlaceholder": "John Doe",
    "emailLabel": "Email",
    "emailPlaceholder": "you@example.com",
    "passwordLabel": "Password",
    "passwordPlaceholder": "At least 6 characters",
    "confirmPasswordLabel": "Confirm password",
    "confirmPasswordPlaceholder": "Repeat your password",
    "creating": "Creating account...",
    "submit": "Create account",
    "haveAccount": "Already have an account?",
    "signIn": "Sign in"
  },
  "ForgotPasswordPage": {
    "checkEmailTitle": "Check your email",
    "checkEmailDesc": "We've sent a password reset link to <strong>{email}</strong>. Please check your inbox.",
    "backToSignIn": "Back to sign in",
    "title": "Reset password",
    "desc": "Enter your email and we'll send you a reset link",
    "emailLabel": "Email",
    "emailPlaceholder": "you@example.com",
    "sending": "Sending...",
    "sendLink": "Send reset link"
  },
  "ResetPasswordPage": {
    "title": "Choose a new password",
    "desc": "Enter a new password for your account.",
    "passwordLabel": "New password",
    "passwordPlaceholder": "At least 6 characters",
    "confirmPasswordLabel": "Confirm new password",
    "confirmPasswordPlaceholder": "Repeat your new password",
    "submit": "Update password",
    "saving": "Updating...",
    "passwordsMismatch": "Passwords do not match",
    "passwordTooShort": "Password must be at least 6 characters",
    "checking": "Checking your link...",
    "expiredTitle": "This link is no longer valid",
    "expiredDesc": "Password reset links work once and expire after a short while. Request a new one and open it in the same browser you requested it from.",
    "requestNewLink": "Request a new link",
    "backToSignIn": "Back to sign in",
    "successTitle": "Password updated",
    "successDesc": "You’re signed in with your new password.",
    "continueToDashboard": "Continue to dashboard"
  },
  "JoinPage": {
    "fail": {
      "notFoundTitle": "Invite not found",
      "notFoundBody": "This link doesn't match a valid invitation. Double-check the URL or ask the person who invited you to send a new one.",
      "usedTitle": "Invite already used",
      "usedBody": "This invitation has already been accepted. If that wasn't you, ask the account admin to send a fresh link.",
      "expiredTitle": "Invite expired",
      "expiredBody": "This invitation has expired. Ask the account admin to send a new one — they take a few seconds to generate.",
      "serverErrorTitle": "Something went wrong",
      "serverErrorBody": "We couldn't verify this invitation right now. Try refreshing the page in a moment."
    },
    "conflictDefault": "You are already in another account. Sign in with a different email to join this one.",
    "acceptFailed": "Failed to accept invitation",
    "welcome": "Welcome to the team",
    "serverUnreachable": "Could not reach the server",
    "signOutFailed": "Could not sign out. Try refreshing the page.",
    "verifying": "Verifying invitation…",
    "tryAgain": "Try again",
    "createNewAccount": "Create a new account instead",
    "signIn": "Sign in",
    "invitedTo": "You're invited to <account>{name}</account>",
    "joinAs": "You'll join as <badge>{role}</badge>. Link valid until {date}.",
    "accepting": "Accepting…",
    "acceptInvitation": "Accept invitation",
    "acceptNote": "Accepting moves your login into {name}. Your empty personal account from signup will be cleaned up.",
    "conflictTitle": "Can't join {name} with this account",
    "conflictBody": "To join <account>{name}</account>, sign out and sign up again with a different email address. The invite link stays valid as long as it hasn't expired.",
    "staySignedIn": "Stay signed in",
    "signingOut": "Signing out…",
    "signOutSwitch": "Sign out & use a different email",
    "createAndJoin": "Create account & join",
    "haveAccount": "I already have an account"
  },
  "Notifications": {
    "title": "Notifications",
    "description": "Conversations other teammates assign to you show up here.",
    "markAllRead": "Mark all as read",
    "markReadFailed": "Failed to mark notification as read",
    "markAllFailed": "Failed to mark all as read",
    "retry": "Retry",
    "emptyTitle": "No notifications yet",
    "emptyDesc": "You'll see an alert here when someone assigns you a conversation.",
    "unread": "Unread"
  },
  "Agents": {
    "title": "AI Agents",
    "description": "Your bring-your-own-key AI agent — set it up, then test it in the playground before it replies to customers in the inbox.",
    "tabPlayground": "Playground",
    "tabSetup": "Setup",
    "tabUsage": "Usage",
    "playground": {
      "title": "Playground",
      "subtitle": "— test replies as if you were a customer",
      "reset": "Reset",
      "emptyTitle": "Send a message to see how your agent would reply.",
      "emptyDesc": "It uses your knowledge base and behaves exactly like the auto-reply bot — including handoff.",
      "goToSetup": "Not set up yet? Go to Setup",
      "handoff": "Would hand off to a human here",
      "thinking": "Thinking…",
      "placeholder": "Type a customer message…",
      "notConfigured": "No agent configured yet — finish Setup first.",
      "noReply": "Couldn't get a reply.",
      "unreachable": "Couldn't reach the agent."
    },
    "usage": {
      "title": "Token usage",
      "description": "Tokens spent on your provider key by drafts and the auto-reply bot. Counts only — no message content is stored here.",
      "window": "Last {days} days",
      "loadFailed": "Failed to load usage",
      "empty": "No AI usage in the last {days} days yet.",
      "emptyHint": "This fills in as the assistant drafts and auto-replies.",
      "totalTokens": "Total tokens",
      "llmCalls": "LLM calls",
      "autoReply": "Auto-reply",
      "drafts": "Drafts",
      "tokens": "Tokens",
      "tokensPerDay": "Tokens per day",
      "byModel": "By model",
      "modelCalls": "{tokens} tok · {count, plural, =1 {# call} other {# calls}}",
      "partialWindow": "Showing a partial window — usage is high enough that only the most recent records are summarized here."
    }
  },
  "Interactive": {
    "replyButtons": "Reply buttons",
    "list": "List",
    "body": "Body",
    "bodyPlaceholder": "What the customer reads above the options",
    "header": "Header (optional)",
    "footer": "Footer (optional)",
    "showIds": "Show reply IDs (advanced)",
    "preview": "Preview",
    "previewBody": "Message body…",
    "previewButton": "Button",
    "previewMenu": "Menu",
    "buttonsCount": "Buttons ({count}/{max})",
    "idPlaceholder": "id",
    "buttonLabelPlaceholder": "Button label",
    "addButton": "Add button",
    "listButtonLabel": "List button label",
    "rowsCount": "Rows ({count}/{max})",
    "sectionTitlePlaceholder": "Section title (optional)",
    "rowTitlePlaceholder": "Row title",
    "rowDescriptionPlaceholder": "Description (optional)",
    "addRow": "Add row",
    "addSection": "Add section",
    "defaultListButton": "Menu"
  },
  "DashboardShell": {
    "loading": "Loading..."
  },
  "UiPrimitives": {
    "close": "Close"
  },
  "GatedButton": {
    "readOnly": "Read-only — your role can't {action}",
    "reasons": {
      "createAutomations": "create automations",
      "createBroadcasts": "create broadcasts",
      "addOrImportContacts": "add or import contacts",
      "deleteContacts": "delete contacts",
      "createFlows": "create flows",
      "createPipelines": "create pipelines",
      "createDeals": "create deals",
      "sendMessages": "send messages"
    }
  },
  "Metadata": {
    "description": "Self-hostable CRM template for WhatsApp."
  },
  "Currency": {
    "USD": "US Dollar",
    "EUR": "Euro",
    "GBP": "British Pound",
    "INR": "Indian Rupee",
    "AUD": "Australian Dollar",
    "CAD": "Canadian Dollar",
    "BRL": "Brazilian Real",
    "JPY": "Japanese Yen",
    "CNY": "Chinese Yuan",
    "AED": "UAE Dirham",
    "ZAR": "South African Rand",
    "NGN": "Nigerian Naira",
    "SGD": "Singapore Dollar",
    "MXN": "Mexican Peso",
    "COP": "Colombian Peso"
  },
  "TemplateStatus": {
    "DRAFT": "Draft",
    "PENDING": "Pending",
    "APPROVED": "Approved",
    "REJECTED": "Rejected",
    "PAUSED": "Paused",
    "DISABLED": "Disabled",
    "IN_APPEAL": "In Appeal",
    "PENDING_DELETION": "Pending Deletion"
  },
  "StarterAutomations": {
    "welcome_message": {
      "name": "Welcome Message",
      "description": "Auto-reply to first-time contacts with a greeting.",
      "text": "Hi! 👋 Thanks for reaching out. We'll get back to you shortly."
    },
    "out_of_office": {
      "name": "Out of Office",
      "description": "Auto-reply during off-hours so nobody is left waiting.",
      "text": "Thanks for your message! Our team is offline right now (9am–6pm) and will reply first thing tomorrow."
    },
    "lead_qualifier": {
      "name": "Lead Qualifier",
      "description": "Ask qualification questions to filter inbound leads.",
      "keywords": "pricing,quote,buy",
      "text": "Great — happy to help with pricing! Quick question: roughly how many seats are you looking for?"
    },
    "follow_up_reminder": {
      "name": "Follow-up Reminder",
      "description": "Send a nudge if a contact has not replied within 24 hours.",
      "text": "Just circling back — did you have any other questions for us? Happy to help!"
    }
  },
  "StarterFlows": {
    "welcome_menu": {
      "name": "Welcome menu",
      "description": "Greet customers who type a keyword and route them to the right agent based on whether they're new or existing.",
      "keywords": "support,help,hi",
      "text": "Hi! 👋 Welcome to support. Are you an existing customer or new here?",
      "footer": "Tap a button below to continue.",
      "existingButton": "Existing customer",
      "newButton": "New customer",
      "existingNote": "Existing customer needs assistance — please check account history before replying.",
      "newNote": "New customer — share pricing + onboarding link."
    },
    "faq_bot": {
      "name": "FAQ bot",
      "description": "Answer common questions automatically. Customer picks a topic from a list; the bot replies with the answer and ends.",
      "keywords": "faq,question,info",
      "text": "What can I help you with?",
      "buttonLabel": "View topics",
      "commonSection": "Common questions",
      "hoursRow": "Opening hours",
      "pricingRow": "Pricing",
      "refundsRow": "Refund policy",
      "otherSection": "Other",
      "humanRow": "Talk to a human",
      "hoursAnswer": "We're open Mon–Fri, 9am–6pm local time. Weekend support is limited to urgent issues.",
      "pricingAnswer": "Our pricing starts at $9/mo. Visit https://example.com/pricing for the full breakdown.",
      "refundsAnswer": "Refunds are honored within 30 days of purchase. Reply with your order number and we'll process it.",
      "humanNote": "Customer asked to talk to a human from the FAQ bot."
    },
    "lead_capture": {
      "name": "Lead capture",
      "description": "Greet first-time inbounds, capture name + email + company, then hand off to sales with the answers in the note.",
      "intro": "Welcome! 👋 I'll ask a few quick questions so we can get you to the right person.",
      "askName": "What's your name?",
      "askEmail": "Thanks {name}! What's your work email?",
      "askCompany": "Almost done — what's your company name?",
      "handoffNote": "New lead — name={name}, email={email}, company={company}."
    }
  },
  "LibErrors": {
    "upload": {
      "notSignedIn": "Not signed in.",
      "accountUnresolved": "Could not resolve your account."
    },
    "media": {
      "noAttachment": "This message has no attachment."
    },
    "ai": {
      "timeout": "The AI provider took too long to respond.",
      "unreachable": "Could not reach the AI provider: {message}",
      "emptyResponse": "{provider} returned an empty response.",
      "compatBaseUrlRequired": "OpenAI-compatible API base URL is required.",
      "compatBaseUrlInvalid": "OpenAI-compatible API base URL must be a valid URL.",
      "compatBaseUrlProtocol": "OpenAI-compatible API base URL must use http:// or https://.",
      "compatBaseUrlHttpsRequired": "OpenAI-compatible API base URL must use https:// unless its host is listed in {envVar}.",
      "compatBaseUrlCredentials": "OpenAI-compatible API base URL must not contain embedded credentials.",
      "compatBaseUrlQuery": "OpenAI-compatible API base URL must not contain a query string or fragment.",
      "compatBlockedUrl": "OpenAI-compatible provider URL is blocked by the server outbound URL policy. For an operator-approved private host, add it to {envVar}.",
      "invalidKey": "{provider} rejected the API key",
      "rateLimited": "{provider} rate limit reached",
      "apiError": "{provider} API error ({status})",
      "embeddingsMalformed": "Embeddings response was malformed.",
      "embeddingsMissingIndices": "Embeddings response was missing result indices.",
      "embeddingsMissingVector": "Embeddings response missing a vector."
    },
    "tags": {
      "verifyFailed": "Could not verify contact tag ownership",
      "contactNotFound": "Contact not found",
      "tagNotFound": "Tag not found",
      "addFailed": "Failed to add contact tag: {message}",
      "removeFailed": "Failed to remove contact tag: {message}"
    },
    "auth": {
      "unauthorized": "Unauthorized",
      "forbidden": "Forbidden",
      "internal": "Internal server error",
      "loadContext": "Could not load account context",
      "notLinked": "Profile is not linked to an account",
      "requiresRole": "This action requires the ''{min}'' role or higher",
      "roleNames": {
        "owner": "owner",
        "admin": "admin",
        "agent": "agent",
        "viewer": "viewer"
      }
    },
    "rateLimitExceeded": "Rate limit exceeded",
    "send": {
      "contactNotFound": "contact not found for this account",
      "noWhatsAppAddress": "contact has no usable WhatsApp address (phone: {phone})",
      "none": "none",
      "notConfigured": "WhatsApp not configured for this account",
      "dbInsertFailed": "sent to Meta but DB insert failed: {message}",
      "conversationLookupFailed": "conversation lookup failed: {message}",
      "conversationNotFound": "conversation not found for this account"
    },
    "engine": {
      "needsContact": "{step} needs a contact",
      "emptyText": "send_message has empty text",
      "needsTemplateName": "send_template needs template_name",
      "needsContactAndTag": "{step} needs contact + tag_id",
      "needsPipelineStage": "create_deal needs pipeline + stage",
      "needsUrl": "send_webhook needs url",
      "pausedWhileWaitingForReply": "automation paused while waiting for reply",
      "noReplyWithin24h": "no reply within 24h",
      "parkForReplyFailed": "could not park for reply: {message}",
      "destinationNotAllowed": "send_webhook: destination not allowed",
      "webhookStatus": "webhook returned {status}",
      "conversationNotInAccount": "conversation does not belong to this account",
      "noContactForConversation": "cannot resolve conversation: no contact",
      "noConversation": "cannot send: contact has no existing conversation",
      "tagAddedNoConversation": "tag_added automation cannot send: contact has no existing conversation"
    }
  },
  "Validation": {
    "flows": {
      "nameRequired": "Flow name is required.",
      "entryRequired": "Pick an entry node before activating.",
      "needsNode": "A flow needs at least one node before activation.",
      "entryMissing": "Entry node \"{id}\" doesn't exist.",
      "duplicateNodeKey": "Duplicate node_key \"{key}\".",
      "unreachable": "Node \"{key}\" is unreachable from the entry node.",
      "keywordsRequired": "Keyword triggers need at least one keyword.",
      "blankKeywords": "{count} {count, plural, =1 {keyword is} other {keywords are}} blank — they won't match anything.",
      "startNeedsNext": "Start node must point to a next node.",
      "startMissingNext": "Start points to non-existent node \"{key}\".",
      "sendMessageNeedsText": "Send-message node needs a text body.",
      "sendMessageNeedsNext": "Send-message node must point to a next node.",
      "sendMessageMissingNext": "Send-message points to non-existent node \"{key}\".",
      "sendMediaNeedsType": "Send-media node needs a media type (image, video, or document).",
      "sendMediaNeedsFile": "Send-media node needs a file (upload one before activating).",
      "captionTooLong": "Caption exceeds {max} chars (WhatsApp limit).",
      "sendMediaNeedsNext": "Send-media node must point to a next node.",
      "sendMediaMissingNext": "Send-media points to non-existent node \"{key}\".",
      "sendButtonsNeedsText": "Send-buttons node needs a text body.",
      "sendButtonsNeedsButton": "Send-buttons needs at least one button.",
      "tooManyButtons": "WhatsApp allows at most {max} buttons per message.",
      "buttonNeedsReplyId": "Button {n} needs a reply id.",
      "duplicateButtonReplyId": "Duplicate button reply id \"{id}\".",
      "buttonNeedsTitle": "Button {n} needs a title.",
      "buttonTitleTooLong": "Button {n} title is over {max} chars (WhatsApp limit).",
      "buttonNeedsNext": "Button {n} needs a next node.",
      "buttonMissingNext": "Button {n} points to non-existent node \"{key}\".",
      "sendListNeedsText": "Send-list node needs a text body.",
      "sendListNeedsLabel": "Send-list needs a button label (the tap-to-expand text).",
      "sendListNeedsRow": "Send-list needs at least one row.",
      "tooManyRows": "Send-list allows at most {max} rows total across sections.",
      "rowNeedsReplyId": "Row {row} in section {section} needs a reply id.",
      "duplicateRowId": "Duplicate list row id \"{id}\".",
      "rowNeedsTitle": "Row {n} needs a title.",
      "rowTitleTooLong": "Row {n} title exceeds {max} chars.",
      "rowDescriptionTooLong": "Row {n} description exceeds {max} chars.",
      "rowNeedsNext": "Row {n} needs a next node.",
      "rowMissingNext": "Row {n} points to non-existent node \"{key}\".",
      "collectNeedsPrompt": "Collect-input needs a prompt to send the customer.",
      "collectNeedsVarKey": "Collect-input needs a var_key to store the answer under.",
      "invalidVarKey": "var_key \"{key}\" must be alphanumeric+underscore and start with a letter or underscore.",
      "collectNeedsNext": "Collect-input must point to a next node.",
      "collectMissingNext": "Collect-input points to non-existent node \"{key}\".",
      "conditionNeedsSubject": "Condition needs a subject (var / tag / contact_field).",
      "conditionNeedsSubjectKey": "Condition needs a subject_key (var name, tag id, or field name).",
      "conditionNeedsOperator": "Condition needs an operator.",
      "operatorNeedsValue": "Operator \"{operator}\" usually expects a comparison value — empty value will only match empty subjects.",
      "conditionNeedsBranch": "Condition needs a node for the \"{branch}\" branch.",
      "conditionMissingBranch": "Condition's \"{branch}\" points to non-existent node \"{key}\".",
      "setTagNeedsMode": "Set-tag needs a mode (add or remove).",
      "setTagNeedsTag": "Set-tag needs a tag to apply.",
      "setTagNeedsNext": "Set-tag must point to a next node.",
      "setTagMissingNext": "Set-tag points to non-existent node \"{key}\".",
      "unknownNodeType": "Unknown node type \"{type}\"."
    },
    "automations": {
      "needsStep": "active automations need at least one step",
      "messageTextRequired": "message text is required",
      "templateNameRequired": "template name is required",
      "tagRequired": "tag is required",
      "agentRequired": "agent is required when mode is \"specific\"",
      "fieldNameRequired": "field name is required",
      "fieldValueRequired": "field value is required",
      "pipelineRequired": "pipeline is required",
      "stageRequired": "stage is required",
      "titleRequired": "title is required",
      "waitAmountInvalid": "wait amount must be greater than 0",
      "waitUnitInvalid": "wait unit must be minutes, hours, or days",
      "conditionSubjectRequired": "condition subject is required",
      "conditionOperandRequired": "condition operand is required",
      "webhookUrlRequired": "webhook URL is required",
      "webhookUrlScheme": "webhook URL must use http or https",
      "webhookUrlInvalid": "webhook URL is not a valid URL",
      "unknownStepType": "unknown step type: {type}",
      "keywordRequired": "at least one keyword is required",
      "keywordsEmpty": "keywords cannot be empty strings",
      "matchTypeInvalid": "match type must be \"exact\", \"contains\" or \"word\"",
      "scheduleRequired": "schedule is required",
      "replyIdRequired": "at least one reply id is required",
      "replyIdsEmpty": "reply ids cannot be empty strings"
    },
    "templates": {
      "nameRequired": "Template name is required.",
      "nameInvalid": "Template name must use only lowercase letters, digits, and underscores (1-512 chars).",
      "bodyNotContiguous": "Body variables must be contiguous starting at {first} — found {found}.",
      "bodyRequired": "Body text is required.",
      "bodyTooLong": "Body text exceeds {max} chars (got {got}).",
      "footerTooLong": "Footer text exceeds {max} chars (got {got}).",
      "footerNoVariables": "Footer text cannot contain {placeholder} variables (Meta rule).",
      "headerTextRequired": "Text header requires header_content.",
      "headerTextTooLong": "Header text exceeds {max} chars (got {got}).",
      "headerTooManyVariables": "Text header supports at most one variable — found {count} (Meta rule).",
      "headerVariableMustBeFirst": "Text header variable must be {var} (Meta rule).",
      "mediaHeaderRequiresSource": "{type} header requires either a public sample URL (header_media_url) or a Resumable Upload handle (header_handle).",
      "headerMediaUrlScheme": "header_media_url must use http(s) scheme.",
      "headerMediaUrlInvalid": "header_media_url must be a valid URL.",
      "tooManyButtons": "Templates can have at most {max} buttons (got {got}).",
      "tooManyUrlButtons": "At most {max} URL buttons allowed (got {got}).",
      "tooManyPhoneButtons": "At most {max} PHONE_NUMBER button allowed (got {got}).",
      "tooManyCopyCodeButtons": "At most {max} COPY_CODE button allowed (got {got}).",
      "quickReplyInterleaved": "QUICK_REPLY buttons cannot be interleaved with URL / PHONE_NUMBER / COPY_CODE buttons — group them at the start.",
      "buttonMissingText": "Button #{n} ({type}) is missing text.",
      "buttonTextTooLong": "Button #{n} text exceeds {max} chars.",
      "urlButtonMissingUrl": "URL button #{n} is missing url.",
      "urlButtonInvalidUrl": "URL button #{n} has an invalid url.",
      "urlButtonTooManyVariables": "URL button #{n} can have at most one variable (Meta rule).",
      "urlButtonVariableMustBeFirst": "URL button #{n} variable must be {var} (Meta rule).",
      "urlButtonNeedsExample": "URL button #{n} uses {var} — Meta requires an example value.",
      "phoneButtonMissingNumber": "PHONE_NUMBER button #{n} is missing phone_number.",
      "copyCodeButtonMissingExample": "COPY_CODE button #{n} is missing example value.",
      "bodySampleCountMismatch": "Body has {count} variable(s) — supply exactly {count} sample value(s) (got {got}).",
      "headerSampleCountMismatch": "Header has {count} variable(s) — supply exactly {count} sample value(s) (got {got}).",
      "bodySampleEmpty": "Body sample value #{n} is empty.",
      "headerSampleEmpty": "Header sample value #{n} is empty.",
      "languageRequired": "Language is required.",
      "metaAppIdRequired": "Media-header templates need META_APP_ID set (used for Meta’s Resumable Upload). Add it to your environment, or remove the media header.",
      "headerUrlUnreachable": "Could not fetch the header media URL. Make sure it is publicly reachable.",
      "headerUrlStatus": "Header {kind} URL returned {status}. It must be publicly reachable.",
      "headerWrongType": "Header {kind} must be {formats} (got {contentType}).",
      "headerEmpty": "Header {kind} is empty.",
      "headerTooLarge": "Header {kind} is {size} MB — Meta's limit is {max} MB.",
      "headerTextValueRequired": "Header text variable {var} requires a value — pass headerText.",
      "mediaHeaderSendSource": "{type} header requires a media link or id at send time — set header_media_url on the template or pass headerMediaUrl/headerMediaId.",
      "bodyValuesMissing": "Body has {count} variable(s) but only {got} value(s) were supplied.",
      "urlButtonParamRequired": "URL button #{n} uses {var} — requires a buttonParams[{index}] value."
    },
    "interactive": {
      "buttonCount": "Interactive button message requires 1-{max} buttons (got {got}).",
      "buttonMissingId": "Interactive button missing id.",
      "duplicateButtonId": "Interactive message has duplicate button id \"{id}\".",
      "buttonMissingTitle": "Interactive button \"{id}\" missing title.",
      "buttonTitleTooLong": "Interactive button title \"{title}\" exceeds {max} chars.",
      "listRequiresButtonLabel": "Interactive list requires a buttonLabel.",
      "listButtonLabelTooLong": "Interactive list buttonLabel \"{label}\" exceeds {max} chars.",
      "listSectionCount": "Interactive list requires 1-{max} sections (got {got}).",
      "listRowCount": "Interactive list requires 1-{max} rows total across all sections (got {got}).",
      "listRowMissingId": "Interactive list row missing id.",
      "duplicateRowId": "Interactive list has duplicate row id \"{id}\".",
      "listRowMissingTitle": "Interactive list row \"{id}\" missing title.",
      "listRowTitleTooLong": "Interactive list row title \"{title}\" exceeds {max} chars.",
      "listRowDescriptionTooLong": "Interactive list row description for \"{id}\" exceeds {max} chars.",
      "bodyRequired": "Interactive message requires bodyText.",
      "bodyTooLong": "Interactive bodyText exceeds {max} chars.",
      "headerTooLong": "Interactive headerText exceeds {max} chars.",
      "footerTooLong": "Interactive footerText exceeds {max} chars."
    }
  },
  "Api": {
    "common": {
      "notFound": "Not found",
      "invalidJson": "Invalid JSON",
      "unauthorized": "Unauthorized",
      "internalServerError": "Internal server error",
      "profileNotLinked": "Your profile is not linked to an account.",
      "conversationNotFound": "Conversation not found",
      "failedToLoadConversation": "Failed to load conversation",
      "whatsappNotConfigured": "WhatsApp not configured",
      "whatsappNotConfiguredDot": "WhatsApp not configured.",
      "whatsappNotConfiguredSetup": "WhatsApp not configured. Please set up your WhatsApp integration first.",
      "whatsappNotConfiguredConnect": "WhatsApp not configured. Connect your WhatsApp Business account in Settings first.",
      "wabaIdMissing": "WABA (WhatsApp Business Account) ID missing. Re-connect your account in Settings.",
      "unknownError": "Unknown error",
      "invalidRequestBody": "Invalid request body",
      "titleEmpty": "title cannot be empty",
      "insertFailed": "insert failed"
    },
    "account": {
      "apiKeys": {
        "revokeFailed": "Failed to revoke API key",
        "notFoundOrRevoked": "API key not found or already revoked",
        "loadFailed": "Failed to load API keys",
        "nameRequired": "'name' is required",
        "nameTooLong": "Name must be {max} characters or fewer",
        "scopesInvalid": "'scopes' must be an array of known scope strings",
        "createFailed": "Failed to create API key"
      },
      "invitations": {
        "revokeFailed": "Failed to revoke invitation",
        "notFound": "Invitation not found",
        "loadFailed": "Failed to load invitations",
        "roleInvalid": "'role' must be one of admin, agent, viewer",
        "labelTooLong": "Label must be {max} characters or fewer",
        "createFailed": "Failed to create invitation"
      },
      "members": {
        "loadFailed": "Failed to load members",
        "updateFailed": "Failed to update member",
        "roleInvalid": "'role' must be one of owner, admin, agent, viewer",
        "useTransferOwnership": "Use POST /api/account/transfer-ownership to promote a member to owner"
      },
      "nameMustBeString": "'name' must be a string",
      "nameEmpty": "Account name cannot be empty",
      "nameTooLong": "Account name must be {max} characters or fewer",
      "updateFailed": "Failed to update account",
      "transferFailed": "Failed to transfer ownership",
      "newOwnerInvalid": "'newOwnerUserId' must be a valid UUID"
    },
    "invitations": {
      "redeemFailed": "Failed to redeem invitation",
      "missingToken": "Missing invitation token"
    },
    "ai": {
      "pausedRequired": "paused (boolean) is required",
      "updateConversationFailed": "Failed to update conversation",
      "loadConfigFailed": "Failed to load AI configuration",
      "providerInvalid": "provider must be \"openai\", \"anthropic\", or \"openai_compatible\"",
      "baseUrlRequired": "base_url is required for openai_compatible",
      "baseUrlInvalid": "base_url must be a valid http(s) URL",
      "modelRequired": "model is required",
      "handoffNotMember": "handoff_agent_id must be a member of this account",
      "storedKeyReenter": "Stored API key could not be decrypted — re-enter your key.",
      "apiKeyRequired": "api_key is required",
      "validateWithProviderFailed": "Could not validate the API key with the provider.",
      "embeddingsKeyError": "Embeddings key: {message}",
      "validateEmbeddingsFailed": "Could not validate the embeddings key.",
      "saveConfigFailed": "Failed to save AI configuration",
      "deleteConfigFailed": "Failed to delete AI configuration",
      "conversationIdRequired": "conversation_id is required",
      "storedKeyUndecryptable": "Stored API key could not be decrypted.",
      "notConfigured": "AI assistant is not set up. Enable it in Settings → AI Assistant.",
      "noMessages": "No messages to draft from yet.",
      "messagesRequired": "messages is required",
      "sendMessageToTest": "Send a message to test the agent.",
      "noAgentConfigured": "No agent configured yet. Add your provider key in Setup.",
      "enterApiKey": "Enter an API key to test.",
      "validateFailed": "Could not validate the API key.",
      "loadUsageFailed": "Failed to load usage",
      "knowledge": {
        "loadDocFailed": "Failed to load document",
        "nothingToUpdate": "Nothing to update",
        "contentEmpty": "content cannot be empty",
        "updateDocFailed": "Failed to update document",
        "indexingFailed": "indexing failed",
        "updatedIndexFailed": "Updated, but semantic indexing failed ({message}). Lexical search still works; use Reindex to retry.",
        "updatedKeywordOnly": "Updated with keyword search only — your embeddings key could not be decrypted (check ENCRYPTION_KEY, then re-enter the key).",
        "deleteDocFailed": "Failed to delete document",
        "loadDocsFailed": "Failed to load documents",
        "reindexKeyCorrupt": "Your embeddings key could not be decrypted (check ENCRYPTION_KEY, then re-enter the key in Settings → AI Assistant). Nothing was reindexed.",
        "reindexPartial": "Reindexed {reindexed}, then hit an error: {message}",
        "loadKbFailed": "Failed to load knowledge base",
        "titleContentRequired": "title and content are required",
        "saveDocFailed": "Failed to save document",
        "savedIndexFailed": "Saved, but semantic indexing failed ({message}). Lexical search still works; use Reindex to retry.",
        "savedKeywordOnly": "Saved with keyword search only — your embeddings key could not be decrypted (check ENCRYPTION_KEY, then re-enter the key)."
      }
    },
    "automations": {
      "copyName": "{name} (Copy)",
      "copyFailed": "copy failed",
      "invalidActiveConfig": "Cannot keep automation active with invalid configuration",
      "invalidActivateConfig": "Cannot activate automation with invalid configuration",
      "nameTriggerRequired": "name and trigger_type are required"
    },
    "contacts": {
      "tagIdRequired": "tag_id required"
    },
    "flows": {
      "statusInvalid": "status must be one of 'draft' | 'active' | 'archived'",
      "cannotActivate": "Cannot activate flow — fix the issues below first.",
      "nameEmpty": "name cannot be empty",
      "unknownTemplate": "Unknown template_slug \"{slug}\"",
      "insertFailed": "flow insert failed",
      "nameRequired": "name is required"
    },
    "quickReplies": {
      "kindInvalid": "kind must be \"text\" or \"interactive\"",
      "contentTextRequired": "content_text is required for text quick replies",
      "titleRequired": "title is required"
    },
    "broadcast": {
      "alreadyRunning": "A delivery pass is already running for this broadcast. Wait for it to finish before resuming again.",
      "recipientsRequired": "Provide either `recipients` (preferred) or `phone_numbers` — must be a non-empty array",
      "templateNameRequired": "template_name is required",
      "templateMalformed": "Template row is malformed locally — run \"Sync from Meta\" in Settings to repair it before broadcasting.",
      "invalidPhoneFormat": "Invalid phone number format"
    },
    "whatsappConfig": {
      "fetchFailed": "Failed to fetch configuration",
      "noConfig": "No WhatsApp configuration saved yet. Fill in the form and click Save Configuration.",
      "tokenCorrupted": "The stored access token cannot be decrypted with the current ENCRYPTION_KEY. This usually means the key changed, or it differs between environments (local vs Hostinger vs Vercel). Click \"Reset Configuration\" below, then re-save.",
      "credentialsRequired": "access_token and phone_number_id are required",
      "phoneIdDigits": "Phone Number ID must contain only digits — it is the numeric id shown under Meta → WhatsApp → API Setup, not the phone number itself.",
      "wabaIdDigits": "WhatsApp Business Account ID must contain only digits — copy it from Meta → WhatsApp → API Setup.",
      "pinDigits": "PIN must be exactly 6 digits.",
      "validateFailed": "Failed to validate configuration",
      "numberLinkedElsewhere": "This WhatsApp phone number is already linked to another account on this instance. Each phone number can only be connected to one wacrm user.",
      "encryptFailed": "Failed to encrypt token. Check that ENCRYPTION_KEY is a valid 64-character hex string in your environment variables.",
      "updateFailed": "Failed to update configuration",
      "saveFailed": "Failed to save configuration",
      "deleteFailed": "Failed to delete configuration",
      "noConfigShort": "No WhatsApp configuration saved yet.",
      "tokenUndecryptable": "Stored access token can't be decrypted — likely ENCRYPTION_KEY changed. Re-enter the token to repair.",
      "phoneCheckFailed": "Phone metadata check failed: {message}",
      "wabaNoApps": "WABA has no subscribed apps. Re-save the configuration to subscribe.",
      "wabaCheckFailed": "WABA subscription check failed: {message}",
      "noWabaId": "No WABA ID on file — webhooks can't be wired without it. Add it in the form and re-save."
    },
    "media": {
      "idRequired": "Media ID is required",
      "fetchFailed": "Failed to fetch media"
    },
    "react": {
      "idEmojiRequired": "message_id and emoji are required",
      "messageNotFound": "Message not found",
      "notSent": "Cannot react to a message that has not been sent to WhatsApp",
      "contactNoPhone": "Contact has no phone number or WhatsApp user ID",
      "unknownMetaError": "Unknown Meta API error",
      "metaError": "Meta API error: {message}",
      "dbDeleteFailed": "Reaction sent to Meta but DB delete failed",
      "dbUpsertFailed": "Reaction sent to Meta but DB upsert failed"
    },
    "send": {
      "idsRequired": "Either conversation_id or contact_id, plus message_type, are required",
      "contactNotFound": "Contact not found",
      "openConversationFailed": "Failed to open a conversation for this contact"
    },
    "templates": {
      "invalidId": "Invalid template id.",
      "invalidJsonBody": "Invalid JSON body.",
      "notFound": "Template not found.",
      "neverSubmitted": "This template was never submitted to Meta — use New Template to submit it instead.",
      "statusNotEditable": "Templates in status {status} cannot be edited. Allowed: APPROVED, REJECTED, PAUSED.",
      "authNotEditable": "AUTHENTICATION templates are not editable here — manage them in Meta WhatsApp Manager.",
      "validationFailed": "Validation failed.",
      "headerUploadFailed": "Header media upload failed.",
      "metaEditFailed": "Meta edit failed.",
      "editedSaveFailed": "Edited on Meta but failed to save locally: {message}. Run \"Sync from Meta\" to recover.",
      "editFailed": "Failed to edit template.",
      "notConfiguredDelete": "WhatsApp not configured — cannot delete on Meta.",
      "metaDeleteFailed": "Meta delete failed.",
      "deletedLocalFailed": "Deleted on Meta but failed to delete locally: {message}.",
      "deleteFailed": "Failed to delete template.",
      "authNotSupported": "AUTHENTICATION templates are not yet supported here — create them in Meta WhatsApp Manager and use \"Sync from Meta\".",
      "metaSubmitFailed": "Meta submit failed.",
      "rateLimit": "Meta rate limit hit (100 template creates per hour). Try again later.",
      "submittedSaveFailed": "Submitted to Meta but failed to save locally: {message}. Run \"Sync from Meta\" to recover.",
      "submitFailed": "Failed to submit template.",
      "metaApiStatus": "Meta API error: {status}",
      "syncFailed": "Failed to sync templates"
    }
  }
}
