@the-portland-company/shell 0.98.0 → 0.99.0

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.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PageHeaderProps, B as BreadcrumbBarProps, N as NavItem } from './index-CUPeC2Ji.cjs';
2
- export { A as AI_CREDITS_STATE_TITLES, a as AiCreditsState, b as AiCreditsStateKind, C as Card, c as CommsNotification, d as CommsNotificationKind, F as FormColumn, H as HeaderTabBar, e as HeaderTabBarItem, K as KNOWN_TAB_GLYPHS, f as NotificationsAdapter, g as NotificationsFeed, R as RowMenu, h as RowMenuItem, i as RowMenuPlacement, T as TabGlyphComponent, V as VRM_TIER_LABELS, j as VRM_VERIFIED_TOOLTIP, k as VrmVerifiedBadge, l as VrmVerifiedBadgeProps, m as VrmVerifiedTier, n as aiCreditsWalletUrl, o as createCommsNotificationsAdapter, p as emptyNotificationsFeed, q as normalizeNotificationsFeed, r as resolveTabGlyph, s as rowMenuPosition } from './index-CUPeC2Ji.cjs';
1
+ import { P as PageHeaderProps, B as BreadcrumbBarProps, N as NavItem } from './index-DhrhpBVm.cjs';
2
+ export { A as AI_CREDITS_STATE_TITLES, a as AiCreditsState, b as AiCreditsStateKind, C as CONTACTS_ORIGIN, c as Card, d as CommsNotification, e as CommsNotificationKind, f as ContactSlideIn, g as ContactSlideInProps, F as FormColumn, H as HeaderTabBar, h as HeaderTabBarItem, K as KNOWN_TAB_GLYPHS, i as NotificationsAdapter, j as NotificationsFeed, R as RowMenu, k as RowMenuItem, l as RowMenuPlacement, T as TabGlyphComponent, V as VRM_TIER_LABELS, m as VRM_VERIFIED_TOOLTIP, n as VrmVerifiedBadge, o as VrmVerifiedBadgeProps, p as VrmVerifiedTier, q as aiCreditsWalletUrl, r as contactEmbedUrl, s as contactPageUrl, t as createCommsNotificationsAdapter, u as emptyNotificationsFeed, v as normalizeNotificationsFeed, w as resolveTabGlyph, x as rowMenuPosition, y as useContactSlideIn } from './index-DhrhpBVm.cjs';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import * as react from 'react';
5
5
  import { ReactNode, CSSProperties } from 'react';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PageHeaderProps, B as BreadcrumbBarProps, N as NavItem } from './index-DAD6tSfV.js';
2
- export { A as AI_CREDITS_STATE_TITLES, a as AiCreditsState, b as AiCreditsStateKind, C as Card, c as CommsNotification, d as CommsNotificationKind, F as FormColumn, H as HeaderTabBar, e as HeaderTabBarItem, K as KNOWN_TAB_GLYPHS, f as NotificationsAdapter, g as NotificationsFeed, R as RowMenu, h as RowMenuItem, i as RowMenuPlacement, T as TabGlyphComponent, V as VRM_TIER_LABELS, j as VRM_VERIFIED_TOOLTIP, k as VrmVerifiedBadge, l as VrmVerifiedBadgeProps, m as VrmVerifiedTier, n as aiCreditsWalletUrl, o as createCommsNotificationsAdapter, p as emptyNotificationsFeed, q as normalizeNotificationsFeed, r as resolveTabGlyph, s as rowMenuPosition } from './index-DAD6tSfV.js';
1
+ import { P as PageHeaderProps, B as BreadcrumbBarProps, N as NavItem } from './index-Di9AyVsU.js';
2
+ export { A as AI_CREDITS_STATE_TITLES, a as AiCreditsState, b as AiCreditsStateKind, C as CONTACTS_ORIGIN, c as Card, d as CommsNotification, e as CommsNotificationKind, f as ContactSlideIn, g as ContactSlideInProps, F as FormColumn, H as HeaderTabBar, h as HeaderTabBarItem, K as KNOWN_TAB_GLYPHS, i as NotificationsAdapter, j as NotificationsFeed, R as RowMenu, k as RowMenuItem, l as RowMenuPlacement, T as TabGlyphComponent, V as VRM_TIER_LABELS, m as VRM_VERIFIED_TOOLTIP, n as VrmVerifiedBadge, o as VrmVerifiedBadgeProps, p as VrmVerifiedTier, q as aiCreditsWalletUrl, r as contactEmbedUrl, s as contactPageUrl, t as createCommsNotificationsAdapter, u as emptyNotificationsFeed, v as normalizeNotificationsFeed, w as resolveTabGlyph, x as rowMenuPosition, y as useContactSlideIn } from './index-Di9AyVsU.js';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import * as react from 'react';
5
5
  import { ReactNode, CSSProperties } from 'react';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { PageHeaderView, warnDeprecated, BreadcrumbBarView } from './chunk-WOOBPM4V.js';
2
- export { AI_CREDITS_STATE_TITLES, AiCreditsState, Card, FormColumn, HeaderTabBar, KNOWN_TAB_GLYPHS, RowMenu, RowMenuItem, SpeculationRulesScript, VRM_TIER_LABELS, VRM_VERIFIED_TOOLTIP, VrmVerifiedBadge, aiCreditsWalletUrl, buildNavSpeculationRules, buildSpeculationRules, collectSiblingAppUrls, createCommsNotificationsAdapter, emptyNotificationsFeed, normalizeNotificationsFeed, resolveTabGlyph, rowMenuPosition } from './chunk-WOOBPM4V.js';
1
+ import { PageHeaderView, warnDeprecated, BreadcrumbBarView } from './chunk-PQQLCUNO.js';
2
+ export { AI_CREDITS_STATE_TITLES, AiCreditsState, CONTACTS_ORIGIN, Card, ContactSlideIn, FormColumn, HeaderTabBar, KNOWN_TAB_GLYPHS, RowMenu, RowMenuItem, SpeculationRulesScript, VRM_TIER_LABELS, VRM_VERIFIED_TOOLTIP, VrmVerifiedBadge, aiCreditsWalletUrl, buildNavSpeculationRules, buildSpeculationRules, collectSiblingAppUrls, contactEmbedUrl, contactPageUrl, createCommsNotificationsAdapter, emptyNotificationsFeed, normalizeNotificationsFeed, resolveTabGlyph, rowMenuPosition, useContactSlideIn } from './chunk-PQQLCUNO.js';
3
3
  import { readResolvedTheme } from './chunk-BHRVZPZ7.js';
4
4
  export { BRAND_APPLE_ICON_LINK_ID, BRAND_FAVICON_LINK_ID, BrandFavicon, applyBrandFavicon, watchBrandFavicon } from './chunk-Q5DTPY5N.js';
5
5
  import { extendTheme, ChakraProvider, useColorMode } from '@chakra-ui/react';
package/dist/native.cjs CHANGED
@@ -3053,17 +3053,19 @@ var TIER_TOOLTIPS = {
3053
3053
  inactive: "Inactive: the voter file marks this registration inactive or canceled."
3054
3054
  };
3055
3055
  var DOT_FALLBACK = {
3056
+ verified: "#00A651",
3056
3057
  identified: "#a855f7",
3057
3058
  anonymous: "var(--color-graphite, #2b2b2b)",
3058
3059
  stale: "#eab308",
3059
3060
  inactive: "var(--muted, #8a8a8a)"
3060
3061
  };
3061
- function VrmVerifiedBadge({ tier, size, showLabel = true, className, style }) {
3062
- const icon = useBrandAsset("verified-icon");
3062
+ function VrmVerifiedBadge({ tier, variant = "pill", size, showLabel = true, className, style }) {
3063
3063
  const known = tier && tier in VRM_TIER_LABELS ? tier : null;
3064
+ if (variant === "icon") {
3065
+ return known === "verified" ? /* @__PURE__ */ jsxRuntime.jsx(VerifiedIcon, { size: size ?? 16, className, style }) : null;
3066
+ }
3064
3067
  const label = known ? VRM_TIER_LABELS[known] : "Not yet computed";
3065
3068
  const title = known ? TIER_TOOLTIPS[known] : "The VRM Verified tier has not been worked out yet.";
3066
- const iconSize = size ?? 16;
3067
3069
  const dotSize = size ?? 8;
3068
3070
  return /* @__PURE__ */ jsxRuntime.jsxs(
3069
3071
  "span",
@@ -3087,24 +3089,11 @@ function VrmVerifiedBadge({ tier, size, showLabel = true, className, style }) {
3087
3089
  ...style
3088
3090
  },
3089
3091
  children: [
3090
- known === "verified" ? (
3091
- // The box is reserved while the Brand sheet loads; nothing stands in.
3092
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, style: { display: "inline-block", width: iconSize, height: iconSize, flexShrink: 0 }, children: icon ? /* @__PURE__ */ jsxRuntime.jsx(
3093
- "img",
3094
- {
3095
- src: icon,
3096
- alt: "",
3097
- width: iconSize,
3098
- height: iconSize,
3099
- draggable: false,
3100
- "data-testid": "vrm-verified-icon",
3101
- style: { display: "block", width: iconSize, height: iconSize }
3102
- }
3103
- ) : null })
3104
- ) : /* @__PURE__ */ jsxRuntime.jsx(
3092
+ /* @__PURE__ */ jsxRuntime.jsx(
3105
3093
  "span",
3106
3094
  {
3107
3095
  "aria-hidden": true,
3096
+ "data-vrm-dot": true,
3108
3097
  style: {
3109
3098
  display: "inline-block",
3110
3099
  width: dotSize,
@@ -3121,6 +3110,184 @@ function VrmVerifiedBadge({ tier, size, showLabel = true, className, style }) {
3121
3110
  }
3122
3111
  );
3123
3112
  }
3113
+ function VerifiedIcon({ size, className, style }) {
3114
+ const icon = useBrandAsset("verified-icon");
3115
+ return (
3116
+ // The box is reserved while the Brand sheet loads; nothing stands in.
3117
+ /* @__PURE__ */ jsxRuntime.jsx(
3118
+ "span",
3119
+ {
3120
+ "data-vrm-tier": "verified",
3121
+ "data-vrm-variant": "icon",
3122
+ role: "img",
3123
+ "aria-label": VRM_TIER_LABELS.verified,
3124
+ title: VRM_VERIFIED_TOOLTIP,
3125
+ className,
3126
+ style: { display: "inline-block", width: size, height: size, flexShrink: 0, verticalAlign: "middle", ...style },
3127
+ children: icon ? /* @__PURE__ */ jsxRuntime.jsx(
3128
+ "img",
3129
+ {
3130
+ src: icon,
3131
+ alt: "",
3132
+ width: size,
3133
+ height: size,
3134
+ draggable: false,
3135
+ "data-testid": "vrm-verified-icon",
3136
+ style: { display: "block", width: size, height: size }
3137
+ }
3138
+ ) : null
3139
+ }
3140
+ )
3141
+ );
3142
+ }
3143
+ var CONTACTS_ORIGIN = "https://contacts.politogyvrm.com";
3144
+ function withOrg(path, orgId) {
3145
+ return orgId ? `${path}?org=${encodeURIComponent(orgId)}` : path;
3146
+ }
3147
+ function contactEmbedUrl(contactId, orgId, origin = CONTACTS_ORIGIN) {
3148
+ return withOrg(`${origin}/contacts/embed/${encodeURIComponent(contactId)}`, orgId);
3149
+ }
3150
+ function contactPageUrl(contactId, orgId, origin = CONTACTS_ORIGIN) {
3151
+ return withOrg(`${origin}/contacts/${encodeURIComponent(contactId)}`, orgId);
3152
+ }
3153
+ function prefersReducedMotion() {
3154
+ try {
3155
+ return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
3156
+ } catch {
3157
+ return false;
3158
+ }
3159
+ }
3160
+ var iconButton = {
3161
+ display: "inline-flex",
3162
+ alignItems: "center",
3163
+ justifyContent: "center",
3164
+ borderRadius: 9999,
3165
+ border: "1px solid var(--line, #d7dadf)",
3166
+ padding: 6,
3167
+ background: "transparent",
3168
+ color: "var(--muted, #5c6b80)",
3169
+ cursor: "pointer"
3170
+ };
3171
+ function ContactSlideIn({ contactId, orgId, onClose, contactsOrigin = CONTACTS_ORIGIN }) {
3172
+ const [shown, setShown] = react.useState(false);
3173
+ react.useEffect(() => {
3174
+ if (!contactId) {
3175
+ setShown(false);
3176
+ return;
3177
+ }
3178
+ if (prefersReducedMotion()) {
3179
+ setShown(true);
3180
+ return;
3181
+ }
3182
+ const id = requestAnimationFrame(() => setShown(true));
3183
+ return () => cancelAnimationFrame(id);
3184
+ }, [contactId]);
3185
+ react.useEffect(() => {
3186
+ if (!contactId) return;
3187
+ const onKey = (event) => {
3188
+ if (event.key === "Escape") onClose();
3189
+ };
3190
+ document.addEventListener("keydown", onKey);
3191
+ return () => document.removeEventListener("keydown", onKey);
3192
+ }, [contactId, onClose]);
3193
+ if (!contactId) return null;
3194
+ return /* @__PURE__ */ jsxRuntime.jsx(
3195
+ "div",
3196
+ {
3197
+ "data-testid": "contact-slide-in-overlay",
3198
+ onClick: onClose,
3199
+ style: { position: "fixed", inset: 0, zIndex: 60, background: "rgba(0, 0, 0, 0.4)" },
3200
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
3201
+ "aside",
3202
+ {
3203
+ role: "dialog",
3204
+ "aria-modal": "true",
3205
+ "aria-label": "Contact card",
3206
+ "data-testid": "contact-slide-in",
3207
+ onClick: (event) => event.stopPropagation(),
3208
+ style: {
3209
+ position: "absolute",
3210
+ top: 0,
3211
+ right: 0,
3212
+ bottom: 0,
3213
+ width: "100%",
3214
+ maxWidth: 672,
3215
+ display: "flex",
3216
+ flexDirection: "column",
3217
+ background: "var(--panel, #ffffff)",
3218
+ color: "var(--foreground, #2f3136)",
3219
+ borderLeft: "1px solid var(--line, #d7dadf)",
3220
+ boxShadow: "var(--shadow-soft, 0 10px 28px rgba(27, 28, 32, 0.14))",
3221
+ transform: shown ? "translateX(0)" : "translateX(100%)",
3222
+ transition: "transform 220ms cubic-bezier(0.16, 1, 0.3, 1)"
3223
+ },
3224
+ children: [
3225
+ /* @__PURE__ */ jsxRuntime.jsxs(
3226
+ "div",
3227
+ {
3228
+ style: {
3229
+ display: "flex",
3230
+ alignItems: "center",
3231
+ justifyContent: "space-between",
3232
+ gap: 12,
3233
+ borderBottom: "1px solid var(--line, #d7dadf)",
3234
+ padding: "12px 24px"
3235
+ },
3236
+ children: [
3237
+ /* @__PURE__ */ jsxRuntime.jsx(
3238
+ "p",
3239
+ {
3240
+ style: {
3241
+ margin: 0,
3242
+ fontSize: 12,
3243
+ fontWeight: 600,
3244
+ letterSpacing: "0.18em",
3245
+ textTransform: "uppercase",
3246
+ color: "var(--muted, #5c6b80)"
3247
+ },
3248
+ children: "Contact Card"
3249
+ }
3250
+ ),
3251
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
3252
+ /* @__PURE__ */ jsxRuntime.jsx(
3253
+ "a",
3254
+ {
3255
+ href: contactPageUrl(contactId, orgId, contactsOrigin),
3256
+ target: "_top",
3257
+ style: { fontSize: 13, fontWeight: 600, color: "var(--color-race-blue-500, #007bff)", textDecoration: "none" },
3258
+ children: "Open in Contacts"
3259
+ }
3260
+ ),
3261
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "aria-label": "Close contact card", title: "Close", onClick: onClose, style: iconButton, children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": true, width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
3262
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18" }),
3263
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 6 12 12" })
3264
+ ] }) })
3265
+ ] })
3266
+ ]
3267
+ }
3268
+ ),
3269
+ /* @__PURE__ */ jsxRuntime.jsx(
3270
+ "iframe",
3271
+ {
3272
+ title: "Contact card",
3273
+ src: contactEmbedUrl(contactId, orgId, contactsOrigin),
3274
+ "data-testid": "contact-slide-in-frame",
3275
+ style: { flex: 1, minHeight: 0, width: "100%", border: 0, background: "var(--panel, #ffffff)" }
3276
+ },
3277
+ contactId
3278
+ )
3279
+ ]
3280
+ }
3281
+ )
3282
+ }
3283
+ );
3284
+ }
3285
+ function useContactSlideIn() {
3286
+ const [contactId, setContactId] = react.useState(null);
3287
+ const open = react.useCallback((id) => setContactId(id), []);
3288
+ const close = react.useCallback(() => setContactId(null), []);
3289
+ return { contactId, open, close };
3290
+ }
3124
3291
  var standardNavIcons = {
3125
3292
  home: lu.LuHouse,
3126
3293
  users: lu.LuUsers,
@@ -3276,14 +3443,14 @@ var APP_SIGNS_CHILDREN = [
3276
3443
  function standardPolitogyNav(opts) {
3277
3444
  const icon = (key) => opts.icons?.[key] ?? standardNavIcons[key];
3278
3445
  const orgParam = opts.activeOrgId ? `org=${opts.activeOrgId}` : "";
3279
- const withOrg = (url) => orgParam ? `${url}${url.includes("?") ? "&" : "?"}${orgParam}` : url;
3446
+ const withOrg2 = (url) => orgParam ? `${url}${url.includes("?") ? "&" : "?"}${orgParam}` : url;
3280
3447
  const leaves = (origin, children) => appLeaves(origin, children);
3281
3448
  const branches = (origin, children) => {
3282
3449
  const o = origin.replace(/\/+$/, "");
3283
3450
  return children.map((c) => ({
3284
3451
  label: c.label,
3285
3452
  icon: icon(c.icon),
3286
- href: withOrg(`${o}/${c.path}`),
3453
+ href: withOrg2(`${o}/${c.path}`),
3287
3454
  children: c.children ? leaves(origin, c.children) : void 0
3288
3455
  }));
3289
3456
  };
@@ -3292,21 +3459,21 @@ function standardPolitogyNav(opts) {
3292
3459
  return children.map((c) => {
3293
3460
  const url = c.path ? `${base}/${c.path}` : `${base}/`;
3294
3461
  const withMode = modeParam ? `${url}${url.includes("?") ? "&" : "?"}mode=${modeParam}` : url;
3295
- return { label: c.label, icon: icon(c.icon), href: withOrg(withMode) };
3462
+ return { label: c.label, icon: icon(c.icon), href: withOrg2(withMode) };
3296
3463
  });
3297
3464
  };
3298
3465
  const accountRows = () => [
3299
3466
  { kind: "section", label: "Account", railHidden: true },
3300
3467
  // My Profile moved to the Politogy ID account app (auth.politogyvrm.com)
3301
3468
  // with the retirement of app.politogyvrm.com.
3302
- { label: "My profile", icon: icon("circleUser"), href: withOrg(`${AUTH_ORIGIN}my-profile`), railHidden: true },
3469
+ { label: "My profile", icon: icon("circleUser"), href: withOrg2(`${AUTH_ORIGIN}my-profile`), railHidden: true },
3303
3470
  {
3304
3471
  label: "Organization settings",
3305
3472
  icon: icon("settings"),
3306
3473
  railHidden: true,
3307
3474
  // Organization settings moved to the standalone Settings app
3308
3475
  // (settings.politogyvrm.com, Specs/Organization-Settings v12).
3309
- href: withOrg(`${SETTINGS_ORIGIN2}organization-settings`),
3476
+ href: withOrg2(`${SETTINGS_ORIGIN2}organization-settings`),
3310
3477
  children: branches(SETTINGS_ORIGIN2, ORG_SETTINGS_CHILDREN)
3311
3478
  }
3312
3479
  ];
@@ -3320,11 +3487,11 @@ function standardPolitogyNav(opts) {
3320
3487
  } : {
3321
3488
  label: "Contacts",
3322
3489
  icon: icon("usersRound"),
3323
- href: withOrg(`${CONTACTS_APP}/`),
3490
+ href: withOrg2(`${CONTACTS_APP}/`),
3324
3491
  children: APP_CONTACTS_CHILDREN.map((c) => ({
3325
3492
  label: c.label,
3326
3493
  icon: icon(c.icon),
3327
- href: withOrg(c.href)
3494
+ href: withOrg2(c.href)
3328
3495
  }))
3329
3496
  };
3330
3497
  return [
@@ -3336,13 +3503,13 @@ function standardPolitogyNav(opts) {
3336
3503
  // target as active on `/` alone, so a root link left the Dashboard row
3337
3504
  // without its active marker on the Dashboard (Left-Navigation §8.1,
3338
3505
  // §11.3 "exactly one row is active").
3339
- { label: "Dashboard", icon: icon("layoutDashboard"), href: withOrg(`${DASHBOARD_ORIGIN}dashboard`) },
3506
+ { label: "Dashboard", icon: icon("layoutDashboard"), href: withOrg2(`${DASHBOARD_ORIGIN}dashboard`) },
3340
3507
  contacts,
3341
3508
  {
3342
3509
  label: "Email broadcast",
3343
3510
  icon: icon("mail"),
3344
- href: withOrg(`${EMAIL_APP}/dashboard`),
3345
- children: APP_EMAIL_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
3511
+ href: withOrg2(`${EMAIL_APP}/dashboard`),
3512
+ children: APP_EMAIL_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg2(c.href) }))
3346
3513
  },
3347
3514
  {
3348
3515
  // SMS/MMS Blast is the a2p app entered in RELATIONSHIP mode (a2p is
@@ -3351,7 +3518,7 @@ function standardPolitogyNav(opts) {
3351
3518
  // lights up on arrival.
3352
3519
  label: "SMS/MMS blast",
3353
3520
  icon: icon("messageSquare"),
3354
- href: withOrg(`${A2P_ORIGIN}?mode=relationship`),
3521
+ href: withOrg2(`${A2P_ORIGIN}?mode=relationship`),
3355
3522
  children: appLeaves(A2P_ORIGIN, APP_A2P_CHILDREN, "relationship")
3356
3523
  },
3357
3524
  { kind: "section", label: "Collect" },
@@ -3360,20 +3527,20 @@ function standardPolitogyNav(opts) {
3360
3527
  {
3361
3528
  label: "Calls to action",
3362
3529
  icon: icon("mousePointerClick"),
3363
- href: withOrg("https://ctas.politogyvrm.com/"),
3364
- children: APP_CTAS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
3530
+ href: withOrg2("https://ctas.politogyvrm.com/"),
3531
+ children: APP_CTAS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg2(c.href) }))
3365
3532
  },
3366
3533
  {
3367
3534
  label: "Forms",
3368
3535
  icon: icon("fileText"),
3369
- href: withOrg("https://forms.politogyvrm.com/"),
3370
- children: APP_FORMS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
3536
+ href: withOrg2("https://forms.politogyvrm.com/"),
3537
+ children: APP_FORMS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg2(c.href) }))
3371
3538
  },
3372
3539
  {
3373
3540
  label: "Surveys",
3374
3541
  icon: icon("clipboardList"),
3375
- href: withOrg("https://surveys.politogyvrm.com/surveys"),
3376
- children: APP_SURVEYS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
3542
+ href: withOrg2("https://surveys.politogyvrm.com/surveys"),
3543
+ children: APP_SURVEYS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg2(c.href) }))
3377
3544
  },
3378
3545
  // No Polls row here: Polling is a Campaign Mode feature only
3379
3546
  // (Specs/Left-Navigation §9.1 "Polls is not a Relationship row"). Its
@@ -3394,48 +3561,48 @@ function standardPolitogyNav(opts) {
3394
3561
  { kind: "section", label: "Race data" },
3395
3562
  // Battleground is the Campaign Mode landing page, its own app on its own
3396
3563
  // host (registry key `battleground`; Specs/Left-Navigation §9.2, §13, §14).
3397
- { label: "Battleground", icon: icon("crosshair"), href: withOrg(`${BATTLEGROUND_ORIGIN}battleground`) },
3564
+ { label: "Battleground", icon: icon("crosshair"), href: withOrg2(`${BATTLEGROUND_ORIGIN}battleground`) },
3398
3565
  // District Data is its own Campaign Mode app on its own host (registry key `districts`).
3399
- { label: "District data", icon: icon("landmark"), href: withOrg(`${DISTRICTS_ORIGIN}districts`) },
3566
+ { label: "District data", icon: icon("landmark"), href: withOrg2(`${DISTRICTS_ORIGIN}districts`) },
3400
3567
  // Campaign Tribes (Specs/Tribes §2.3–§2.4, Left-Navigation §9.2; decided
3401
3568
  // 2026-10-16, Ben): a page of the Battleground app at /tribes, so it is
3402
3569
  // the only active row there (Battleground's /battleground prefix does
3403
3570
  // not match it). Relationship Tribes stay inside Contacts.
3404
- { label: "Tribes", icon: icon("usersRound"), href: withOrg(`${BATTLEGROUND_ORIGIN}tribes`) },
3571
+ { label: "Tribes", icon: icon("usersRound"), href: withOrg2(`${BATTLEGROUND_ORIGIN}tribes`) },
3405
3572
  { kind: "section", label: "Research" },
3406
3573
  {
3407
3574
  label: "Polling",
3408
3575
  icon: icon("chartNoAxes"),
3409
- href: withOrg(POLLS_ORIGIN),
3410
- children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) })),
3576
+ href: withOrg2(POLLS_ORIGIN),
3577
+ children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg2(c.href) })),
3411
3578
  flag: "polling"
3412
3579
  },
3413
3580
  { kind: "section", label: "GOTV" },
3414
3581
  {
3415
3582
  label: "Field canvassing",
3416
3583
  icon: icon("doorOpen"),
3417
- href: withOrg(CANVASS_ORIGIN),
3584
+ href: withOrg2(CANVASS_ORIGIN),
3418
3585
  children: appLeaves(CANVASS_ORIGIN, APP_CANVASS_CHILDREN),
3419
3586
  flag: "canvass"
3420
3587
  },
3421
3588
  {
3422
3589
  label: "Phone banking",
3423
3590
  icon: icon("phone"),
3424
- href: withOrg(PHONEBANK_ORIGIN),
3591
+ href: withOrg2(PHONEBANK_ORIGIN),
3425
3592
  children: appLeaves(PHONEBANK_ORIGIN, APP_PHONEBANK_CHILDREN),
3426
3593
  flag: "phonebank"
3427
3594
  },
3428
3595
  {
3429
3596
  label: "A2P texting",
3430
3597
  icon: icon("messageSquare"),
3431
- href: withOrg(A2P_ORIGIN),
3598
+ href: withOrg2(A2P_ORIGIN),
3432
3599
  children: appLeaves(A2P_ORIGIN, APP_A2P_CHILDREN),
3433
3600
  flag: "a2p"
3434
3601
  },
3435
3602
  {
3436
3603
  label: "Sign mapping",
3437
3604
  icon: icon("signpost"),
3438
- href: withOrg(SIGNS_ORIGIN),
3605
+ href: withOrg2(SIGNS_ORIGIN),
3439
3606
  children: appLeaves(SIGNS_ORIGIN, APP_SIGNS_CHILDREN),
3440
3607
  flag: "signs"
3441
3608
  },
@@ -3452,9 +3619,9 @@ function standardPolitogyNav(opts) {
3452
3619
  opts.petitionsItem ? {
3453
3620
  label: "Dashboard",
3454
3621
  icon: icon("home"),
3455
- href: opts.petitionsItem.href ?? withOrg(PETITION_MODE_ORIGIN),
3622
+ href: opts.petitionsItem.href ?? withOrg2(PETITION_MODE_ORIGIN),
3456
3623
  children: opts.petitionsItem.children
3457
- } : { label: "Dashboard", icon: icon("home"), href: withOrg(PETITION_MODE_ORIGIN) }
3624
+ } : { label: "Dashboard", icon: icon("home"), href: withOrg2(PETITION_MODE_ORIGIN) }
3458
3625
  ];
3459
3626
  const mode = opts.mode ?? "relationship";
3460
3627
  const built = mode === "campaign" ? buildCampaign() : mode === "petition" ? buildPetition() : buildRelationship();
@@ -5094,11 +5261,13 @@ exports.BETA_BANNER_DISMISS_KEY = BETA_BANNER_DISMISS_KEY;
5094
5261
  exports.BrandFavicon = BrandFavicon;
5095
5262
  exports.BreadcrumbBar = BreadcrumbBar;
5096
5263
  exports.CAMPAIGN_FEATURE_AVAILABILITY = CAMPAIGN_FEATURE_AVAILABILITY;
5264
+ exports.CONTACTS_ORIGIN = CONTACTS_ORIGIN;
5097
5265
  exports.CORE_APP_ORIGIN = CORE_APP_ORIGIN;
5098
5266
  exports.CORE_BILLING_PATH = CORE_BILLING_PATH;
5099
5267
  exports.CREDIT_TYPE_LABELS = CREDIT_TYPE_LABELS;
5100
5268
  exports.CREDIT_TYPE_ORDER = CREDIT_TYPE_ORDER;
5101
5269
  exports.Card = Card;
5270
+ exports.ContactSlideIn = ContactSlideIn;
5102
5271
  exports.CreditsAction = CreditsAction;
5103
5272
  exports.FormColumn = FormColumn;
5104
5273
  exports.FuelAction = FuelAction;
@@ -5134,6 +5303,8 @@ exports.aiCreditsWalletUrl = aiCreditsWalletUrl;
5134
5303
  exports.applyBrandFavicon = applyBrandFavicon;
5135
5304
  exports.buildLineParts = buildLineParts;
5136
5305
  exports.clearBetaBannerDismissal = clearBetaBannerDismissal;
5306
+ exports.contactEmbedUrl = contactEmbedUrl;
5307
+ exports.contactPageUrl = contactPageUrl;
5137
5308
  exports.creditGaugeRatio = creditGaugeRatio;
5138
5309
  exports.creditStateWord = creditStateWord;
5139
5310
  exports.creditTooltipLine = creditTooltipLine;
@@ -5151,6 +5322,7 @@ exports.standardPolitogyNav = standardPolitogyNav;
5151
5322
  exports.topBarIconButtonClass = topBarIconButtonClass;
5152
5323
  exports.useChromeMe = useChromeMe;
5153
5324
  exports.useChromeOrgs = useChromeOrgs;
5325
+ exports.useContactSlideIn = useContactSlideIn;
5154
5326
  exports.useNavChromeDedupedFetch = useNavChromeDedupedFetch;
5155
5327
  exports.useNavChromeFetcher = useNavChromeFetcher;
5156
5328
  exports.useThemePreference = useThemePreference;