@dialstack/sdk-native 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -646,6 +646,7 @@ declare class Call {
646
646
  * otherwise prepareAnswerForOffer does it when the offer lands.
647
647
  */
648
648
  private acquireDeferredCapture;
649
+ private reportAnswerFailure;
649
650
  /** Set by the owner to surface a late mic failure, since `Call` has no error event. */
650
651
  private reportCaptureFailure;
651
652
  onCaptureFailure(report: (e: unknown) => void): void;
@@ -664,7 +665,6 @@ declare class Call {
664
665
  /** Route this call's ringback tone to `deviceId` (null = OS default). */
665
666
  setAudioOutputDevice(deviceId: string | null): void;
666
667
  private watchCaptureTrack;
667
- private get isFinished();
668
668
  private issueReqId;
669
669
  on<K extends keyof CallEventMap>(event: K, handler: Listener$1<K>): void;
670
670
  off<K extends keyof CallEventMap>(event: K, handler?: Listener$1<K>): void;
@@ -988,6 +988,7 @@ declare class DialStackPhone {
988
988
  private fetchIceServers;
989
989
  private handleMessage;
990
990
  private handleIncoming;
991
+ private answerFailureReporter;
991
992
  private emit;
992
993
  }
993
994
 
@@ -1736,9 +1737,16 @@ declare const en: {
1736
1737
  extensionPlaceholder: string;
1737
1738
  addUser: string;
1738
1739
  removeUser: string;
1740
+ removePhoneAccess: string;
1741
+ adminBadge: string;
1739
1742
  noUsers: string;
1740
1743
  atLeastOne: string;
1741
1744
  duplicateEmail: string;
1745
+ extensionRequired: string;
1746
+ extensionTaken: string;
1747
+ noPhoneService: string;
1748
+ givePhoneAccess: string;
1749
+ givingPhoneAccess: string;
1742
1750
  };
1743
1751
  location: {
1744
1752
  heading: string;
@@ -2011,6 +2019,7 @@ declare const en: {
2011
2019
  focDateTooSoon: string;
2012
2020
  focDateTooFar: string;
2013
2021
  focTimeRequired: string;
2022
+ focTimeOutOfWindow: string;
2014
2023
  billCopyRequired: string;
2015
2024
  signatureRequired: string;
2016
2025
  eligibilityError: string;
package/dist/index.js CHANGED
@@ -683,6 +683,7 @@ class Call {
683
683
  // True until answer() acquires the mic this call deliberately did not take on
684
684
  // arrival. Cleared there so a later device switch takes the ordinary path.
685
685
  this.captureDeferred = false;
686
+ this.reportAnswerFailure = () => { };
686
687
  /** Set by the owner to surface a late mic failure, since `Call` has no error event. */
687
688
  this.reportCaptureFailure = () => { };
688
689
  this.id = init.id;
@@ -731,11 +732,17 @@ class Call {
731
732
  // only need the success path. A rejection is swallowed so it cannot surface as
732
733
  // an unhandled rejection before the owner attaches.
733
734
  void this.localMediaReady.then(async () => {
734
- if (this.state === 'ended' || this.answerSent || !this.remoteDescriptionSet)
735
+ if (this.isFinished || this.answerSent || !this.remoteDescriptionSet)
735
736
  return;
736
- await this.buildAnswer();
737
+ // Nothing awaits this build, so its failure would otherwise vanish as an
738
+ // unhandled rejection and leave the call ringing with no answer sent.
739
+ await this.buildAnswer().catch(this.reportAnswerFailure);
737
740
  }, this.reportCaptureFailure);
738
741
  }
742
+ /** @internal Set by the owner to surface an answer built off the offer path failing. */
743
+ onAnswerFailure(report) {
744
+ this.reportAnswerFailure = report;
745
+ }
739
746
  onCaptureFailure(report) {
740
747
  this.reportCaptureFailure = report;
741
748
  }
@@ -757,10 +764,17 @@ class Call {
757
764
  // let the OS choose. Skipped for a permission denial (re-prompts, same answer)
758
765
  // and for a locked mic (no device of the kind is readable, so there is nothing
759
766
  // looser constraints could find).
760
- if (!preferred || !isRetryableWithoutDevice(e))
767
+ // A retry for a call that is already over would prompt again for nothing.
768
+ if (!preferred || !isRetryableWithoutDevice(e) || this.isFinished)
761
769
  throw e;
762
770
  stream = await getUserMedia({ audio: true });
763
771
  }
772
+ // The call ended while the prompt was open: releaseMedia already ran and can't
773
+ // see these tracks; unstopped, the mic indicator stays lit.
774
+ if (this.isFinished) {
775
+ stream.getTracks().forEach(stopTrack$1);
776
+ return;
777
+ }
764
778
  stream.getTracks().forEach((t) => {
765
779
  this.localStream.addTrack(t);
766
780
  this.watchCaptureTrack(t);
@@ -910,8 +924,10 @@ class Call {
910
924
  this.emit('audioInputLost');
911
925
  });
912
926
  }
913
- // True once the call is over by either path: the server's call.ended (which sets
914
- // endedSettled) or a local dispose().
927
+ /**
928
+ * @internal True once the call is over by either path: the server's call.ended
929
+ * (which sets endedSettled) or a local dispose().
930
+ */
915
931
  get isFinished() {
916
932
  return this.endedSettled || this.state === 'ended';
917
933
  }
@@ -957,7 +973,8 @@ class Call {
957
973
  callId: this.id,
958
974
  });
959
975
  }
960
- if (this.answerSent)
976
+ // A stale tap on a call that already ended must not take the mic for it.
977
+ if (this.answerSent || this.isFinished)
961
978
  return;
962
979
  // Deferred capture is taken HERE, not on arrival: the OS owns the audio
963
980
  // session and only activates it on answer, so acquiring earlier fails and
@@ -981,7 +998,7 @@ class Call {
981
998
  // call has ended, or the answer SDP isn't ready. Called from answer() (when
982
999
  // ready) and from prepareAnswerForOffer() (to flush a deferred answer).
983
1000
  sendAnswer() {
984
- if (this.answerSent || this.state === 'ended' || !this.pendingAnswerSdp)
1001
+ if (this.answerSent || this.isFinished || !this.pendingAnswerSdp)
985
1002
  return;
986
1003
  this.transport.send({ type: 'call.answer', req_id: this.issueReqId(), call_id: this.id });
987
1004
  this.transport.send({ type: 'sdp.answer', call_id: this.id, sdp: this.pendingAnswerSdp });
@@ -1222,9 +1239,23 @@ class Call {
1222
1239
  // buffered while the mic prompt was open can be applied, then wait for the
1223
1240
  // local mic before building the answer — the offer may have arrived while
1224
1241
  // getUserMedia was still pending.
1225
- await this.peerConnection.setRemoteDescription({ type: 'offer', sdp });
1226
- this.remoteDescriptionSet = true;
1227
- await this.flushPendingRemoteCandidates();
1242
+ //
1243
+ // The call can end at any of these awaits — the caller hangs up, another
1244
+ // device in a ring group answers, the user declines — and teardown closes the
1245
+ // peer connection, which then throws on every operation. That is not a
1246
+ // failure to report: the call is simply over, so stop without rejecting.
1247
+ if (this.isFinished)
1248
+ return;
1249
+ try {
1250
+ await this.peerConnection.setRemoteDescription({ type: 'offer', sdp });
1251
+ this.remoteDescriptionSet = true;
1252
+ await this.flushPendingRemoteCandidates();
1253
+ }
1254
+ catch (e) {
1255
+ if (this.isFinished)
1256
+ return;
1257
+ throw e;
1258
+ }
1228
1259
  try {
1229
1260
  await this.localMediaReady;
1230
1261
  }
@@ -1235,6 +1266,8 @@ class Call {
1235
1266
  // same denial.
1236
1267
  return;
1237
1268
  }
1269
+ if (this.isFinished)
1270
+ return;
1238
1271
  await this.buildAnswer();
1239
1272
  }
1240
1273
  // Builds (or rebuilds) the answer from an already-set remote description. Split
@@ -1259,11 +1292,20 @@ class Call {
1259
1292
  try {
1260
1293
  await this.buildAnswerOnce();
1261
1294
  }
1295
+ catch (e) {
1296
+ // Teardown mid-build rejects whichever await was in flight (a closed peer
1297
+ // connection, or the ICE wait releaseMedia aborts); see prepareAnswerForOffer.
1298
+ if (!this.isFinished)
1299
+ throw e;
1300
+ }
1262
1301
  finally {
1263
1302
  this.buildingAnswer = false;
1264
1303
  }
1265
1304
  }
1266
1305
  async buildAnswerOnce() {
1306
+ // Rechecked after every await: the call may have ended while it was pending.
1307
+ if (this.isFinished)
1308
+ return;
1267
1309
  // setRemoteDescription(offer) above already created a track-less sender for
1268
1310
  // each offered m-line, so getSenders() is non-empty here even though no mic
1269
1311
  // is attached yet. Guard on whether a sender actually has a track — keying
@@ -1277,10 +1319,16 @@ class Call {
1277
1319
  }
1278
1320
  this.attachDtmfSender();
1279
1321
  const answer = await this.peerConnection.createAnswer();
1322
+ if (this.isFinished)
1323
+ return;
1280
1324
  await this.peerConnection.setLocalDescription(answer);
1325
+ if (this.isFinished)
1326
+ return;
1281
1327
  // Same requirement as startOutbound: the answer must carry at least one
1282
1328
  // candidate, or the negotiated session has no ICE.
1283
1329
  await this.waitForIceGatheringComplete();
1330
+ if (this.isFinished)
1331
+ return;
1284
1332
  this.pendingAnswerSdp = this.peerConnection.localDescription?.sdp ?? answer.sdp ?? null;
1285
1333
  // Flush a deferred answer: answer() may have been clicked before the SDP
1286
1334
  // was ready, in which case it set wantsAnswer instead of sending.
@@ -1349,11 +1397,26 @@ class Call {
1349
1397
  return true;
1350
1398
  }
1351
1399
  async acceptRemoteAnswer(sdp) {
1352
- await this.peerConnection.setRemoteDescription({ type: 'answer', sdp });
1353
- this.remoteDescriptionSet = true;
1354
- await this.flushPendingRemoteCandidates();
1400
+ // As in prepareAnswerForOffer: an end landing mid-apply closes the connection,
1401
+ // and that is not a failure to report.
1402
+ if (this.isFinished)
1403
+ return;
1404
+ try {
1405
+ await this.peerConnection.setRemoteDescription({ type: 'answer', sdp });
1406
+ this.remoteDescriptionSet = true;
1407
+ await this.flushPendingRemoteCandidates();
1408
+ }
1409
+ catch (e) {
1410
+ if (this.isFinished)
1411
+ return;
1412
+ throw e;
1413
+ }
1355
1414
  }
1356
1415
  async addRemoteCandidate(candidate, sdpMid, sdpMLineIndex) {
1416
+ // A disposed call stays routable, but its closed connection rejects every
1417
+ // candidate, and the caller does not await this.
1418
+ if (this.isFinished)
1419
+ return;
1357
1420
  const init = candidate == null
1358
1421
  ? null
1359
1422
  : { candidate, sdpMid: sdpMid ?? undefined, sdpMLineIndex: sdpMLineIndex ?? undefined };
@@ -3238,11 +3301,7 @@ class DialStackPhone {
3238
3301
  // is swallowed inside prepareAnswerForOffer, so it is not double-emitted
3239
3302
  // here.
3240
3303
  if (call) {
3241
- void call.prepareAnswerForOffer(msg.sdp).catch((e) => this.emit('error', new PhoneError({
3242
- code: 'call_failed',
3243
- message: `Failed to prepare answer for incoming call: ${e.message}`,
3244
- callId: msg.call_id,
3245
- })));
3304
+ void call.prepareAnswerForOffer(msg.sdp).catch(this.answerFailureReporter(call));
3246
3305
  }
3247
3306
  return;
3248
3307
  }
@@ -3352,6 +3411,9 @@ class DialStackPhone {
3352
3411
  // through onCaptureFailure if the mic is still unavailable on answer.
3353
3412
  if (e instanceof CaptureDeferred)
3354
3413
  return;
3414
+ // A prompt dismissed after the call ended failed nothing: the call is over.
3415
+ if (call.isFinished)
3416
+ return;
3355
3417
  this.emit('error', new PhoneError({
3356
3418
  code: 'call_failed',
3357
3419
  message: `Microphone unavailable for incoming call: ${e.message}`,
@@ -3359,8 +3421,22 @@ class DialStackPhone {
3359
3421
  }));
3360
3422
  };
3361
3423
  call.onCaptureFailure(reportMicFailure);
3424
+ call.onAnswerFailure(this.answerFailureReporter(call));
3362
3425
  call.whenLocalMediaReady().catch(reportMicFailure);
3363
3426
  }
3427
+ answerFailureReporter(call) {
3428
+ return (e) => {
3429
+ // Backstop for the guards inside Call: whatever an ended call's answer
3430
+ // build throws, the call is over and nothing failed.
3431
+ if (call.isFinished)
3432
+ return;
3433
+ this.emit('error', new PhoneError({
3434
+ code: 'call_failed',
3435
+ message: `Failed to prepare answer for incoming call: ${e.message}`,
3436
+ callId: call.id,
3437
+ }));
3438
+ };
3439
+ }
3364
3440
  emit(event, ...args) {
3365
3441
  this.listeners[event]?.forEach((h) => {
3366
3442
  h(...args);
@@ -5779,7 +5855,7 @@ function resolveSoftphonePalette(appearance) {
5779
5855
  };
5780
5856
  }
5781
5857
 
5782
- "function"==typeof SuppressedError&&SuppressedError;const v={common:{loading:"Loading...",error:"Error",noResults:"No results",delete:"Delete",call:"Call",cancel:"Cancel",confirm:"Confirm",previous:"Previous",next:"Next",perPage:"Per page",showing:"Showing {start}-{end} of {total}",play:"Play",pause:"Pause"},softphone:{title:"Softphone",destinationPlaceholder:"Enter a number",call:"Call",backspace:"Delete",connecting:"Connecting…",reconnecting:"Reconnecting…",disconnected:"Disconnected",connectionError:"Connection error",callError:"Call failed",micPermissionError:"Microphone access is required — allow it and try again",dismiss:"Dismiss",unknownCaller:"Unknown",incomingCall:"Incoming call",answer:"Answer",decline:"Decline",hangUp:"Hang up",mute:"Mute",unmute:"Unmute",hold:"Hold",resume:"Resume",keypad:"Keypad",transfer:"Transfer",transferPlaceholder:"Transfer to…",transferSend:"Transfer",transferNow:"Transfer now",transferConsult:"Consult first",transferComplete:"Complete transfer",transferConsulting:"Consulting…",transferOriginalOnHold:"On hold",addCall:"Add call",addCallPlaceholder:"Number to dial",addCallSend:"Call",merge:"Merge calls",split:"Split",conferenceLabel:"Conference",cancel:"Cancel",stateTrying:"Calling…",stateRinging:"Ringing…",stateActive:"In call",stateHeld:"On hold",stateEnded:"Call ended",done:"Done",audioDevices:"Audio",audioMicrophone:"Microphone",audioSpeaker:"Speaker",audioSystemDefault:"System default",audioUnnamedDevice:"Unnamed device",audioLabelsHidden:"Allow microphone access to see device names",audioDevicesUnsupported:"This browser cannot list audio devices",audioSpeakerUnsupported:"Choose your speaker in your device settings",audioMicrophoneLost:"Your microphone was disconnected — choose another",switchToCall:"Switch to this call",heldCallsLabel:"On hold",callWaiting:"Call waiting",emergencyPrompt:"Set your emergency location",emergencyHint:"Confirm your location before placing calls — required by 911 regulations for internet calling.",emergencyConfirm:"Yes, I'm here",emergencyNewLocation:"Set a new location",emergencyUseLocation:"Use my current location",emergencyLocating:"Getting your location…",emergencyNumber:"Number",emergencyStreet:"Street",emergencyUnit:"Unit (optional)",emergencyCity:"City",emergencyState:"State",emergencyPostalCode:"Postal code",emergencySave:"Confirm location",emergencySaving:"Saving…",emergencyBack:"Back"},aiAgent:{loading:"Loading Managed VoiceAI agent…",loadFailed:"Failed to load Managed VoiceAI agent: {message}",fields:{name:"Name",namePlaceholder:"Front Desk Agent",nameHint:"Internal label shown in lists and call logs. Not heard by callers.",extensionNumber:"Extension",extensionNumberPlaceholder:"700",extensionNumberHint:"Dial this extension from any phone on the account to reach the agent.",extensionChecking:"Checking extension...",personaName:"Persona name",personaNamePlaceholder:"e.g. Receptionist",personaNameHint:"How the agent introduces itself on calls.",greetingName:"Greeting name",greetingNamePlaceholder:"Your business name",greetingNameHintWithName:'Used in the call greeting (e.g. "Thanks for calling {name}").',greetingNameHintGeneric:'Used in the call greeting (e.g. "Thanks for calling [your business]").',instructions:"Instructions",instructionsPlaceholder:"Provide additional instructions for how the Managed VoiceAI agent should behave during calls...",instructionsHint:"Plain-English guidance for the agent: tone, what to do, what to escalate.",faq:"FAQ",faqEmpty:"No FAQ entries yet. Add one to teach the agent a recurring question.",faqEntry:"Entry {index}",faqQuestion:"Question",faqAnswer:"Answer",faqQuestionLabel:"FAQ entry {index} question",faqAnswerLabel:"FAQ entry {index} answer",faqRemove:"Remove",faqRemoveLabel:"Remove FAQ entry {index}",faqAdd:"Add FAQ entry",scheduling:"Scheduling",schedulingHint:"Connect your Managed VoiceAI agent to an external scheduling system. Clear the URL to disable scheduling.",webhookUrl:"Webhook URL",webhookUrlHint:"Base URL for scheduling webhooks. DialStack appends tool-call paths automatically.",webhookUrlPlaceholder:"https://example.com/api/dialstack/webhooks",secret:"Webhook secret",secretHint:"Used to verify tool-call webhooks sent from this Managed VoiceAI agent to your integration.",copySecret:"Copy webhook secret",rotateSecret:"Rotate secret"},save:"Save",saving:"Saving…",saved:"Saved.",errors:{nameRequired:"Name is required.",nameMaxLength:"Name must be {max} characters or fewer.",personaNameMaxLength:"Persona name must be {max} characters or fewer.",greetingNameMaxLength:"Greeting name must be {max} characters or fewer.",instructionsMaxLength:"Instructions must be {max} characters or fewer.",faqMaxItems:"FAQ supports up to {max} entries.",faqIncompleteEntry:"Every FAQ entry needs both a question and an answer.",faqFieldMaxLength:"FAQ fields must be {max} characters or fewer.",extensionNumeric:"Extension must contain only digits.",extensionUnavailable:"Extension number is already in use.",schedulingUrlMaxLength:"Webhook URL must be {max} characters or fewer.",schedulingUrlHttpsRequired:"Webhook URL must start with https://.",hostCreateRequired:"This form is waiting for the host app to create the Managed VoiceAI agent.",hostSaveRequired:"This form is waiting for the host app to save the Managed VoiceAI agent."}},voicemails:{title:"Voicemails",loading:"Loading voicemails...",empty:"No voicemails",noUserId:"Please set a user ID to load voicemails",transcription:"Transcription",summary:"Summary",sentiment:"Sentiment",sentimentPositive:"Positive",sentimentNeutral:"Neutral",sentimentNegative:"Negative",sentimentMixed:"Mixed",transcript:"Full Transcript",transcriptLoading:"Loading transcript...",transcriptNotAvailable:"Transcript not available",deleteConfirm:"Delete this voicemail?",deleteTitle:"Delete Voicemail",progress:"Playback progress"},callLogs:{title:"Call Logs",loading:"Loading call logs...",empty:"No call logs found",columns:{date:"Date",direction:"Direction",from:"From",to:"To",duration:"Duration",status:"Status",quality:"MOS"},directions:{inbound:"Inbound",outbound:"Outbound",internal:"Internal"},routedTo:"Routed to:",calledBy:"Called by:",statuses:{completed:"Completed",noAnswer:"No Answer",busy:"Busy",failed:"Failed",voicemail:"Voicemail"},quality:{good:"Good",fair:"Fair",poor:"Poor",unavailable:"N/A",unavailableTooltip:"No quality data available"}},callHistory:{title:"Call History",loading:"Loading call history...",empty:"No call history",noPhoneNumber:"Please set a phone number to load call history",error:"Unable to load call history",clickToCall:"Click to call",summaryNotAvailable:"Summary not available",relativeTime:{justNow:"Just now",minuteAgo:"1 min ago",minutesAgo:"{count} min ago",hourAgo:"1 hour ago",hoursAgo:"{count} hours ago",yesterday:"Yesterday"}},phoneNumberOrdering:{title:"Order Phone Numbers",steps:{search:"Search",select:"Select",confirm:"Confirm",route:"Route",done:"Done",stepOf:"Step {current} of {total}"},search:{title:"Search Available Numbers",subtitle:"Find available phone numbers by entering an area code or ZIP code.",searchType:"Search by",areaCode:"Area Code",zip:"ZIP Code",areaCodeLabel:"Area Code",areaCodePlaceholder:"e.g. 212",zipLabel:"ZIP Code",zipPlaceholder:"e.g. 10001",numberOfResults:"Quantity to display",search:"Search"},results:{title:"Available Numbers",phoneNumber:"Phone Number",state:"State",selectAll:"Select all",selected:"{count} selected",noResults:"No numbers available for this search",continue:"Continue",backToSearch:"Back to Search"},confirm:{title:"Confirm Order",subtitleOne:"You are about to order 1 phone number",subtitleOther:"You are about to order {count} phone numbers",description:"Your order will be submitted to the carrier for fulfillment. This usually completes within seconds but may take longer.",placeOrder:"Place Order",continue:"Continue",back:"Back",billing:{label:"Billing impact",headline:"Adds {amount}/month to this account's bill",detail:"{count} phone numbers at {rate} each per month.",detail_one:"{count} phone number at {rate} per month.",detail_other:"{count} phone numbers at {rate} each per month.",timing:"Billing starts when each number activates.",taxesAndFees:"Taxes and fees are additional.",noPrice:"These numbers are billable on this account.",noPrice_one:"This number is billable on this account.",noPrice_other:"These numbers are billable on this account.",notBilled:"This account is not billed, so ordering these numbers costs nothing."}},route:{title:"Choose call routing",subtitle:"Pick where these numbers should send calls once they activate. You can change this any time, or set it up later.",later:"Set up routing later",laterHint:"Configure each number from its detail page after it activates.",noTargets:"No routing destinations exist yet. You can set up routing after the numbers are added.",unnamed:"Untitled",extension:"ext. {ext}",back:"Back",type:{user:"User",dial_plan:"Dial plan",voice_app:"Voice app",queue:"Queue",ring_group:"Ring group",shared_voicemail:"Shared voicemail"}},ordering:{title:"Placing Order..."},complete:{titlePendingOne:"Order Submitted",titlePendingOther:"Order Submitted",titleCompleteOne:"Number Ready",titleCompleteOther:"Numbers Ready",titlePartialOne:"Partially Fulfilled",titlePartialOther:"Partially Fulfilled",descriptionPendingOne:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",descriptionPendingOther:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",descriptionCompleteOne:"Your phone number is now in your inventory and ready to be configured.",descriptionCompleteOther:"Your phone numbers are now in your inventory and ready to be configured.",descriptionPartialOne:"Some numbers could not be fulfilled by the carrier.",descriptionPartialOther:"Some numbers could not be fulfilled by the carrier.",checking:"Checking order status...",assignmentHint:"Numbers added to your inventory still need to be assigned to an extension or dial plan before they can receive calls.",orderMore:"Order More Numbers"},error:{title:"Order Failed",description:"The carrier was unable to fulfill your order.",tryAgain:"Try Again"},statuses:{pending:"Pending",complete:"Complete",partial:"Partial",failed:"Failed"}},phoneNumbers:{title:"Phone Numbers",loading:"Loading phone numbers...",empty:"No phone numbers",filterLabel:"Filter by status",search:{placeholder:"Search phone numbers...",noResults:"No phone numbers match your search"},filters:{active:"Active",in_progress:"In Progress",cancelled:"Cancelled"},columns:{phoneNumber:"Phone Number",status:"Status",callerID:"Outbound Caller ID",callerIDPrefix:"Inbound Caller ID Prefix",outbound:"Usage",carrier:"Carrier",transferDate:"Transfer Date",routingTarget:"Call Routing",cancelledDate:"Date Cancelled"},statuses:{active:"Active",inactive:"Inactive",released:"Released",ordering:"Ordering",orderFailed:"Order Failed",portingDraft:"Port Draft",portingApproved:"Ready to Submit",portingSubmitted:"Port Submitted",portingException:"Port Issue",portingFoc:"Port Scheduled"},badges:{temporary:"Temporary"},outbound:{enabled:"Two-way",disabled:"Inbound only",fax:"Fax"},routingTarget:{notSet:"Not set",setAction:"Set routing",faxNotApplicable:"Not applicable"},routingTargetTypes:{user:"User",dialPlan:"Dial Plan",voiceApp:"Voice App",ringGroup:"Ring Group"}},accountOnboarding:{billing:{label:"Billing impact",headline:"Adds {amount}/month to this account's bill",detail:{userSeat:{one:"{count} user seat at {rate} per month.",other:"{count} user seats at {rate} each per month."},phoneNumber:{one:"{count} phone number at {rate} per month.",other:"{count} phone numbers at {rate} each per month."}},noPrice:{userSeat:{one:"Adds {count} billable user seat to this account.",other:"Adds {count} billable user seats to this account."},phoneNumber:{one:"Adds {count} billable phone number to this account.",other:"Adds {count} billable phone numbers to this account."}},rateHeadline:{userSeat:"{rate}/month per user seat",phoneNumber:"{rate}/month per phone number"},rateDetail:{userSeat:"Each team member you add is billed at this rate.",phoneNumber:"Each number you add is billed at this rate."},noPriceRate:{userSeat:"Each team member you add is billable on this account.",phoneNumber:"Each number you add is billable on this account."},startsOnActivation:"Billing starts when each number activates.",taxesAndFees:"Taxes and fees are additional.",notBilled:"This account is not billed, so this costs nothing."},title:"Account Onboarding",breadcrumbAriaLabel:"Onboarding progress",loading:"Loading...",error:{title:"Unable to Load",description:"Something went wrong loading the onboarding wizard.",retry:"Try Again"},steps:{account:"Account Setup",numbers:"Phone Numbers",hardware:"Hardware Setup",complete:"Complete"},sidebar:{businessDetails:"Business Details",businessDetailsDesc:"Enter your company information",teamMembers:"Team Members",teamMembersDesc:"Add users and assign extensions",numberOptions:"Number Options",numberOptionsDesc:"Choose to port existing or get new numbers",callerId:"Caller ID",callerIdDesc:"Set caller ID for your numbers",directoryListing:"Directory Listing",directoryListingDesc:"Configure 411 directory listing",numberSetup:"Number Setup",numberSetupDesc:"Configure your phone numbers",verification:"Verification",verificationDesc:"Verify number status",deviceAssignment:"Device Assignment",deviceAssignmentDesc:"Assign devices to users"},account:{title:"Business Details",subtitle:"Enter your company information",details:{heading:"Account Details",companyNameLabel:"Company Name",companyNamePlaceholder:"Acme Corp",companyNameRequired:"Company name is required",emailLabel:"Primary Contact Email",emailPlaceholder:"admin@company.com",emailRequired:"Primary contact email is required",emailInvalid:"Enter a valid email address",phoneLabel:"Primary Contact Phone Number",phonePlaceholder:"(555) 123-4567",phoneRequired:"Primary contact phone number is required",phoneInvalid:"Enter a valid US phone number",primaryContactLabel:"Primary Contact",primaryContactPlaceholder:"Jane Doe",primaryContactRequired:"Primary contact is required",regionLabel:"Region",regionPlaceholder:"Select a region",timezoneLabel:"Timezone",timezonePlaceholder:"Select a timezone",timezoneRequired:"Timezone is required"},users:{heading:"Team Members",description:"Add users who will have phone extensions",nameLabel:"Full name",namePlaceholder:"John Doe",nameRequired:"Name is required",emailLabel:"Email",emailPlaceholder:"john@company.com",extensionLabel:"Extension",extensionPlaceholder:"ex. 103",addUser:"Add User",removeUser:"Remove",noUsers:"No team members added yet.",atLeastOne:"Add at least one team member to continue.",duplicateEmail:"A user with this email already exists."},location:{heading:"Business Location",description:"Add your business address for E911 and caller ID.",nameLabel:"Location Name",namePlaceholder:"Main Office",nameRequired:"Location name is required",addressLabel:"Address",searchPlaceholder:"Start typing an address...",searching:"Searching...",noResults:"No addresses found",enterManually:"Enter manually",searchInstead:"Search instead",edit:"Edit",addressRequired:"Address is required",houseNumberLabel:"#",houseNumberPlaceholder:"123",streetLabel:"Street",streetPlaceholder:"Main St",cityLabel:"City",cityPlaceholder:"New York",stateLabel:"State",statePlaceholder:"Select",postalCodeLabel:"ZIP",postalCodePlaceholder:"10001"},saving:"Saving...",saveError:"Failed to save. Please try again."},numbers:{title:"Phone Numbers",subtitle:"Choose how you'd like to set up your business numbers",defaultDialPlanName:"Onboarding Dial Plan",callerId:{title:"Caller ID Setup",subtitle:"Configure the name displayed when making outbound calls",inputLabel:"Caller ID Name",inputPlaceholder:"e.g. ACME Corp",inputHelp:"Max 15 characters. Letters, numbers, spaces, and hyphens only.",charCount:"{count}/15",submit:"Set Caller ID",submitting:"Submitting...",submittingAll:"Submitting caller IDs...",submitted:"Submitted",alreadySet:"Already configured",submitAll:"Set All Caller IDs",skipCallerId:"Skip",partialError:"Some caller IDs could not be set. Fix errors and retry, or skip.",validation:{required:"Caller ID name is required",tooLong:"Must be 15 characters or fewer",invalidChars:"Only letters, numbers, spaces, and hyphens allowed"},error:{submitFailed:"Failed to set caller ID. Please try again.",conflict:"A caller ID update is already in progress for this number."},directoryListing:{title:"Directory Listing (DA/DL)",info:"To update your directory listing, contact {platformName} support."},noDIDs:"No active phone numbers to configure."},directoryListing:{title:"Directory Listing",subtitle:"A directory listing feeds your business information into online directories and data aggregators, helping customers find you. It also reduces the chance of your outbound calls being flagged as spam by call-screening apps.",selectPrompt:"Select which number should be listed:",noneOption:"None — skip directory listing",noDIDs:"No eligible phone numbers to configure.",businessName:"Business Name",businessNamePlaceholder:"Enter business name for listing",businessNameHelp:"The name shown in directory listings and used for caller verification. Max 200 characters.",validation:{nameRequired:"Business name is required for the directory listing."}},overview:{heading:"Your Numbers",empty:"No telephone numbers yet. Request new numbers or port your existing ones.",requestNew:"Request New Numbers",requestNewDesc:"Get new business phone numbers instantly. Choose from available numbers in your area.",portExisting:"Port Existing Number",portExistingDesc:"Transfer your current business number to {platformName}. This typically takes 5–10 business days.",phoneNumber:"Phone Number",type:"Type",status:"Status",source:"Source",temporaryBanner:"A temporary number has been assigned to your account while you set up your permanent numbers.",loadError:"Failed to load telephone numbers. Please try again.",retry:"Retry"},status:{active:"Active",inactive:"Inactive",released:"Released",ordering:"Ordering",order_failed:"Order Failed",porting_draft:"Port Draft",porting_submitted:"Port Submitted",porting_exception:"Port Exception",porting_foc:"Port Scheduled",porting_approved:"Ready to Submit"},source:{did:"Account",didTemporary:"Temporary",number_order:"New Order",port_order:"Port"},order:{searchTitle:"Search Available Numbers",searchSubtitle:"Find available numbers by entering an area code or ZIP code",searchByAreaCode:"Area Code",searchByZip:"ZIP Code",areaCodeLabel:"Area Code",areaCodePlaceholder:"212",zipLabel:"ZIP Code",zipPlaceholder:"10001",quantityLabel:"Quantity",search:"Search",searching:"Searching...",resultsTitle:"Available Numbers",resultsSubtitle:"Select the numbers you would like to order.",noResults:"No numbers found. Try a different search.",selectAll:"Select All",deselectAll:"Deselect All",selected:"selected",state:"State",confirmTitle:"Confirm Your Order",confirmSubtitle:"You are about to order {count} phone numbers",confirmSubtitle_one:"You are about to order {count} phone number",confirmSubtitle_other:"You are about to order {count} phone numbers",carrierNote:"Your order will be submitted to the carrier for fulfillment. This usually completes within seconds but may take longer.",placeOrder:"Place Order",placing:"Placing Order...",ordering:"Ordering...",statusTitle:"Order Submitted",statusPending:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",statusStalled:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",statusComplete:"Your numbers have been activated.",statusFailed:"The order could not be completed.",statusPartial:"Some numbers were activated, but others failed.",done:"Done",orderMore:"Order More Numbers",continue:"Continue",error:"An error occurred while placing the order."},port:{numbersTitle:"Numbers to Port",numbersSubtitle:"Enter the numbers you want to transfer to {platformName}, or paste a whole list into any row.",phoneLabel:"Phone Number",phonePlaceholder:"(555) 123-4567",addAnother:"Add another number",numberLabel:"Phone number {row}",removeNumber:"Remove phone number {row}",duplicateOfRow:"Duplicate of row {row}",pasteHint:"Press Enter for another row. Pasting a list — one per line, commas, or a spreadsheet column — fills a row for each number.",readyCountZero:"No numbers yet",readyCountOne:"{count} number ready",readyCountOther:"{count} numbers ready",needsAttentionOne:"{count} row needs attention before you can continue",needsAttentionOther:"{count} rows need attention before you can continue",reasonInvalid:"Not a valid US phone number",reasonNotUs:"Only US numbers can be ported",reasonTollFree:"Toll-free numbers cannot be ported",reasonAmbiguous:"Too many digits for one number — if this is several, put one per row",reasonHasExtension:"Remove the extension",maxPerOrder:"{count} numbers — the maximum is {max} per order. Move {excess} into a second port order.",notPortableWithDetail:"{label} ({detail})",accountLimit:"You've reached the number of phone numbers this account can hold. Contact support to raise the limit, then try again.",numbersUnavailable:"Some of these numbers are already in use and can't be ported. The ones affected are marked above.",conflictAlreadyOnAccount:"You already have this number",conflictInServiceElsewhere:"Already in service — contact support to transfer it",checkEligibility:"Check Eligibility",checking:"Checking...",eligibilityTitle:"Port Eligibility",eligibilitySubtitle:"Review which numbers can be ported.",portable:"Portable",notPortable:"Not Portable",carrier:"Current Carrier",wireless:"Wireless",wirelessYes:"Yes",wirelessNo:"No",accountRequired:"Account # Required",continueWithPortable:"Continue with Portable Numbers",noPortable:"None of the entered numbers are eligible for porting.",subscriberTitle:"Subscriber Information",subscriberSubtitle:"Enter the details exactly as they appear on your current phone bill.",btnLabel:"Billing Telephone Number (BTN)",btnPlaceholder:"(555) 123-4567",businessNameLabel:"Business Name",businessNamePlaceholder:"Acme Corp",approverNameLabel:"Authorized Contact",approverNamePlaceholder:"John Doe",accountNumberLabel:"Account Number",accountNumberPlaceholder:"From your current carrier",pinLabel:"Account PIN",pinPlaceholder:"1234",addressHeading:"Service Address",houseNumberLabel:"Street Number",houseNumberPlaceholder:"123",streetNameLabel:"Street Name",streetNamePlaceholder:"Main St",line2Label:"Suite / Unit",line2Placeholder:"Suite 100",cityLabel:"City",cityPlaceholder:"New York",stateLabel:"State",statePlaceholder:"Select state",zipLabel:"ZIP Code",zipPlaceholder:"10001",focTitle:"Requested Port Date",focSubtitle:"Choose when you want the numbers transferred. Must be at least 5 business days out.",focDateLabel:"Port Date",focTimeLabel:"Port Time (Eastern)",focTimePlaceholder:"Select time",documentsTitle:"Supporting Documents",documentsSubtitle:"Upload your latest phone bill and optionally a Customer Service Record (CSR).",billCopyLabel:"Phone Bill Copy",billCopyDesc:"A recent bill from your current carrier showing the numbers to be ported.",billCopyRequired:"Required",csrLabel:"Customer Service Record (CSR)",csrDesc:"Optional but recommended — speeds up the porting process.",csrOptional:"Optional",uploadFile:"Choose File",fileSelected:"Selected:",noFileSelected:"No file selected",uploading:"Uploading...",reviewTitle:"Review & Approve",reviewSubtitle:"Verify all details before submitting your port request.",numbersSection:"Numbers",subscriberSection:"Subscriber",focSection:"Port Date",documentsSection:"Documents",signatureLabel:"Electronic Signature",signaturePlaceholder:"Type your full legal name",signatureHelp:"By signing, you authorize the transfer of the listed numbers to {platformName}.",approve:"Approve & Submit",submitting:"Submitting...",submittedTitle:"Port Request Submitted",submittedSubtitle:"Your port request has been submitted and is being processed.",submittedStatus:"Status",backToOverview:"Back to Numbers",carrierGroupsTitle:"Carrier Groups",carrierGroupsSubtitle:"Your numbers are with different carriers. Each carrier requires a separate port request.",carrierStart:"Start",carrierContinue:"Continue",carrierSubmitted:"Submitted",numberSingular:"number",numberPlural:"numbers"},validation:{areaCodeRequired:"Area code is required.",areaCodeFormat:"Enter a 3-digit area code.",cityRequired:"City is required.",stateRequired:"State is required.",zipRequired:"ZIP code is required.",zipFormat:"Enter a 5-digit ZIP code.",selectAtLeastOne:"Select at least one number.",phoneRequired:"At least one phone number is required.",phoneInvalid:"Enter a valid US phone number.",phoneDuplicate:"This number has already been entered.",btnRequired:"BTN is required.",btnInvalid:"Enter a valid US phone number.",businessNameRequired:"Business name is required.",approverNameRequired:"Authorized contact name is required.",houseNumberRequired:"Street number is required.",streetNameRequired:"Street name is required.",focDateRequired:"Port date is required.",focDateTooSoon:"Port date must be at least 5 business days from today.",focDateTooFar:"Port date must be within 30 days.",focTimeRequired:"Port time is required.",billCopyRequired:"A phone bill copy is required.",signatureRequired:"Signature is required.",eligibilityError:"Failed to check eligibility. Please try again.",submitError:"Failed to submit port request. Please try again."},nav:{back:"Back",next:"Next",cancel:"Cancel",backToSearch:"Back to Search",confirm:"Confirm"},gate:{noDIDsAvailable:"You need at least one phone number before selecting a primary number. Order or port a number first.",primaryRequired:"Please select a primary number to continue."}},hardware:{title:"Assign Devices",shippingAddress:"Shipping Address",subtitle:"Drag and drop devices to assign them to team members",noUsers:"No team members found. Add team members in the Account step first.",noDevices:"No devices are available for your account at the moment.",isDectBase:"This is a cordless handset base station",userLabel:"Team Member",selectUser:"Select a team member",selectUserRequired:"Please select a team member.",macLabel:"MAC Address",macPlaceholder:"00:04:13:AA:BB:CC",invalidMac:"Enter a valid 12-digit MAC address.",ipeiLabel:"Handset IPEI",ipeiPlaceholder:"03AABB1234567890CCDD",invalidIpei:"Enter a valid IPEI (hex digits only).",ipeiNotMac:"This looks like a MAC address, not an IPEI. An IPEI looks like 03AABB1234567890CCDD.",removeDevice:"Remove",unsupportedVendor:"This device is not currently supported. Our support team has been notified and will follow up.",duplicateMac:"This MAC address is already registered.",deviceNotFound:"Device was created but could not be found. Please try again.",handset:"handset",handsets:"handsets",addDeviceButton:"+ Add Device",addHandsetButton:"+ Handset",save:"Save",saving:"Saving...",cancel:"Cancel",dectBase:"Cordless Base",removeBaseFailed:"Failed to remove cordless base.",tableHeaderName:"Full name",tableHeaderExtension:"Extension",tableHeaderDevice:"Assigned Device",availableDevices:"Available Devices",allAssigned:"All devices have been assigned",dragDropHint:"Drag and drop device here",clickToAssign:"Click to assign",submitOrder:"Submit Order",assignAndComplete:"Save & Continue",unassign:"Unassign",deskPhone:"Desk phone",cordless:"Cordless",submitting:"Submitting...",gate:{noDevices:"No devices are available for your account. Please contact support to add devices before completing this step."}},complete:{title:"Wahoo!",subtitle:"It's time to start using your embedded voice system",e911:{loading:"Configuring emergency services...",pollingStatus:"Verifying emergency services registration...",verified:"E911 emergency address is verified.",processing:"E911 registration is being processed. This may take a few minutes.",pendingAfterPolling:"E911 registration submitted. Your phone service is active — emergency address verification will complete shortly.",addressStandardized:"Your address was standardized for emergency services accuracy.",primaryAssigned:"assigned as primary number for",errorTitle:"E911 configuration failed",errorDescription:"There was an error configuring emergency services. You can retry or configure manually later.",retryButton:"Retry",deferred:"E911 emergency services have not been fully configured. Each location with a phone number needs a verified emergency address before your phone service can be activated."}},stepComplete:{title:"{stepName} Complete",subtitle:"This step has been completed successfully.",done:"Done"},nav:{next:"Next",skip:"Skip",back:"Back",exit:"Finish"},legal:{prefix:"By continuing, you agree to the",and:"and",termsOfService:"Terms of Service",recipientTerms:"Recipient Terms of Service",privacyPolicy:"Privacy Policy"},ssa:{title:"Review and accept your subscription agreement",intro:"Before you can use your phone service, please review the Service Subscription Agreement below — including its emergency calling (911/E911) terms — and confirm your acceptance.",pricingTitle:"Your plan pricing",perUser:"Per user",perNumber:"Per phone number",perAiLocation:"Managed VoiceAI, per location",perMonthSuffix:"/mo",agreementLabel:"Service Subscription Agreement",openInNewTab:"Open the full agreement in a new tab",accept:"Accept & Continue",submitting:"Recording your acceptance…",notPermitted:"Only the account owner can accept this agreement. Please ask them to sign in and accept it — phone service requires their signature.",errors:{stale:"The agreement was updated. Please review the latest version and accept again.",pricingMissing:"Your plan pricing has not been finalized yet. Please contact your provider to continue.",generic:"We could not record your acceptance. Please try again.",retry:"Try again"},loadError:{title:"Unable to load your agreement",description:"We could not load your subscription agreement, which is required before you can continue. Please try again.",retry:"Try again",retrying:"Loading…"}}},onboardingPortal:{onboardingFlows:"ONBOARDING FLOWS",saveAndExit:"Save & Exit to Overview",back:"Back",helpSupport:"Help & Support",onboardingComplete:"Onboarding complete",rates:{title:"Your monthly rates",subtitle:"What you're billed at today.",perUser:"Per user",perPhoneNumber:"Per phone number",perVoiceAiLocation:"Managed VoiceAI, per location",voiceAiPerLocationNote:"Charged for every location once Managed VoiceAI is active.",perMonth:"{rate}/month",rateNotSet:"Not set",pendingRate:"{rate}/month from {date}",pendingNote:"Rate changes take effect at the start of the next billing period.",taxesAndFees:"Taxes and fees are additional.",notBilled:"This account is not billed.",noRates:"No rates are set for this account yet.",unavailable:"Rates are unavailable right now."},overview:{label:"Overview",title:"Your Business Onboarding",subtitle:"Complete the steps below to set up your business phone system",progressTitle:"Onboarding Progress",flowsComplete:"{completed} of {total} flows complete",stepsTitle:"Onboarding Steps",complete:"Complete",progress:"Progress",completeSetup:"Complete Setup",continueSetup:"Continue Setup",review:"Review",needHelp:"Need help?",needHelpSubtitle:"Our team is here to help you get set up quickly",scheduleCall:"Schedule a Call",viewDocs:"View Documentation",accountDesc:"Set up your business profile, add team members, and configure your dial plan",numbersDesc:"Port existing numbers or request new business lines",hardwareDesc:"Assign phones to team members and track delivery",phoneStatusTitle:"Phone number status",phoneStatusSubtitle:"Track the status of your phone numbers",phoneStatusNumber:"Phone Number",phoneStatusType:"Type",phoneStatusStatus:"Status",phoneStatusTypeNew:"New",phoneStatusTypePort:"Port",phoneStatusProcessing:"Processing",phoneStatusComplete:"Complete",phoneStatusTemporary:"Temporary"},splash:{title:"Welcome\nto {platformName}",subtitle:"Let's get your business set up in 3 easy steps",start:"Start Onboarding",step1:"Account Details",step2:"Setup Phone Numbers",step3:"Assign Hardware"}},dialPlan:{title:"Dial Plan",loading:"Loading dial plan...",error:"Failed to load dial plan",empty:"No dial plan found",nodeTypes:{start:"Start",schedule:"Schedule",internalDial:"Internal Extension",voicemail:"Voicemail",externalDial:"External Number",voiceApp:"Voice App",menu:"IVR Menu",audioClip:"Audio Clip",hangUp:"Hang Up"},nodeDescriptions:{menu:"Play prompt and route by keypress",audioClip:"Play an audio clip",hangUp:"End the call"},exits:{open:"Open",closed:"Closed",holiday:"Holiday",next:"Next",timeout:"Timeout",invalid:"Invalid"},configLabels:{promptClip:"Prompt",audioClip:"Audio Clip",digit:"Digit",options:"Options",addOption:"Add Option",removeOption:"Remove",optionLabel:"Label",optionLabelPlaceholder:"e.g. Sales",routeHolidaySeparately:"Route holidays separately",routeHolidaySeparatelyHint:"When on, holidays route to a dedicated branch you wire below. Otherwise holidays follow the Closed exit."},resourceGroups:{audioClips:"Audio Clips"}}},f=v;
5858
+ "function"==typeof SuppressedError&&SuppressedError;const v={common:{loading:"Loading...",error:"Error",noResults:"No results",delete:"Delete",call:"Call",cancel:"Cancel",confirm:"Confirm",previous:"Previous",next:"Next",perPage:"Per page",showing:"Showing {start}-{end} of {total}",play:"Play",pause:"Pause"},softphone:{title:"Softphone",destinationPlaceholder:"Enter a number",call:"Call",backspace:"Delete",connecting:"Connecting…",reconnecting:"Reconnecting…",disconnected:"Disconnected",connectionError:"Connection error",callError:"Call failed",micPermissionError:"Microphone access is required — allow it and try again",dismiss:"Dismiss",unknownCaller:"Unknown",incomingCall:"Incoming call",answer:"Answer",decline:"Decline",hangUp:"Hang up",mute:"Mute",unmute:"Unmute",hold:"Hold",resume:"Resume",keypad:"Keypad",transfer:"Transfer",transferPlaceholder:"Transfer to…",transferSend:"Transfer",transferNow:"Transfer now",transferConsult:"Consult first",transferComplete:"Complete transfer",transferConsulting:"Consulting…",transferOriginalOnHold:"On hold",addCall:"Add call",addCallPlaceholder:"Number to dial",addCallSend:"Call",merge:"Merge calls",split:"Split",conferenceLabel:"Conference",cancel:"Cancel",stateTrying:"Calling…",stateRinging:"Ringing…",stateActive:"In call",stateHeld:"On hold",stateEnded:"Call ended",done:"Done",audioDevices:"Audio",audioMicrophone:"Microphone",audioSpeaker:"Speaker",audioSystemDefault:"System default",audioUnnamedDevice:"Unnamed device",audioLabelsHidden:"Allow microphone access to see device names",audioDevicesUnsupported:"This browser cannot list audio devices",audioSpeakerUnsupported:"Choose your speaker in your device settings",audioMicrophoneLost:"Your microphone was disconnected — choose another",switchToCall:"Switch to this call",heldCallsLabel:"On hold",callWaiting:"Call waiting",emergencyPrompt:"Set your emergency location",emergencyHint:"Confirm your location before placing calls — required by 911 regulations for internet calling.",emergencyConfirm:"Yes, I'm here",emergencyNewLocation:"Set a new location",emergencyUseLocation:"Use my current location",emergencyLocating:"Getting your location…",emergencyNumber:"Number",emergencyStreet:"Street",emergencyUnit:"Unit (optional)",emergencyCity:"City",emergencyState:"State",emergencyPostalCode:"Postal code",emergencySave:"Confirm location",emergencySaving:"Saving…",emergencyBack:"Back"},aiAgent:{loading:"Loading Managed VoiceAI agent…",loadFailed:"Failed to load Managed VoiceAI agent: {message}",fields:{name:"Name",namePlaceholder:"Front Desk Agent",nameHint:"Internal label shown in lists and call logs. Not heard by callers.",extensionNumber:"Extension",extensionNumberPlaceholder:"700",extensionNumberHint:"Dial this extension from any phone on the account to reach the agent.",extensionChecking:"Checking extension...",personaName:"Persona name",personaNamePlaceholder:"e.g. Receptionist",personaNameHint:"How the agent introduces itself on calls.",greetingName:"Greeting name",greetingNamePlaceholder:"Your business name",greetingNameHintWithName:'Used in the call greeting (e.g. "Thanks for calling {name}").',greetingNameHintGeneric:'Used in the call greeting (e.g. "Thanks for calling [your business]").',instructions:"Instructions",instructionsPlaceholder:"Provide additional instructions for how the Managed VoiceAI agent should behave during calls...",instructionsHint:"Plain-English guidance for the agent: tone, what to do, what to escalate.",faq:"FAQ",faqEmpty:"No FAQ entries yet. Add one to teach the agent a recurring question.",faqEntry:"Entry {index}",faqQuestion:"Question",faqAnswer:"Answer",faqQuestionLabel:"FAQ entry {index} question",faqAnswerLabel:"FAQ entry {index} answer",faqRemove:"Remove",faqRemoveLabel:"Remove FAQ entry {index}",faqAdd:"Add FAQ entry",scheduling:"Scheduling",schedulingHint:"Connect your Managed VoiceAI agent to an external scheduling system. Clear the URL to disable scheduling.",webhookUrl:"Webhook URL",webhookUrlHint:"Base URL for scheduling webhooks. DialStack appends tool-call paths automatically.",webhookUrlPlaceholder:"https://example.com/api/dialstack/webhooks",secret:"Webhook secret",secretHint:"Used to verify tool-call webhooks sent from this Managed VoiceAI agent to your integration.",copySecret:"Copy webhook secret",rotateSecret:"Rotate secret"},save:"Save",saving:"Saving…",saved:"Saved.",errors:{nameRequired:"Name is required.",nameMaxLength:"Name must be {max} characters or fewer.",personaNameMaxLength:"Persona name must be {max} characters or fewer.",greetingNameMaxLength:"Greeting name must be {max} characters or fewer.",instructionsMaxLength:"Instructions must be {max} characters or fewer.",faqMaxItems:"FAQ supports up to {max} entries.",faqIncompleteEntry:"Every FAQ entry needs both a question and an answer.",faqFieldMaxLength:"FAQ fields must be {max} characters or fewer.",extensionNumeric:"Extension must contain only digits.",extensionUnavailable:"Extension number is already in use.",schedulingUrlMaxLength:"Webhook URL must be {max} characters or fewer.",schedulingUrlHttpsRequired:"Webhook URL must start with https://.",hostCreateRequired:"This form is waiting for the host app to create the Managed VoiceAI agent.",hostSaveRequired:"This form is waiting for the host app to save the Managed VoiceAI agent."}},voicemails:{title:"Voicemails",loading:"Loading voicemails...",empty:"No voicemails",noUserId:"Please set a user ID to load voicemails",transcription:"Transcription",summary:"Summary",sentiment:"Sentiment",sentimentPositive:"Positive",sentimentNeutral:"Neutral",sentimentNegative:"Negative",sentimentMixed:"Mixed",transcript:"Full Transcript",transcriptLoading:"Loading transcript...",transcriptNotAvailable:"Transcript not available",deleteConfirm:"Delete this voicemail?",deleteTitle:"Delete Voicemail",progress:"Playback progress"},callLogs:{title:"Call Logs",loading:"Loading call logs...",empty:"No call logs found",columns:{date:"Date",direction:"Direction",from:"From",to:"To",duration:"Duration",status:"Status",quality:"MOS"},directions:{inbound:"Inbound",outbound:"Outbound",internal:"Internal"},routedTo:"Routed to:",calledBy:"Called by:",statuses:{completed:"Completed",noAnswer:"No Answer",busy:"Busy",failed:"Failed",voicemail:"Voicemail"},quality:{good:"Good",fair:"Fair",poor:"Poor",unavailable:"N/A",unavailableTooltip:"No quality data available"}},callHistory:{title:"Call History",loading:"Loading call history...",empty:"No call history",noPhoneNumber:"Please set a phone number to load call history",error:"Unable to load call history",clickToCall:"Click to call",summaryNotAvailable:"Summary not available",relativeTime:{justNow:"Just now",minuteAgo:"1 min ago",minutesAgo:"{count} min ago",hourAgo:"1 hour ago",hoursAgo:"{count} hours ago",yesterday:"Yesterday"}},phoneNumberOrdering:{title:"Order Phone Numbers",steps:{search:"Search",select:"Select",confirm:"Confirm",route:"Route",done:"Done",stepOf:"Step {current} of {total}"},search:{title:"Search Available Numbers",subtitle:"Find available phone numbers by entering an area code or ZIP code.",searchType:"Search by",areaCode:"Area Code",zip:"ZIP Code",areaCodeLabel:"Area Code",areaCodePlaceholder:"e.g. 212",zipLabel:"ZIP Code",zipPlaceholder:"e.g. 10001",numberOfResults:"Quantity to display",search:"Search"},results:{title:"Available Numbers",phoneNumber:"Phone Number",state:"State",selectAll:"Select all",selected:"{count} selected",noResults:"No numbers available for this search",continue:"Continue",backToSearch:"Back to Search"},confirm:{title:"Confirm Order",subtitleOne:"You are about to order 1 phone number",subtitleOther:"You are about to order {count} phone numbers",description:"Your order will be submitted to the carrier for fulfillment. This usually completes within seconds but may take longer.",placeOrder:"Place Order",continue:"Continue",back:"Back",billing:{label:"Billing impact",headline:"Adds {amount}/month to this account's bill",detail:"{count} phone numbers at {rate} each per month.",detail_one:"{count} phone number at {rate} per month.",detail_other:"{count} phone numbers at {rate} each per month.",timing:"Billing starts when each number activates.",taxesAndFees:"Taxes and fees are additional.",noPrice:"These numbers are billable on this account.",noPrice_one:"This number is billable on this account.",noPrice_other:"These numbers are billable on this account.",notBilled:"This account is not billed, so ordering these numbers costs nothing."}},route:{title:"Choose call routing",subtitle:"Pick where these numbers should send calls once they activate. You can change this any time, or set it up later.",later:"Set up routing later",laterHint:"Configure each number from its detail page after it activates.",noTargets:"No routing destinations exist yet. You can set up routing after the numbers are added.",unnamed:"Untitled",extension:"ext. {ext}",back:"Back",type:{user:"User",dial_plan:"Dial plan",voice_app:"Voice app",queue:"Queue",ring_group:"Ring group",shared_voicemail:"Shared voicemail"}},ordering:{title:"Placing Order..."},complete:{titlePendingOne:"Order Submitted",titlePendingOther:"Order Submitted",titleCompleteOne:"Number Ready",titleCompleteOther:"Numbers Ready",titlePartialOne:"Partially Fulfilled",titlePartialOther:"Partially Fulfilled",descriptionPendingOne:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",descriptionPendingOther:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",descriptionCompleteOne:"Your phone number is now in your inventory and ready to be configured.",descriptionCompleteOther:"Your phone numbers are now in your inventory and ready to be configured.",descriptionPartialOne:"Some numbers could not be fulfilled by the carrier.",descriptionPartialOther:"Some numbers could not be fulfilled by the carrier.",checking:"Checking order status...",assignmentHint:"Numbers added to your inventory still need to be assigned to an extension or dial plan before they can receive calls.",orderMore:"Order More Numbers"},error:{title:"Order Failed",description:"The carrier was unable to fulfill your order.",tryAgain:"Try Again"},statuses:{pending:"Pending",complete:"Complete",partial:"Partial",failed:"Failed"}},phoneNumbers:{title:"Phone Numbers",loading:"Loading phone numbers...",empty:"No phone numbers",filterLabel:"Filter by status",search:{placeholder:"Search phone numbers...",noResults:"No phone numbers match your search"},filters:{active:"Active",in_progress:"In Progress",cancelled:"Cancelled"},columns:{phoneNumber:"Phone Number",status:"Status",callerID:"Outbound Caller ID",callerIDPrefix:"Inbound Caller ID Prefix",outbound:"Usage",carrier:"Carrier",transferDate:"Transfer Date",routingTarget:"Call Routing",cancelledDate:"Date Cancelled"},statuses:{active:"Active",inactive:"Inactive",released:"Released",ordering:"Ordering",orderFailed:"Order Failed",portingDraft:"Port Draft",portingApproved:"Ready to Submit",portingSubmitted:"Port Submitted",portingException:"Port Issue",portingFoc:"Port Scheduled"},badges:{temporary:"Temporary"},outbound:{enabled:"Two-way",disabled:"Inbound only",fax:"Fax"},routingTarget:{notSet:"Not set",setAction:"Set routing",faxNotApplicable:"Not applicable"},routingTargetTypes:{user:"User",dialPlan:"Dial Plan",voiceApp:"Voice App",ringGroup:"Ring Group"}},accountOnboarding:{billing:{label:"Billing impact",headline:"Adds {amount}/month to this account's bill",detail:{userSeat:{one:"{count} user seat at {rate} per month.",other:"{count} user seats at {rate} each per month."},phoneNumber:{one:"{count} phone number at {rate} per month.",other:"{count} phone numbers at {rate} each per month."}},noPrice:{userSeat:{one:"Adds {count} billable user seat to this account.",other:"Adds {count} billable user seats to this account."},phoneNumber:{one:"Adds {count} billable phone number to this account.",other:"Adds {count} billable phone numbers to this account."}},rateHeadline:{userSeat:"{rate}/month per user seat",phoneNumber:"{rate}/month per phone number"},rateDetail:{userSeat:"Each team member you add is billed at this rate.",phoneNumber:"Each number you add is billed at this rate."},noPriceRate:{userSeat:"Each team member you add is billable on this account.",phoneNumber:"Each number you add is billable on this account."},startsOnActivation:"Billing starts when each number activates.",taxesAndFees:"Taxes and fees are additional.",notBilled:"This account is not billed, so this costs nothing."},title:"Account Onboarding",breadcrumbAriaLabel:"Onboarding progress",loading:"Loading...",error:{title:"Unable to Load",description:"Something went wrong loading the onboarding wizard.",retry:"Try Again"},steps:{account:"Account Setup",numbers:"Phone Numbers",hardware:"Hardware Setup",complete:"Complete"},sidebar:{businessDetails:"Business Details",businessDetailsDesc:"Enter your company information",teamMembers:"Team Members",teamMembersDesc:"Add users and assign extensions",numberOptions:"Number Options",numberOptionsDesc:"Choose to port existing or get new numbers",callerId:"Caller ID",callerIdDesc:"Set caller ID for your numbers",directoryListing:"Directory Listing",directoryListingDesc:"Configure 411 directory listing",numberSetup:"Number Setup",numberSetupDesc:"Configure your phone numbers",verification:"Verification",verificationDesc:"Verify number status",deviceAssignment:"Device Assignment",deviceAssignmentDesc:"Assign devices to users"},account:{title:"Business Details",subtitle:"Enter your company information",details:{heading:"Account Details",companyNameLabel:"Company Name",companyNamePlaceholder:"Acme Corp",companyNameRequired:"Company name is required",emailLabel:"Primary Contact Email",emailPlaceholder:"admin@company.com",emailRequired:"Primary contact email is required",emailInvalid:"Enter a valid email address",phoneLabel:"Primary Contact Phone Number",phonePlaceholder:"(555) 123-4567",phoneRequired:"Primary contact phone number is required",phoneInvalid:"Enter a valid US phone number",primaryContactLabel:"Primary Contact",primaryContactPlaceholder:"Jane Doe",primaryContactRequired:"Primary contact is required",regionLabel:"Region",regionPlaceholder:"Select a region",timezoneLabel:"Timezone",timezonePlaceholder:"Select a timezone",timezoneRequired:"Timezone is required"},users:{heading:"Team Members",description:"Add users who will have phone extensions. Administrators without phone service are listed too.",nameLabel:"Full name",namePlaceholder:"John Doe",nameRequired:"Name is required",emailLabel:"Email",emailPlaceholder:"john@company.com",extensionLabel:"Extension",extensionPlaceholder:"ex. 103",addUser:"Add User",removeUser:"Remove",removePhoneAccess:"Remove phone access",adminBadge:"Admin",noUsers:"No team members added yet.",atLeastOne:"Add at least one team member to continue.",duplicateEmail:"A user with this email already exists.",extensionRequired:"Extension is required",extensionTaken:"This extension is already in use. Choose another.",noPhoneService:"No phone service",givePhoneAccess:"Give phone access",givingPhoneAccess:"Adding…"},location:{heading:"Business Location",description:"Add your business address for E911 and caller ID.",nameLabel:"Location Name",namePlaceholder:"Main Office",nameRequired:"Location name is required",addressLabel:"Address",searchPlaceholder:"Start typing an address...",searching:"Searching...",noResults:"No addresses found",enterManually:"Enter manually",searchInstead:"Search instead",edit:"Edit",addressRequired:"Address is required",houseNumberLabel:"#",houseNumberPlaceholder:"123",streetLabel:"Street",streetPlaceholder:"Main St",cityLabel:"City",cityPlaceholder:"New York",stateLabel:"State",statePlaceholder:"Select",postalCodeLabel:"ZIP",postalCodePlaceholder:"10001"},saving:"Saving...",saveError:"Failed to save. Please try again."},numbers:{title:"Phone Numbers",subtitle:"Choose how you'd like to set up your business numbers",defaultDialPlanName:"Onboarding Dial Plan",callerId:{title:"Caller ID Setup",subtitle:"Configure the name displayed when making outbound calls",inputLabel:"Caller ID Name",inputPlaceholder:"e.g. ACME Corp",inputHelp:"Max 15 characters. Letters, numbers, spaces, and hyphens only.",charCount:"{count}/15",submit:"Set Caller ID",submitting:"Submitting...",submittingAll:"Submitting caller IDs...",submitted:"Submitted",alreadySet:"Already configured",submitAll:"Set All Caller IDs",skipCallerId:"Skip",partialError:"Some caller IDs could not be set. Fix errors and retry, or skip.",validation:{required:"Caller ID name is required",tooLong:"Must be 15 characters or fewer",invalidChars:"Only letters, numbers, spaces, and hyphens allowed"},error:{submitFailed:"Failed to set caller ID. Please try again.",conflict:"A caller ID update is already in progress for this number."},directoryListing:{title:"Directory Listing (DA/DL)",info:"To update your directory listing, contact {platformName} support."},noDIDs:"No active phone numbers to configure."},directoryListing:{title:"Directory Listing",subtitle:"A directory listing feeds your business information into online directories and data aggregators, helping customers find you. It also reduces the chance of your outbound calls being flagged as spam by call-screening apps.",selectPrompt:"Select which number should be listed:",noneOption:"None — skip directory listing",noDIDs:"No eligible phone numbers to configure.",businessName:"Business Name",businessNamePlaceholder:"Enter business name for listing",businessNameHelp:"The name shown in directory listings and used for caller verification. Max 200 characters.",validation:{nameRequired:"Business name is required for the directory listing."}},overview:{heading:"Your Numbers",empty:"No telephone numbers yet. Request new numbers or port your existing ones.",requestNew:"Request New Numbers",requestNewDesc:"Get new business phone numbers instantly. Choose from available numbers in your area.",portExisting:"Port Existing Number",portExistingDesc:"Transfer your current business number to {platformName}. This typically takes 5–10 business days.",phoneNumber:"Phone Number",type:"Type",status:"Status",source:"Source",temporaryBanner:"A temporary number has been assigned to your account while you set up your permanent numbers.",loadError:"Failed to load telephone numbers. Please try again.",retry:"Retry"},status:{active:"Active",inactive:"Inactive",released:"Released",ordering:"Ordering",order_failed:"Order Failed",porting_draft:"Port Draft",porting_submitted:"Port Submitted",porting_exception:"Port Exception",porting_foc:"Port Scheduled",porting_approved:"Ready to Submit"},source:{did:"Account",didTemporary:"Temporary",number_order:"New Order",port_order:"Port"},order:{searchTitle:"Search Available Numbers",searchSubtitle:"Find available numbers by entering an area code or ZIP code",searchByAreaCode:"Area Code",searchByZip:"ZIP Code",areaCodeLabel:"Area Code",areaCodePlaceholder:"212",zipLabel:"ZIP Code",zipPlaceholder:"10001",quantityLabel:"Quantity",search:"Search",searching:"Searching...",resultsTitle:"Available Numbers",resultsSubtitle:"Select the numbers you would like to order.",noResults:"No numbers found. Try a different search.",selectAll:"Select All",deselectAll:"Deselect All",selected:"selected",state:"State",confirmTitle:"Confirm Your Order",confirmSubtitle:"You are about to order {count} phone numbers",confirmSubtitle_one:"You are about to order {count} phone number",confirmSubtitle_other:"You are about to order {count} phone numbers",carrierNote:"Your order will be submitted to the carrier for fulfillment. This usually completes within seconds but may take longer.",placeOrder:"Place Order",placing:"Placing Order...",ordering:"Ordering...",statusTitle:"Order Submitted",statusPending:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",statusStalled:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",statusComplete:"Your numbers have been activated.",statusFailed:"The order could not be completed.",statusPartial:"Some numbers were activated, but others failed.",done:"Done",orderMore:"Order More Numbers",continue:"Continue",error:"An error occurred while placing the order."},port:{numbersTitle:"Numbers to Port",numbersSubtitle:"Enter the numbers you want to transfer to {platformName}, or paste a whole list into any row.",phoneLabel:"Phone Number",phonePlaceholder:"(555) 123-4567",addAnother:"Add another number",numberLabel:"Phone number {row}",removeNumber:"Remove phone number {row}",duplicateOfRow:"Duplicate of row {row}",pasteHint:"Press Enter for another row. Pasting a list — one per line, commas, or a spreadsheet column — fills a row for each number.",readyCountZero:"No numbers yet",readyCountOne:"{count} number ready",readyCountOther:"{count} numbers ready",needsAttentionOne:"{count} row needs attention before you can continue",needsAttentionOther:"{count} rows need attention before you can continue",reasonInvalid:"Not a valid US phone number",reasonNotUs:"Only US numbers can be ported",reasonTollFree:"Toll-free numbers cannot be ported",reasonAmbiguous:"Too many digits for one number — if this is several, put one per row",reasonHasExtension:"Remove the extension",maxPerOrder:"{count} numbers — the maximum is {max} per order. Move {excess} into a second port order.",notPortableWithDetail:"{label} ({detail})",accountLimit:"You've reached the number of phone numbers this account can hold. Contact support to raise the limit, then try again.",numbersUnavailable:"Some of these numbers are already in use and can't be ported. The ones affected are marked above.",conflictAlreadyOnAccount:"You already have this number",conflictInServiceElsewhere:"Already in service — contact support to transfer it",checkEligibility:"Check Eligibility",checking:"Checking...",eligibilityTitle:"Port Eligibility",eligibilitySubtitle:"Review which numbers can be ported.",portable:"Portable",notPortable:"Not Portable",carrier:"Current Carrier",wireless:"Wireless",wirelessYes:"Yes",wirelessNo:"No",accountRequired:"Account # Required",continueWithPortable:"Continue with Portable Numbers",noPortable:"None of the entered numbers are eligible for porting.",subscriberTitle:"Subscriber Information",subscriberSubtitle:"Enter the details exactly as they appear on your current phone bill.",btnLabel:"Billing Telephone Number (BTN)",btnPlaceholder:"(555) 123-4567",businessNameLabel:"Business Name",businessNamePlaceholder:"Acme Corp",approverNameLabel:"Authorized Contact",approverNamePlaceholder:"John Doe",accountNumberLabel:"Account Number",accountNumberPlaceholder:"From your current carrier",pinLabel:"Account PIN",pinPlaceholder:"1234",addressHeading:"Service Address",houseNumberLabel:"Street Number",houseNumberPlaceholder:"123",streetNameLabel:"Street Name",streetNamePlaceholder:"Main St",line2Label:"Suite / Unit",line2Placeholder:"Suite 100",cityLabel:"City",cityPlaceholder:"New York",stateLabel:"State",statePlaceholder:"Select state",zipLabel:"ZIP Code",zipPlaceholder:"10001",focTitle:"Requested Port Date",focSubtitle:"Choose when you want the numbers transferred. Must be at least 5 business days out.",focDateLabel:"Port Date",focTimeLabel:"Port Time ({zone})",focTimePlaceholder:"Select time",documentsTitle:"Supporting Documents",documentsSubtitle:"Upload your latest phone bill and optionally a Customer Service Record (CSR).",billCopyLabel:"Phone Bill Copy",billCopyDesc:"A recent bill from your current carrier showing the numbers to be ported.",billCopyRequired:"Required",csrLabel:"Customer Service Record (CSR)",csrDesc:"Optional but recommended — speeds up the porting process.",csrOptional:"Optional",uploadFile:"Choose File",fileSelected:"Selected:",noFileSelected:"No file selected",uploading:"Uploading...",reviewTitle:"Review & Approve",reviewSubtitle:"Verify all details before submitting your port request.",numbersSection:"Numbers",subscriberSection:"Subscriber",focSection:"Port Date",documentsSection:"Documents",signatureLabel:"Electronic Signature",signaturePlaceholder:"Type your full legal name",signatureHelp:"By signing, you authorize the transfer of the listed numbers to {platformName}.",approve:"Approve & Submit",submitting:"Submitting...",submittedTitle:"Port Request Submitted",submittedSubtitle:"Your port request has been submitted and is being processed.",submittedStatus:"Status",backToOverview:"Back to Numbers",carrierGroupsTitle:"Carrier Groups",carrierGroupsSubtitle:"Your numbers are with different carriers. Each carrier requires a separate port request.",carrierStart:"Start",carrierContinue:"Continue",carrierSubmitted:"Submitted",numberSingular:"number",numberPlural:"numbers"},validation:{areaCodeRequired:"Area code is required.",areaCodeFormat:"Enter a 3-digit area code.",cityRequired:"City is required.",stateRequired:"State is required.",zipRequired:"ZIP code is required.",zipFormat:"Enter a 5-digit ZIP code.",selectAtLeastOne:"Select at least one number.",phoneRequired:"At least one phone number is required.",phoneInvalid:"Enter a valid US phone number.",phoneDuplicate:"This number has already been entered.",btnRequired:"BTN is required.",btnInvalid:"Enter a valid US phone number.",businessNameRequired:"Business name is required.",approverNameRequired:"Authorized contact name is required.",houseNumberRequired:"Street number is required.",streetNameRequired:"Street name is required.",focDateRequired:"Port date is required.",focDateTooSoon:"Port date must be at least 5 business days from today.",focDateTooFar:"Port date must be within 30 days.",focTimeRequired:"Port time is required.",focTimeOutOfWindow:"Choose a time between {start} and {end} {zone}.",billCopyRequired:"A phone bill copy is required.",signatureRequired:"Signature is required.",eligibilityError:"Failed to check eligibility. Please try again.",submitError:"Failed to submit port request. Please try again."},nav:{back:"Back",next:"Next",cancel:"Cancel",backToSearch:"Back to Search",confirm:"Confirm"},gate:{noDIDsAvailable:"You need at least one phone number before selecting a primary number. Order or port a number first.",primaryRequired:"Please select a primary number to continue."}},hardware:{title:"Assign Devices",shippingAddress:"Shipping Address",subtitle:"Drag and drop devices to assign them to team members",noUsers:"No team members found. Add team members in the Account step first.",noDevices:"No devices are available for your account at the moment.",isDectBase:"This is a cordless handset base station",userLabel:"Team Member",selectUser:"Select a team member",selectUserRequired:"Please select a team member.",macLabel:"MAC Address",macPlaceholder:"00:04:13:AA:BB:CC",invalidMac:"Enter a valid 12-digit MAC address.",ipeiLabel:"Handset IPEI",ipeiPlaceholder:"03AABB1234567890CCDD",invalidIpei:"Enter a valid IPEI (hex digits only).",ipeiNotMac:"This looks like a MAC address, not an IPEI. An IPEI looks like 03AABB1234567890CCDD.",removeDevice:"Remove",unsupportedVendor:"This device is not currently supported. Our support team has been notified and will follow up.",duplicateMac:"This MAC address is already registered.",deviceNotFound:"Device was created but could not be found. Please try again.",handset:"handset",handsets:"handsets",addDeviceButton:"+ Add Device",addHandsetButton:"+ Handset",save:"Save",saving:"Saving...",cancel:"Cancel",dectBase:"Cordless Base",removeBaseFailed:"Failed to remove cordless base.",tableHeaderName:"Full name",tableHeaderExtension:"Extension",tableHeaderDevice:"Assigned Device",availableDevices:"Available Devices",allAssigned:"All devices have been assigned",dragDropHint:"Drag and drop device here",clickToAssign:"Click to assign",submitOrder:"Submit Order",assignAndComplete:"Save & Continue",unassign:"Unassign",deskPhone:"Desk phone",cordless:"Cordless",submitting:"Submitting...",gate:{noDevices:"No devices are available for your account. Please contact support to add devices before completing this step."}},complete:{title:"Wahoo!",subtitle:"It's time to start using your embedded voice system",e911:{loading:"Configuring emergency services...",pollingStatus:"Verifying emergency services registration...",verified:"E911 emergency address is verified.",processing:"E911 registration is being processed. This may take a few minutes.",pendingAfterPolling:"E911 registration submitted. Your phone service is active — emergency address verification will complete shortly.",addressStandardized:"Your address was standardized for emergency services accuracy.",primaryAssigned:"assigned as primary number for",errorTitle:"E911 configuration failed",errorDescription:"There was an error configuring emergency services. You can retry or configure manually later.",retryButton:"Retry",deferred:"E911 emergency services have not been fully configured. Each location with a phone number needs a verified emergency address before your phone service can be activated."}},stepComplete:{title:"{stepName} Complete",subtitle:"This step has been completed successfully.",done:"Done"},nav:{next:"Next",skip:"Skip",back:"Back",exit:"Finish"},legal:{prefix:"By continuing, you agree to the",and:"and",termsOfService:"Terms of Service",recipientTerms:"Recipient Terms of Service",privacyPolicy:"Privacy Policy"},ssa:{title:"Review and accept your subscription agreement",intro:"Before you can use your phone service, please review the Service Subscription Agreement below — including its emergency calling (911/E911) terms — and confirm your acceptance.",pricingTitle:"Your plan pricing",perUser:"Per user",perNumber:"Per phone number",perAiLocation:"Managed VoiceAI, per location",perMonthSuffix:"/mo",agreementLabel:"Service Subscription Agreement",openInNewTab:"Open the full agreement in a new tab",accept:"Accept & Continue",submitting:"Recording your acceptance…",notPermitted:"Only the account owner can accept this agreement. Please ask them to sign in and accept it — phone service requires their signature.",errors:{stale:"The agreement was updated. Please review the latest version and accept again.",pricingMissing:"Your plan pricing has not been finalized yet. Please contact your provider to continue.",generic:"We could not record your acceptance. Please try again.",retry:"Try again"},loadError:{title:"Unable to load your agreement",description:"We could not load your subscription agreement, which is required before you can continue. Please try again.",retry:"Try again",retrying:"Loading…"}}},onboardingPortal:{onboardingFlows:"ONBOARDING FLOWS",saveAndExit:"Save & Exit to Overview",back:"Back",helpSupport:"Help & Support",onboardingComplete:"Onboarding complete",rates:{title:"Your monthly rates",subtitle:"What you're billed at today.",perUser:"Per user",perPhoneNumber:"Per phone number",perVoiceAiLocation:"Managed VoiceAI, per location",voiceAiPerLocationNote:"Charged for every location once Managed VoiceAI is active.",perMonth:"{rate}/month",rateNotSet:"Not set",pendingRate:"{rate}/month from {date}",pendingNote:"Rate changes take effect at the start of the next billing period.",taxesAndFees:"Taxes and fees are additional.",notBilled:"This account is not billed.",noRates:"No rates are set for this account yet.",unavailable:"Rates are unavailable right now."},overview:{label:"Overview",title:"Your Business Onboarding",subtitle:"Complete the steps below to set up your business phone system",progressTitle:"Onboarding Progress",flowsComplete:"{completed} of {total} flows complete",stepsTitle:"Onboarding Steps",complete:"Complete",progress:"Progress",completeSetup:"Complete Setup",continueSetup:"Continue Setup",review:"Review",needHelp:"Need help?",needHelpSubtitle:"Our team is here to help you get set up quickly",scheduleCall:"Schedule a Call",viewDocs:"View Documentation",accountDesc:"Set up your business profile, add team members, and configure your dial plan",numbersDesc:"Port existing numbers or request new business lines",hardwareDesc:"Assign phones to team members and track delivery",phoneStatusTitle:"Phone number status",phoneStatusSubtitle:"Track the status of your phone numbers",phoneStatusNumber:"Phone Number",phoneStatusType:"Type",phoneStatusStatus:"Status",phoneStatusTypeNew:"New",phoneStatusTypePort:"Port",phoneStatusProcessing:"Processing",phoneStatusComplete:"Complete",phoneStatusTemporary:"Temporary"},splash:{title:"Welcome\nto {platformName}",subtitle:"Let's get your business set up in 3 easy steps",start:"Start Onboarding",step1:"Account Details",step2:"Setup Phone Numbers",step3:"Assign Hardware"}},dialPlan:{title:"Dial Plan",loading:"Loading dial plan...",error:"Failed to load dial plan",empty:"No dial plan found",nodeTypes:{start:"Start",schedule:"Schedule",internalDial:"Internal Extension",voicemail:"Voicemail",externalDial:"External Number",voiceApp:"Voice App",menu:"IVR Menu",audioClip:"Audio Clip",hangUp:"Hang Up"},nodeDescriptions:{menu:"Play prompt and route by keypress",audioClip:"Play an audio clip",hangUp:"End the call"},exits:{open:"Open",closed:"Closed",holiday:"Holiday",next:"Next",timeout:"Timeout",invalid:"Invalid"},configLabels:{promptClip:"Prompt",audioClip:"Audio Clip",digit:"Digit",options:"Options",addOption:"Add Option",removeOption:"Remove",optionLabel:"Label",optionLabelPlaceholder:"e.g. Sales",routeHolidaySeparately:"Route holidays separately",routeHolidaySeparatelyHint:"When on, holidays route to a dedicated branch you wire below. Otherwise holidays follow the Closed exit."},resourceGroups:{audioClips:"Audio Clips"}}},f=v;
5783
5859
 
5784
5860
  const SoftphoneContext = createContext(null);
5785
5861
  // Stands in for the phone while `usePhone` has none — before the first construct