diff --git a/app/src/main/java/app/closer/MainActivity.kt b/app/src/main/java/app/closer/MainActivity.kt
index 865e4091..8df9ff4e 100644
--- a/app/src/main/java/app/closer/MainActivity.kt
+++ b/app/src/main/java/app/closer/MainActivity.kt
@@ -316,7 +316,7 @@ private fun BiometricLockScreen(activity: AppCompatActivity, onUnlocked: () -> U
}
).authenticate(
BiometricPrompt.PromptInfo.Builder()
- .setTitle("Unlock Closer")
+ .setTitle("Unlock Closer Couples")
.setSubtitle("Verify it's you to continue")
.setAllowedAuthenticators(
BiometricManager.Authenticators.BIOMETRIC_STRONG or
diff --git a/app/src/main/java/app/closer/ui/brand/CloserCopy.kt b/app/src/main/java/app/closer/ui/brand/CloserCopy.kt
index 7ff53892..d531b279 100644
--- a/app/src/main/java/app/closer/ui/brand/CloserCopy.kt
+++ b/app/src/main/java/app/closer/ui/brand/CloserCopy.kt
@@ -36,11 +36,11 @@ object CloserCopy {
object Paywall {
const val headline = "Go deeper together"
- const val subhead = "Unlock everything Closer has built for couples."
+ const val subhead = "Unlock everything Closer Couples has built for you."
const val choosePlanTitle = "Choose your plan"
const val coupleShared = "One subscription covers you both — treat your partner."
const val thankYouTitle = "You're all set"
- const val thankYouBody = "Thank you for supporting Closer."
+ const val thankYouBody = "Thank you for supporting Closer Couples."
}
object Subscription {
@@ -53,9 +53,9 @@ object CloserCopy {
* error was triplicated verbatim. Two disclaimer variants are intentionally distinct
* (brief on sign-up, with-reason on the DOB step) — kept separate, not unified. */
object AgeGate {
- const val disclaimer = "Closer is an 18+ app."
- const val disclaimerWithReason = "Closer is an 18+ app. We ask once to confirm your age."
+ const val disclaimer = "Closer Couples is an 18+ app."
+ const val disclaimerWithReason = "Closer Couples is an 18+ app. We ask once to confirm your age."
const val dobRequired = "Please enter your date of birth."
- fun ageError(minAge: Int) = "You must be at least $minAge to use Closer."
+ fun ageError(minAge: Int) = "You must be at least $minAge to use Closer Couples."
}
}
diff --git a/app/src/main/java/app/closer/ui/pairing/InviteShareText.kt b/app/src/main/java/app/closer/ui/pairing/InviteShareText.kt
index a8a1b730..d3d928f2 100644
--- a/app/src/main/java/app/closer/ui/pairing/InviteShareText.kt
+++ b/app/src/main/java/app/closer/ui/pairing/InviteShareText.kt
@@ -10,7 +10,7 @@ import app.closer.core.navigation.JoinLink
object InviteShareText {
fun build(code: String): String {
val pretty = code.chunked(3).joinToString(" ")
- return "Let's try Closer together 💜 It's our own private space to actually talk. " +
+ return "Let's try Closer Couples together 💜 It's our own private space to actually talk. " +
"Tap to join me: ${JoinLink.webUrl(code)}\n\n" +
"Or enter this code in the app: $pretty"
}
diff --git a/app/src/main/java/app/closer/ui/pairing/PairPromptScreen.kt b/app/src/main/java/app/closer/ui/pairing/PairPromptScreen.kt
index 1acfa849..95671b42 100644
--- a/app/src/main/java/app/closer/ui/pairing/PairPromptScreen.kt
+++ b/app/src/main/java/app/closer/ui/pairing/PairPromptScreen.kt
@@ -102,7 +102,7 @@ fun PairPromptScreen(
Spacer(Modifier.height(16.dp))
Text(
- text = "Closer is built for two. Connect your partner to unlock everything worth unlocking:",
+ text = "Closer Couples is built for two. Connect your partner to unlock everything worth unlocking:",
style = MaterialTheme.typography.bodyLarge,
color = AuthMuted,
textAlign = TextAlign.Center
diff --git a/app/src/main/java/app/closer/ui/recap/WeeklyRecapShareCard.kt b/app/src/main/java/app/closer/ui/recap/WeeklyRecapShareCard.kt
index 487b44db..7fc09add 100644
--- a/app/src/main/java/app/closer/ui/recap/WeeklyRecapShareCard.kt
+++ b/app/src/main/java/app/closer/ui/recap/WeeklyRecapShareCard.kt
@@ -34,7 +34,7 @@ object WeeklyRecapShareCard {
else -> "We answered $q questions"
}
val reveals = if (r > 0) " and opened $r reveal${if (r == 1) "" else "s"}" else ""
- return "$answered$reveals together this week on Closer 💜"
+ return "$answered$reveals together this week on Closer Couples 💜"
}
/** Renders the card to a bitmap using plain Canvas (no Compose-capture fragility). */
diff --git a/app/src/main/java/app/closer/ui/settings/SettingsScreen.kt b/app/src/main/java/app/closer/ui/settings/SettingsScreen.kt
index 8ab7f68c..ff0a8837 100644
--- a/app/src/main/java/app/closer/ui/settings/SettingsScreen.kt
+++ b/app/src/main/java/app/closer/ui/settings/SettingsScreen.kt
@@ -499,7 +499,7 @@ fun SettingsScreen(
SettingsRow(
icon = CloserGlyphs.Palette,
label = "Appearance",
- subtitle = "Make Closer feel comfortable to open",
+ subtitle = "Make Closer Couples feel comfortable to open",
onClick = { onNavigate(AppRoute.APPEARANCE) }
)
}
@@ -534,7 +534,7 @@ fun SettingsScreen(
SettingsRow(
icon = ImageVector.vectorResource(R.drawable.glyph_delete_account),
label = "Delete account",
- subtitle = "Permanently remove your Closer account",
+ subtitle = "Permanently remove your Closer Couples account",
onClick = { onNavigate(AppRoute.DELETE_ACCOUNT) },
tint = SettingsDanger
)
diff --git a/app/src/main/java/app/closer/widget/TodayWidget.kt b/app/src/main/java/app/closer/widget/TodayWidget.kt
index a6c69015..9f172628 100644
--- a/app/src/main/java/app/closer/widget/TodayWidget.kt
+++ b/app/src/main/java/app/closer/widget/TodayWidget.kt
@@ -92,9 +92,9 @@ private fun TodayWidgetContent(context: Context, snapshot: TodayWidgetSnapshot)
/** Content-free headline derived only from state flags. */
internal fun headlineFor(s: TodayWidgetSnapshot): String = when {
- !s.signedIn -> "Open Closer"
+ !s.signedIn -> "Open Closer Couples"
!s.paired -> "Invite your partner to begin"
- s.appLockEnabled -> "Something's waiting in Closer"
+ s.appLockEnabled -> "Something's waiting in Closer Couples"
else -> when (s.dailyState) {
"USER_ANSWERED_PARTNER_PENDING" -> "Waiting for your partner"
"PARTNER_ANSWERED_USER_PENDING" -> "Your turn — answer to reveal"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b13332d2..6a87229d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -72,8 +72,8 @@
Streak and shared wins
Your couple\'s streak count and challenge completions are shared between both of you.
No data export
- Closer does not currently offer a data export. Your answers and history are deleted along with your account.
- Closer is built on one rule: answers stay private until both of you have answered. Here\'s exactly what that means.
+ Closer Couples does not currently offer a data export. Your answers and history are deleted along with your account.
+ Closer Couples is built on one rule: answers stay private until both of you have answered. Here\'s exactly what that means.
Anonymous usage data
Share anonymous usage data
Helps us see which features couples use — never what you write. Your answers, messages, and prompts are end-to-end encrypted and can\'t be in this data even if we wanted them.
diff --git a/app/src/test/java/app/closer/widget/TodayWidgetTest.kt b/app/src/test/java/app/closer/widget/TodayWidgetTest.kt
index 97a18421..ae2192ce 100644
--- a/app/src/test/java/app/closer/widget/TodayWidgetTest.kt
+++ b/app/src/test/java/app/closer/widget/TodayWidgetTest.kt
@@ -15,7 +15,7 @@ class TodayWidgetTest {
@Test
fun `signed-out shows a neutral open prompt`() {
- assertEquals("Open Closer", headlineFor(snap(signedIn = false)))
+ assertEquals("Open Closer Couples", headlineFor(snap(signedIn = false)))
}
@Test
@@ -26,7 +26,7 @@ class TodayWidgetTest {
@Test
fun `app-lock hides the daily state behind a generic headline`() {
val locked = headlineFor(snap(appLock = true, state = "BOTH_ANSWERED"))
- assertEquals("Something's waiting in Closer", locked)
+ assertEquals("Something's waiting in Closer Couples", locked)
// The specific state must NOT leak when the lock is on.
assertFalse(locked.contains("reveal", ignoreCase = true))
}
diff --git a/docs/NameChange.md b/docs/NameChange.md
index 3bef7860..c0ff17c5 100644
--- a/docs/NameChange.md
+++ b/docs/NameChange.md
@@ -1,7 +1,15 @@
-# App rename: "Closer" → "Closer Couples" (store / marketing tier only)
+# App rename: "Closer" → "Closer Couples"
> Audit + decision record for renaming the product's public name to **"Closer Couples"**.
> Status: **executed in repo.** Store-console changes remain external owner steps.
+>
+> **2026-07-09 extension — in-app prose now renamed.** The original pass was store/marketing only
+> (in-app copy deliberately stayed "Closer"). Owner decision to extend: **in-app *prose* copy now uses
+> "Closer Couples"** across Android + iOS (settings, pairing, invite share, widget headlines, paywall
+> subhead/thank-you, age gate, privacy body, iOS settings/onboarding/pairing). The **launcher label and
+> wordmark logos still stay "Closer"** (owner kept these — truncation under the icon, and the logo is a
+> brand mark). See "What still stays 'Closer'" below. No technical identifiers touched; Android compiles +
+> unit tests green (`TodayWidgetTest` assertions updated).
## Context
@@ -17,12 +25,20 @@ After auditing every occurrence of the name across Android, iOS, images, and doc
Renaming any of these breaks builds / Firebase / the Play listing:
`namespace app.closer` · `applicationId closer.app` · package `app.closer.*` + `class CloserApp` · deep-link host `closer.app` + `closer://` scheme · Firebase `closer-app-22014` (`google-services.json`, `GoogleService-Info.plist`) · iOS `PRODUCT_BUNDLE_IDENTIFIER app.closer.iphone` + `bundleIdPrefix app.closer` + product/target/scheme `Closer` · SPM package `Closer` · Gradle `rootProject.name "Closer"` · resource filenames (`closer_launcher_*`, `ic_notification_closer`, `ic_launcher*`) · XML styles `Theme.Closer[.Splash]` · entitlement id `closer_premium` · crypto AAD constants.
-## What does NOT change (per the chosen tier)
+## What still stays "Closer" (after the 2026-07-09 prose extension)
-- **Android launcher label** — `app/src/main/res/values/strings.xml` → `app_name` stays **"Closer"**.
+- **Android launcher label** — `app/src/main/res/values/strings.xml` → `app_name` stays **"Closer"** (14-char "Closer Couples" truncates under the icon).
- **iOS home-screen label** — `iphone/Closer/Info.plist` → `CFBundleDisplayName` stays **"Closer"** (`CFBundleName`/`PRODUCT_NAME` untouched).
-- **All ~25 in-app copy strings** stay "Closer" (paywall, onboarding/age-gate, settings, widget, invite share text, privacy `strings.xml:95-96`, share card, iOS onboarding, etc.).
-- **Wordmark logos** (onboarding, auth alt-text, widget, share card) stay "Closer" → their asserting tests stay green, untouched.
+- **Wordmark logos** (onboarding `OnboardingScreen`/iOS `OnboardingViews`, auth alt-text `AuthVisuals`, `TodayWidget` header, `WeeklyRecapShareCard` drawText) stay "Closer" → the logo is a brand mark; their asserting tests (`FirstRunRenderSmokeTest` contentDescription, recap/widget tests) stay green.
+- **Deliberate copy exceptions that stay "Closer":** the **"Grow Closer"** onboarding headline (intimacy pun, not the app name); the privacy-rotator slogan *"…so Closer cannot read them"* and iOS *"not even Closer's servers"* (entity references; the rotator line also has a hard 64-char display cap that "Closer Couples" would exceed — `CloserBrandCopyTest`); the iOS **"Settings > Closer"** help path (must match the kept `CFBundleDisplayName`); and the **"Closer Premium"** tier label (matches the RevenueCat entitlement display name).
+- **Internal engineering/brand-system docs** using "Closer" as codename/design-system name (`DEVELOPMENT_LOG.md`, `SECURITY.md`, `Future.md`, `Engineering_Reference_Manual`, `Claude*.md`, brand-system docs).
+
+## In-app prose renamed to "Closer Couples" (2026-07-09)
+
+The ~26 user-facing strings where "Closer" names the app in a sentence now read "Closer Couples":
+
+- **Android (9 files):** `CloserCopy` (paywall subhead reworded to avoid "Couples…couples", thank-you, age-gate ×3), `InviteShareText`, `PairPromptScreen`, `SettingsScreen` (appearance + delete-account subtitles), `TodayWidget` (Open / "Something's waiting" headlines — header wordmark kept), `MainActivity` biometric prompt, `WeeklyRecapShareCard` caption (drawText wordmark kept), `strings.xml` (`privacy_no_export_body`, `privacy_rule_intro`). `TodayWidgetTest` exact-match assertions updated.
+- **iOS (2 files):** `SettingsViews` (profile/account/data-export/legal/help/premium-eligibility/paywall subhead), `PairingViews` explore line.
- **Internal engineering/brand-system docs** using "Closer" as codename/design-system name (`DEVELOPMENT_LOG.md`, `SECURITY.md`, `Future.md`, `Engineering_Reference_Manual`, the `Claude*.md` reports, `docs/brand/asset-system.md` "Closer Artwork Asset System", `docs/brand/generated-art/glyphs/README.md` "Closer G-set").
## Changes to make (in-repo)
diff --git a/iphone/Closer/Pairing/PairingViews.swift b/iphone/Closer/Pairing/PairingViews.swift
index 1db869fe..dabb7f1a 100644
--- a/iphone/Closer/Pairing/PairingViews.swift
+++ b/iphone/Closer/Pairing/PairingViews.swift
@@ -28,7 +28,7 @@ struct PairPromptView: View {
)
.closerPadding()
- Text("You can keep exploring Closer, but shared reveals and partner activity start after your person joins.")
+ Text("You can keep exploring Closer Couples, but shared reveals and partner activity start after your person joins.")
.font(CloserFont.footnote)
.foregroundColor(.closerTextSecondary)
.multilineTextAlignment(.center)
diff --git a/iphone/Closer/Settings/SettingsViews.swift b/iphone/Closer/Settings/SettingsViews.swift
index ca5ef75d..238f512d 100644
--- a/iphone/Closer/Settings/SettingsViews.swift
+++ b/iphone/Closer/Settings/SettingsViews.swift
@@ -28,7 +28,7 @@ struct SettingsView: View {
SettingsProfileHeader(
initials: initials,
name: appState.currentUser?.displayName ?? "You",
- detail: "Create an account to save your Closer space",
+ detail: "Create an account to save your Closer Couples space",
imageUrl: appState.currentUser?.photoUrl
)
}
@@ -54,7 +54,7 @@ struct SettingsView: View {
SettingsLinkRow(
icon: "heart.fill",
title: "Connected with \(partner.displayName.isEmpty ? "Partner" : partner.displayName)",
- subtitle: "Your shared Closer space is active",
+ subtitle: "Your shared Closer Couples space is active",
tint: .closerPrimary,
imageUrl: partner.photoUrl,
showsChevron: false
@@ -124,7 +124,7 @@ struct SettingsView: View {
SettingsLinkRow(
icon: "square.and.arrow.up",
title: "Export Data",
- subtitle: "Download a copy of your Closer data"
+ subtitle: "Download a copy of your Closer Couples data"
)
}
.buttonStyle(.plain)
@@ -150,7 +150,7 @@ struct SettingsView: View {
SettingsLinkRow(
icon: "doc.text",
title: "Terms of Service",
- subtitle: "The agreement for using Closer"
+ subtitle: "The agreement for using Closer Couples"
)
}
.buttonStyle(.plain)
@@ -177,7 +177,7 @@ struct SettingsView: View {
SettingsLinkRow(
icon: "envelope",
title: "Contact Us",
- subtitle: "Get help from the Closer team"
+ subtitle: "Get help from the Closer Couples team"
)
}
.buttonStyle(.plain)
@@ -207,7 +207,7 @@ struct SettingsView: View {
SettingsLinkRow(
icon: "trash",
title: "Delete Account",
- subtitle: "Permanently remove your Closer account",
+ subtitle: "Permanently remove your Closer Couples account",
tint: .closerDanger,
isDestructive: true,
showsChevron: false
@@ -407,7 +407,7 @@ struct DataExportView: View {
.font(CloserFont.title2)
.foregroundColor(.closerText)
- Text("Download a copy of all your Closer data including answers, memories, and preferences.")
+ Text("Download a copy of all your Closer Couples data including answers, memories, and preferences.")
.font(CloserFont.callout)
.foregroundColor(.closerTextSecondary)
.multilineTextAlignment(.center)
@@ -580,7 +580,7 @@ struct PairingHelpView: View {
BulletPoint("Codes expire after a set time — generate a new one if needed")
BulletPoint("Each account can only be in one couple at a time")
- BulletPoint("Both of you need a Closer account first")
+ BulletPoint("Both of you need a Closer Couples account first")
}
.closerPadding()
}
@@ -704,7 +704,7 @@ struct PaywallView: View {
.foregroundColor(.closerText)
.multilineTextAlignment(.center)
- Text("Unlock everything Closer has built for couples.")
+ Text("Unlock everything Closer Couples has built for you.")
.font(CloserFont.callout)
.foregroundColor(.closerTextSecondary)
.multilineTextAlignment(.center)