fix(tier2-g): warmer Gate copy, generic example, plain-language advanced controls
Round-three pass on the Gate card based on the latest UX feedback. - Tagline: "Keeps your guest list yours" -> "Only your guests get in" - Walk-through example now uses a neutral placeholder name (Sam) instead of "Aunty Patience". GuestGuard's audience is wedding couples, corporate planners, and party hosts as much as family organisers, and Sam is at home in any of those contexts. - The four-step "How does the Gate work?" expander was lightly rewritten for warmth and to remove em-dashes; the mechanism it describes is unchanged. - Advanced strictness controls now open with a real explanation rather than a one-liner about "band thresholds". The intro maps the three sliders to the three reactions (watch / flag / refuse), explains what the 0-100 numbers mean, and reassures hosts that the presets above are still fine for almost everyone. Each slider also gets a one-line caption tying its level dot (green / amber / red) to the user-visible effect. - The trusted-networks "What this is and isn't" panel had its quotes unwound into natural sentences; the empty-state copy was rewritten in the second person; "No decisions to review yet" reworded. - Pass through every user-visible string and replaced em-dashes with periods, commas, or natural rephrasing. Em-dashes only remain in code comments now (developer-facing, not on screen). No behaviour changes; no backend changes; no API changes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -53,7 +53,7 @@ const PRESETS: Preset[] = [
|
||||
{
|
||||
id: 'relaxed',
|
||||
label: 'Relaxed',
|
||||
description: "Casual party — fine if friends share their link with each other.",
|
||||
description: "Casual party. It's fine if a few friends share their link with each other.",
|
||||
medium: 50, high: 80, block: 95,
|
||||
},
|
||||
{
|
||||
@@ -65,7 +65,7 @@ const PRESETS: Preset[] = [
|
||||
{
|
||||
id: 'strict',
|
||||
label: 'Strict',
|
||||
description: "Wedding or private event — uninvited plus-ones are a problem and the guest list matters.",
|
||||
description: "Wedding or private event. Uninvited plus-ones are a problem and the guest list really matters.",
|
||||
medium: 25, high: 50, block: 70,
|
||||
},
|
||||
{
|
||||
@@ -270,30 +270,30 @@ function verdictLabel(v: string) {
|
||||
<header class="mb-3 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">Gate</h2>
|
||||
<p class="text-xs text-zinc-500">Keeps your guest list yours.</p>
|
||||
<p class="text-xs text-zinc-500">Only your guests get in.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Value-prop paragraph. This is the *point* of the feature in plain
|
||||
words. The user named the actual pain ("preventing multiple sharing
|
||||
of events to uninvited guests") — that phrase lives here verbatim. -->
|
||||
<!-- Value-prop paragraph. Plain language, no em-dashes, no example
|
||||
names. Hits the actual pain (forwarded / shared invitation
|
||||
links) head-on. -->
|
||||
<div class="mb-4 rounded-lg border border-brand-700/40 bg-brand-500/[0.04] p-4 text-sm leading-relaxed">
|
||||
<p class="text-zinc-200">
|
||||
Every guest gets their own personal invitation link — only meant for them.
|
||||
The <strong class="text-brand-300">Gate</strong> watches each link in the
|
||||
background and stops <strong>forwarded or shared invitations</strong>
|
||||
from being used by people who weren't on your list.
|
||||
Every guest gets their own personal invitation link. Only one person was meant to use it.
|
||||
The <strong class="text-brand-300">Gate</strong> quietly watches each link, so when
|
||||
someone forwards or shares an invitation, the people it ends up with can't actually use it.
|
||||
</p>
|
||||
<p class="mt-2 text-xs text-zinc-400">
|
||||
Real invited guests don't notice it. You don't need to set anything up
|
||||
for it to work — the Gate is on by default with sensible settings.
|
||||
Your invited guests won't notice a thing. There's nothing you need to set up for this
|
||||
to work; the Gate runs in the background with sensible defaults from the moment your
|
||||
event is live.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- "How does this work?" — collapsed by default so the page stays
|
||||
scannable. The expander walks through the actual mechanism in
|
||||
plain language so curious / sceptical hosts can see what we're
|
||||
doing without reading docs. -->
|
||||
scannable. Plain-language walkthrough; uses a generic placeholder
|
||||
name (Sam) rather than family vocabulary so the example fits
|
||||
wedding couples, party hosts, and corporate planners equally. -->
|
||||
<details class="group mb-6 rounded-lg border border-zinc-800 bg-zinc-950">
|
||||
<summary class="flex cursor-pointer items-center justify-between p-3 text-sm font-medium text-zinc-200">
|
||||
<span class="flex items-center gap-2">
|
||||
@@ -307,46 +307,49 @@ function verdictLabel(v: string) {
|
||||
</svg>
|
||||
</summary>
|
||||
<div class="space-y-3 border-t border-zinc-900 p-4 text-sm text-zinc-300">
|
||||
<p class="text-zinc-400">
|
||||
Here's the short version, using "Sam" as a stand-in for any one of your invited guests.
|
||||
</p>
|
||||
<ol class="space-y-3">
|
||||
<li class="flex gap-3">
|
||||
<span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-brand-500/15 text-xs font-semibold text-brand-300">1</span>
|
||||
<p>
|
||||
When you send Aunty Patience her invitation, she gets her own personal link.
|
||||
That link only belongs to her.
|
||||
When you send Sam an invitation, the link inside it is just for Sam. Nobody else
|
||||
has the same link.
|
||||
</p>
|
||||
</li>
|
||||
<li class="flex gap-3">
|
||||
<span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-brand-500/15 text-xs font-semibold text-brand-300">2</span>
|
||||
<p>
|
||||
The first time Aunty opens her link, the Gate quietly remembers a few details:
|
||||
her phone or browser, the general area she connected from, and the network shape.
|
||||
That becomes her "I'm me" signature.
|
||||
The first time Sam opens it, the Gate quietly notes a few details about the visit:
|
||||
the phone or browser Sam is on, roughly where Sam is in the world, and the kind of
|
||||
network Sam is connected to. Together those become Sam's "this is really me" picture.
|
||||
</p>
|
||||
</li>
|
||||
<li class="flex gap-3">
|
||||
<span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-brand-500/15 text-xs font-semibold text-brand-300">3</span>
|
||||
<p>
|
||||
Every time someone clicks Aunty's link after that — including Aunty herself —
|
||||
the Gate compares them to her signature. Same phone, similar location?
|
||||
They sail through. No signature yet? They become Aunty's signature on the first visit.
|
||||
Every later click on Sam's link, including Sam coming back to update their reply,
|
||||
gets compared to that first visit. If it looks like the same person, they go straight
|
||||
through with no friction at all.
|
||||
</p>
|
||||
</li>
|
||||
<li class="flex gap-3">
|
||||
<span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-brand-500/15 text-xs font-semibold text-brand-300">4</span>
|
||||
<p>
|
||||
If someone with a totally different phone on a totally different network tries to
|
||||
use Aunty's link — like a friend Aunty forwarded it to — the Gate notices. Depending
|
||||
on your strictness setting it'll either flag them for your review, or refuse them
|
||||
outright.
|
||||
If a completely different device on a completely different network tries to use Sam's
|
||||
link, say because Sam forwarded it to a friend, the Gate notices. Depending on how
|
||||
strict you've set it, the Gate will either flag that click for you to review, or stop
|
||||
the RSVP from going through at all.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
<p class="rounded-md border border-zinc-800 bg-zinc-900/60 p-3 text-xs text-zinc-400">
|
||||
<strong class="text-zinc-300">Worth knowing:</strong> guests can switch from mobile data
|
||||
to Wi-Fi or change rooms without being flagged — the Gate only cares about
|
||||
<em>meaningful</em> differences from the original visit, not normal day-to-day variation.
|
||||
If a real guest does ever get flagged (it happens), you can clear them with one click
|
||||
in <em>Recent reviews</em> below.
|
||||
<strong class="text-zinc-300">Worth knowing:</strong> guests can switch between Wi-Fi
|
||||
and mobile data, change rooms, or open their link a few days later without being
|
||||
flagged. The Gate only cares about <em>meaningful</em> differences from that first
|
||||
visit, not normal day-to-day variation. And if a real guest of yours ever does end up
|
||||
flagged, you can clear them with one click under <em>Recent reviews</em> below.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
@@ -393,7 +396,11 @@ function verdictLabel(v: string) {
|
||||
You're running with custom strictness settings (set under Advanced).
|
||||
</p>
|
||||
|
||||
<!-- Advanced — sliders for power users who want to dial individual bands. -->
|
||||
<!-- Advanced — three sliders that map directly to the engine's
|
||||
band thresholds. Heavy intro copy is intentional: most
|
||||
hosts who open this are curious rather than expert, and a
|
||||
short plain-language explanation here keeps them from
|
||||
feeling lost. -->
|
||||
<details class="group mt-4 rounded-lg border border-zinc-800 bg-zinc-950">
|
||||
<summary class="flex cursor-pointer items-center justify-between p-3 text-sm text-zinc-300">
|
||||
<span>Advanced strictness controls</span>
|
||||
@@ -402,40 +409,70 @@ function verdictLabel(v: string) {
|
||||
</svg>
|
||||
</summary>
|
||||
<div class="space-y-4 border-t border-zinc-900 p-4">
|
||||
<p class="text-xs text-zinc-500">
|
||||
These directly drive the band thresholds (0–100). The presets above just write
|
||||
sensible triples for you.
|
||||
<div class="space-y-2 text-xs text-zinc-400">
|
||||
<p class="text-zinc-300">
|
||||
For most hosts, the four presets above are all you need. These sliders are
|
||||
here if you want to fine-tune exactly when each reaction kicks in.
|
||||
</p>
|
||||
<p>
|
||||
As a click on a guest's link looks more and more different from their first
|
||||
visit, the Gate moves through three reactions: watch silently, flag for your
|
||||
review, or refuse the RSVP. The numbers below (from 0 to 100) are how much
|
||||
difference is enough to trigger each one. Lower numbers make the Gate more
|
||||
sensitive; higher numbers make it more forgiving.
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||||
<label class="block text-sm">
|
||||
<span class="mb-1 flex items-center justify-between text-xs text-zinc-400">
|
||||
<span>Watch from</span>
|
||||
<span class="flex items-center gap-1.5">
|
||||
<span class="inline-block h-2 w-2 rounded-full bg-brand-500"></span>
|
||||
Watch from
|
||||
</span>
|
||||
<span class="font-mono tabular-nums text-zinc-300">{{ thresholds.medium }}</span>
|
||||
</span>
|
||||
<input v-model.number="thresholds.medium" type="range" min="0" max="100"
|
||||
:disabled="!canEdit" class="w-full accent-brand-500"
|
||||
@change="saveThresholds()"
|
||||
@input="clampOrder('medium')" />
|
||||
<p class="mt-1 text-[11px] leading-snug text-zinc-500">
|
||||
When the Gate starts paying closer attention. Quiet for guests; visible only
|
||||
to you in activity logs.
|
||||
</p>
|
||||
</label>
|
||||
<label class="block text-sm">
|
||||
<span class="mb-1 flex items-center justify-between text-xs text-zinc-400">
|
||||
<span>Flag from</span>
|
||||
<span class="flex items-center gap-1.5">
|
||||
<span class="inline-block h-2 w-2 rounded-full bg-amber-500"></span>
|
||||
Flag from
|
||||
</span>
|
||||
<span class="font-mono tabular-nums text-zinc-300">{{ thresholds.high }}</span>
|
||||
</span>
|
||||
<input v-model.number="thresholds.high" type="range" min="0" max="100"
|
||||
:disabled="!canEdit" class="w-full accent-amber-500"
|
||||
@change="saveThresholds()"
|
||||
@input="clampOrder('high')" />
|
||||
<p class="mt-1 text-[11px] leading-snug text-zinc-500">
|
||||
When the Gate marks the click for your review. The RSVP still goes through;
|
||||
you decide whether to clear it or flag the guest.
|
||||
</p>
|
||||
</label>
|
||||
<label class="block text-sm">
|
||||
<span class="mb-1 flex items-center justify-between text-xs text-zinc-400">
|
||||
<span>Refuse from</span>
|
||||
<span class="flex items-center gap-1.5">
|
||||
<span class="inline-block h-2 w-2 rounded-full bg-red-500"></span>
|
||||
Refuse from
|
||||
</span>
|
||||
<span class="font-mono tabular-nums text-zinc-300">{{ thresholds.block }}</span>
|
||||
</span>
|
||||
<input v-model.number="thresholds.block" type="range" min="0" max="100"
|
||||
:disabled="!canEdit" class="w-full accent-red-500"
|
||||
@change="saveThresholds()"
|
||||
@input="clampOrder('block')" />
|
||||
<p class="mt-1 text-[11px] leading-snug text-zinc-500">
|
||||
Where the Gate refuses the RSVP outright. The visitor sees a polite "this
|
||||
invitation can't be used" and you get a notification.
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -459,15 +496,17 @@ function verdictLabel(v: string) {
|
||||
<strong>What this is and isn't:</strong>
|
||||
</p>
|
||||
<p class="mb-2">
|
||||
Adding a network here tells the Gate "always wave through clicks coming from
|
||||
this Wi-Fi — they're already with me." It's useful when you're hosting at home
|
||||
or the office and your guests will connect through your network.
|
||||
Adding a network here tells the Gate to always wave through clicks coming from
|
||||
that Wi-Fi, because the people on it are already with you. It's useful when
|
||||
you're hosting at home or in the office and your guests will be on your network
|
||||
when they reply.
|
||||
</p>
|
||||
<p>
|
||||
<strong class="text-zinc-300">It doesn't change how anyone else is treated.</strong>
|
||||
Guests connecting from their own homes, mobile data, or anywhere else still get
|
||||
the regular check — they're not suspected of anything by default. The Gate works
|
||||
perfectly well with this list empty.
|
||||
Guests connecting from their own homes, from mobile data, or from anywhere else
|
||||
still get the regular check. They aren't suspected of anything just because they
|
||||
aren't on your network. The Gate works perfectly well with this list empty, and
|
||||
most events stay that way.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -547,7 +586,7 @@ function verdictLabel(v: string) {
|
||||
</li>
|
||||
</ul>
|
||||
<p v-else class="text-sm text-zinc-500">
|
||||
No trusted networks — and that's fine. The Gate is doing its job.
|
||||
You haven't added any trusted networks, and that's fine. The Gate is still doing its job.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -577,7 +616,7 @@ function verdictLabel(v: string) {
|
||||
and {{ feedback.length - 10 }} more.
|
||||
</li>
|
||||
</ul>
|
||||
<p v-else class="text-sm text-zinc-500">No decisions to review yet — the gate hasn't flagged anyone.</p>
|
||||
<p v-else class="text-sm text-zinc-500">Nothing to review yet. The Gate hasn't flagged anyone.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user