ed5d1c0e57eb

reconcile the last chirp-era names: peach-chirp-* CSS classes become peach-pair-*, the three CHIRP_-prefixed device messages drop the prefix, stale comments stop pointing at deleted files, and the dead peach-pair-pro-chirp rule goes (v4.0.37)

time
2026-07-25 01:22 UTC · 3 months ago
machine
koh2
agent
claude-opus-5
session
chirp era naming reconcile
parent
ba8d30d4cb70
10 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/messages.ts+3 −3src/popup/components/PairingBirds.tsx+37 −37src/popup/styles/popup.css+233 −252src/popup/views/PairDevice.test.tsx+1 −1src/popup/views/PairDevice.tsx+23 −23src/popup/views/Settings.tsx+2 −2src/shared/types.ts+3 −3
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "4.0.36",4+  "version": "4.0.37",55   "description": "Zero-knowledge password manager",66   "browser_specific_settings": {77     "gecko": {

view file

manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "4.0.36",4+  "version": "4.0.37",55   "description": "Zero-knowledge password manager",66   "action": {77     "default_popup": "src/popup/index.html",

view file

package.json+1 −1
@@ -1,6 +1,6 @@11 {22   "name": "peach",3-  "version": "4.0.36",3+  "version": "4.0.37",44   "description": "Zero-knowledge password manager",55   "license": "GPL-3.0-only",66   "type": "module",

view file

src/background/messages.ts+3 −3
@@ -1407,12 +1407,12 @@14071407         return { ok: true };14081408       }14091409 1410-      case "CHIRP_LIST_PAIRED_DEVICES": {1410+      case "LIST_PAIRED_DEVICES": {14111411         const devices = await listPairedDevicesV3();14121412         return { ok: true, data: { devices } };14131413       }14141414 1415-      case "CHIRP_UNPAIR_DEVICE": {1415+      case "UNPAIR_DEVICE": {14161416         const { deviceId } = (msg.payload ?? {}) as { deviceId?: string };14171417         if (typeof deviceId !== "string" || !deviceId) {14181418           return { ok: false, error: "invalid_payload" };@@ -1421,7 +1421,7 @@14211421         return { ok: true };14221422       }14231423 1424-      case "CHIRP_RENAME_LOCAL_DEVICE": {1424+      case "RENAME_LOCAL_DEVICE": {14251425         const { name } = (msg.payload ?? {}) as { name?: string };14261426         if (typeof name !== "string") return { ok: false, error: "invalid_payload" };14271427         await setDeviceNameV3(name);

view file

src/popup/components/PairingBirds.tsx+37 −37
@@ -1,9 +1,9 @@11 // Pairing birds — the two illustrated characters used on the pairing screens.22 //3-// These are all that remains of the audio-chirp pairing animation this file is4-// named after: the flow itself was removed with Chirp, but the birds outlived5-// it and still animate above the code-entry, connecting, SAS and paired6-// screens (ChirpSync.tsx's `desktopBirdStage`).3+// These are all that remains of the removed audio-pairing animation: the flow4+// itself went with it, but the birds outlived it and still animate above the5+// code-entry, connecting, SAS and paired screens (PairDevice.tsx's bird stage).6+// The `-chirping` pose names are kept on purpose — the bird visibly chirps.77 88 import { Component } from "solid-js";99 @@ -19,43 +19,43 @@1919 export const DesktopBird: Component<{ pose: string }> = (props) => {2020   const p = FINCH;2121   return (22-    <div class={`peach-chirp-bird peach-chirp-bird-desktop peach-chirp-bird-pose-${props.pose}`}>22+    <div class={`peach-pair-bird peach-pair-bird-desktop peach-pair-bird-pose-${props.pose}`}>2323       <svg viewBox="0 0 160 150" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMax meet">2424         <defs>25-          <radialGradient id="peach-chirp-finch-body" cx="0.42" cy="0.32" r="0.72">25+          <radialGradient id="peach-pair-finch-body" cx="0.42" cy="0.32" r="0.72">2626             <stop offset="0%" stop-color={p.hi} />2727             <stop offset="55%" stop-color={p.mid} />2828             <stop offset="100%" stop-color={p.lo} />2929           </radialGradient>30-          <radialGradient id="peach-chirp-finch-head" cx="0.5" cy="0.4" r="0.7">30+          <radialGradient id="peach-pair-finch-head" cx="0.5" cy="0.4" r="0.7">3131             <stop offset="0%" stop-color={p.hi} />3232             <stop offset="100%" stop-color={p.mid} />3333           </radialGradient>34-          <linearGradient id="peach-chirp-finch-belly" x1="0" y1="0" x2="0" y2="1">34+          <linearGradient id="peach-pair-finch-belly" x1="0" y1="0" x2="0" y2="1">3535             <stop offset="0%" stop-color={p.cream} stop-opacity="0" />3636             <stop offset="50%" stop-color={p.cream} stop-opacity="0.85" />3737             <stop offset="100%" stop-color={p.cream} stop-opacity="0.5" />3838           </linearGradient>3939         </defs>40-        <ellipse class="peach-chirp-bird-shadow" cx="78" cy="138" rx="40" ry="3.5" fill="rgba(0,0,0,0.45)" />41-        <g class="peach-chirp-bird-aura" opacity="0">40+        <ellipse class="peach-pair-bird-shadow" cx="78" cy="138" rx="40" ry="3.5" fill="rgba(0,0,0,0.45)" />41+        <g class="peach-pair-bird-aura" opacity="0">4242           <ellipse cx="76" cy="74" rx="60" ry="46" fill={p.hi} opacity="0.18" style={{ filter: "blur(8px)" }} />4343         </g>44-        <g class="peach-chirp-bird-tail">44+        <g class="peach-pair-bird-tail">4545           <path d="M 32 92 Q 8 90, 6 80 Q 10 95, 28 100 Z" fill={p.lo} />4646           <path d="M 32 95 Q 4 99, 4 92 Q 10 102, 28 102 Z" fill={p.shade} opacity="0.85" />4747           <path d="M 32 98 Q 8 108, 12 110 Q 20 110, 30 105 Z" fill={p.lo} opacity="0.9" />4848         </g>49-        <g class="peach-chirp-bird-feet" stroke={p.legs} stroke-width="1.6" stroke-linecap="round" fill="none">49+        <g class="peach-pair-bird-feet" stroke={p.legs} stroke-width="1.6" stroke-linecap="round" fill="none">5050           <line x1="62" y1="118" x2="60" y2="134" />5151           <path d="M 60 134 L 55 138 M 60 134 L 60 139 M 60 134 L 65 138" stroke-width="1.2" />5252           <line x1="84" y1="118" x2="86" y2="134" />5353           <path d="M 86 134 L 81 138 M 86 134 L 86 139 M 86 134 L 91 138" stroke-width="1.2" />5454         </g>55-        <g class="peach-chirp-bird-body">56-          <path d="M 30 88 C 24 64, 40 38, 72 36 C 105 34, 124 56, 122 84 C 120 110, 100 122, 70 120 C 44 118, 32 108, 30 88 Z" fill="url(#peach-chirp-finch-body)" />57-          <path d="M 40 82 C 42 100, 60 112, 80 110 C 100 108, 110 100, 112 86 C 100 102, 80 106, 60 102 C 50 100, 44 92, 40 82 Z" fill="url(#peach-chirp-finch-belly)" />58-          <g class="peach-chirp-bird-wing">55+        <g class="peach-pair-bird-body">56+          <path d="M 30 88 C 24 64, 40 38, 72 36 C 105 34, 124 56, 122 84 C 120 110, 100 122, 70 120 C 44 118, 32 108, 30 88 Z" fill="url(#peach-pair-finch-body)" />57+          <path d="M 40 82 C 42 100, 60 112, 80 110 C 100 108, 110 100, 112 86 C 100 102, 80 106, 60 102 C 50 100, 44 92, 40 82 Z" fill="url(#peach-pair-finch-belly)" />58+          <g class="peach-pair-bird-wing">5959             <path d="M 56 60 C 68 56, 88 60, 102 68 C 108 76, 106 86, 96 90 C 80 92, 64 86, 54 78 C 50 70, 50 64, 56 60 Z" fill={p.lo} />6060             <g stroke={p.shade} stroke-width="0.7" stroke-linecap="round" fill="none" opacity="0.55">6161               <path d="M 64 64 Q 72 70, 78 80" />@@ -65,20 +65,20 @@6565             <path d="M 56 60 C 68 56, 88 60, 102 68" stroke={p.shade} stroke-width="1" fill="none" opacity="0.4" />6666           </g>6767         </g>68-        <g class="peach-chirp-bird-head-group" style={{ "transform-origin": "95px 52px" }}>69-          <g class="peach-chirp-bird-tuft">68+        <g class="peach-pair-bird-head-group" style={{ "transform-origin": "95px 52px" }}>69+          <g class="peach-pair-bird-tuft">7070             <path d="M 88 22 Q 86 12, 94 12 Q 94 20, 92 26 Z" fill={p.lo} />7171             <path d="M 96 20 Q 96 10, 104 14 Q 102 22, 100 26 Z" fill={p.shade} opacity="0.95" />7272             <path d="M 104 24 Q 108 16, 114 20 Q 110 28, 106 30 Z" fill={p.lo} opacity="0.85" />7373           </g>74-          <circle cx="98" cy="48" r="26" fill="url(#peach-chirp-finch-head)" />74+          <circle cx="98" cy="48" r="26" fill="url(#peach-pair-finch-head)" />7575           <path d="M 76 46 Q 80 30, 96 26 Q 86 32, 80 48 Z" fill={p.shade} opacity="0.35" />76-          <g class="peach-chirp-bird-eye-group">76+          <g class="peach-pair-bird-eye-group">7777             <circle cx="108" cy="42" r="4.5" fill="#1f0a10" />7878             <circle cx="109.4" cy="40.5" r="1.4" fill="rgba(255,240,225,0.95)" />7979             <circle cx="106.5" cy="44" r="0.5" fill="rgba(255,240,225,0.6)" />8080           </g>81-          <g class="peach-chirp-bird-beak" style={{ "transform-origin": "120px 52px" }}>81+          <g class="peach-pair-bird-beak" style={{ "transform-origin": "120px 52px" }}>8282             <path d="M 120 48 L 138 50 L 122 56 Z" fill={p.beak} />8383             <path d="M 120 48 L 138 50 L 128 52 Z" fill={p.beakShade} opacity="0.55" />8484             <path d="M 122 52 L 134 51" stroke={p.beakShade} stroke-width="0.6" opacity="0.6" />@@ -92,42 +92,42 @@9292 export const MobileBird: Component<{ pose: string }> = (props) => {9393   const p = SWALLOW;9494   return (95-    <div class={`peach-chirp-bird peach-chirp-bird-mobile peach-chirp-bird-pose-${props.pose}`}>95+    <div class={`peach-pair-bird peach-pair-bird-mobile peach-pair-bird-pose-${props.pose}`}>9696       <svg viewBox="0 0 160 150" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMax meet" style={{ transform: "scaleX(-1)" }}>9797         <defs>98-          <radialGradient id="peach-chirp-swallow-body" cx="0.55" cy="0.35" r="0.75">98+          <radialGradient id="peach-pair-swallow-body" cx="0.55" cy="0.35" r="0.75">9999             <stop offset="0%" stop-color={p.hi} />100100             <stop offset="50%" stop-color={p.mid} />101101             <stop offset="100%" stop-color={p.lo} />102102           </radialGradient>103-          <radialGradient id="peach-chirp-swallow-head" cx="0.45" cy="0.4" r="0.7">103+          <radialGradient id="peach-pair-swallow-head" cx="0.45" cy="0.4" r="0.7">104104             <stop offset="0%" stop-color={p.hi} />105105             <stop offset="100%" stop-color={p.mid} />106106           </radialGradient>107-          <linearGradient id="peach-chirp-swallow-throat" x1="0" y1="0" x2="0" y2="1">107+          <linearGradient id="peach-pair-swallow-throat" x1="0" y1="0" x2="0" y2="1">108108             <stop offset="0%" stop-color={p.cream} stop-opacity="0.95" />109109             <stop offset="100%" stop-color={p.cream} stop-opacity="0.2" />110110           </linearGradient>111111         </defs>112-        <ellipse class="peach-chirp-bird-shadow" cx="86" cy="140" rx="34" ry="3" fill="rgba(0,0,0,0.45)" />113-        <g class="peach-chirp-bird-aura" opacity="0">112+        <ellipse class="peach-pair-bird-shadow" cx="86" cy="140" rx="34" ry="3" fill="rgba(0,0,0,0.45)" />113+        <g class="peach-pair-bird-aura" opacity="0">114114           <ellipse cx="80" cy="78" rx="60" ry="42" fill={p.hi} opacity="0.18" style={{ filter: "blur(8px)" }} />115115         </g>116-        <g class="peach-chirp-bird-tail">116+        <g class="peach-pair-bird-tail">117117           <path d="M 38 80 Q 8 70, 0 60 Q 8 78, 28 88 Q 14 90, 6 96 Q 16 94, 32 92 L 38 84 Z" fill={p.lo} />118118           <path d="M 30 84 Q 14 78, 6 70 Q 18 84, 30 88 Z" fill={p.shade} opacity="0.7" />119119         </g>120-        <g class="peach-chirp-bird-feet" stroke={p.legs} stroke-width="1.5" stroke-linecap="round" fill="none">120+        <g class="peach-pair-bird-feet" stroke={p.legs} stroke-width="1.5" stroke-linecap="round" fill="none">121121           <line x1="76" y1="118" x2="74" y2="136" />122122           <path d="M 74 136 L 69 140 M 74 136 L 74 141 M 74 136 L 79 140" stroke-width="1.1" />123123           <line x1="96" y1="118" x2="98" y2="136" />124124           <path d="M 98 136 L 93 140 M 98 136 L 98 141 M 98 136 L 103 140" stroke-width="1.1" />125125         </g>126-        <g class="peach-chirp-bird-body">127-          <path d="M 36 82 C 32 56, 56 42, 88 44 C 116 46, 134 60, 134 80 C 134 102, 116 118, 90 118 C 60 118, 40 104, 36 82 Z" fill="url(#peach-chirp-swallow-body)" />126+        <g class="peach-pair-bird-body">127+          <path d="M 36 82 C 32 56, 56 42, 88 44 C 116 46, 134 60, 134 80 C 134 102, 116 118, 90 118 C 60 118, 40 104, 36 82 Z" fill="url(#peach-pair-swallow-body)" />128128           <path d="M 50 64 C 60 52, 80 46, 100 48 C 116 50, 126 60, 128 70 C 120 60, 100 56, 80 60 C 64 64, 56 68, 50 64 Z" fill={p.shade} opacity="0.5" />129-          <path d="M 64 82 C 66 100, 86 114, 102 112 C 116 110, 124 100, 126 88 C 116 102, 100 108, 84 104 C 74 102, 68 94, 64 82 Z" fill="url(#peach-chirp-swallow-throat)" />130-          <g class="peach-chirp-bird-wing">129+          <path d="M 64 82 C 66 100, 86 114, 102 112 C 116 110, 124 100, 126 88 C 116 102, 100 108, 84 104 C 74 102, 68 94, 64 82 Z" fill="url(#peach-pair-swallow-throat)" />130+          <g class="peach-pair-bird-wing">131131             <path d="M 50 70 C 64 64, 84 66, 100 72 C 112 78, 112 90, 100 96 C 84 100, 64 96, 52 88 C 46 80, 46 74, 50 70 Z" fill={p.lo} />132132             <g fill={p.shade} opacity="0.85">133133               <path d="M 96 88 L 110 92 L 100 96 Z" />@@ -142,14 +142,14 @@142142             <path d="M 50 70 C 64 64, 84 66, 100 72" stroke={p.shade} stroke-width="1" fill="none" opacity="0.55" />143143           </g>144144         </g>145-        <g class="peach-chirp-bird-head-group" style={{ "transform-origin": "116px 64px" }}>146-          <circle cx="118" cy="64" r="20" fill="url(#peach-chirp-swallow-head)" />145+        <g class="peach-pair-bird-head-group" style={{ "transform-origin": "116px 64px" }}>146+          <circle cx="118" cy="64" r="20" fill="url(#peach-pair-swallow-head)" />147147           <path d="M 100 60 Q 108 46, 124 46 Q 134 50, 136 60 Q 124 54, 108 60 Z" fill={p.shade} opacity="0.55" />148-          <g class="peach-chirp-bird-eye-group">148+          <g class="peach-pair-bird-eye-group">149149             <circle cx="126" cy="60" r="4" fill="#1f0a10" />150150             <circle cx="127.2" cy="58.8" r="1.2" fill="rgba(255,240,225,0.95)" />151151           </g>152-          <g class="peach-chirp-bird-beak" style={{ "transform-origin": "136px 64px" }}>152+          <g class="peach-pair-bird-beak" style={{ "transform-origin": "136px 64px" }}>153153             <path d="M 136 60 L 154 62 L 138 66 Z" fill={p.beak} />154154             <path d="M 136 60 L 154 62 L 145 63 Z" fill={p.beakShade} opacity="0.5" />155155             <path d="M 138 63 L 152 63" stroke={p.beakShade} stroke-width="0.5" opacity="0.6" />

view file

src/popup/styles/popup.css+233 −252
@@ -194,7 +194,7 @@194194   visibility: hidden;195195   pointer-events: none;196196 }197-/* Chirp-sync owns its own surface and header — fully collapse the global197+/* The pair-device surface owns its own header and header — fully collapse the global198198    chrome row so the warm gradient reaches the popup edge. */199199 .peach-chrome.is-collapsed,200200 .peach-search-wrap.is-collapsed {@@ -1027,8 +1027,8 @@10271027   padding-top: 2px;10281028 }10291029 1030-/* Desktop helper (peach-sync) code pairing — additive hooks. The chirp pairing1031-   classes (peach-chirp-*) carry the shared layout; these only style the parts1030+/* Desktop helper (peach-sync) code pairing — additive hooks. The shared pairing1031+   classes (peach-pair-*) carry the shared layout; these only style the parts10321032    unique to the typed-code path. Inline styles cover the SAS/confirm gate. */10331033 .peach-desktop-pair { display: flex; flex-direction: column; }10341034 .peach-desktop-enter,@@ -9343,16 +9343,16 @@93439343 }93449344 93459345 /* ──────────────────────────────────────────────────────────────────────────9346-   Chirp pairing flow — bird-stage animation (Phase 1)9347-   See src/popup/components/ChirpPairingFlow.tsx and the brief §6.2.9346+   Pair-device flow — bird-stage animation (Phase 1)9347+   See src/popup/components/PairingBirds.tsx and the brief §6.2.93489348    Three-act animation gated on the [data-phase] attribute of9349-   .peach-chirp-pair; child layers (birds, chirp arcs, flight wave, dot)9349+   .peach-pair-pair; child layers (birds, sound arcs, flight wave, dot)93509350    each react via either pose class or visibility flag.93519351    Tokens: accent surfaces use var(--peach-accent); bird illustration93529352    colours are baked into the SVG per the brand-peach exception in §3.1.93539353    ────────────────────────────────────────────────────────────────────── */93549354 9355-.peach-chirp-pair {9355+.peach-pair-pair {93569356   position: absolute;93579357   inset: 0;93589358   z-index: 3;@@ -9370,14 +9370,14 @@93709370   overflow-x: hidden;93719371   scrollbar-width: none;93729372   isolation: isolate;9373-  animation: peach-chirp-overlay-in 180ms cubic-bezier(0.4, 0, 0.2, 1) both;9373+  animation: peach-pair-overlay-in 180ms cubic-bezier(0.4, 0, 0.2, 1) both;93749374 }9375-@keyframes peach-chirp-overlay-in {9375+@keyframes peach-pair-overlay-in {93769376   from { opacity: 0; transform: translateY(8px); }93779377   to   { opacity: 1; transform: translateY(0); }93789378 }9379-.peach-chirp-pair::-webkit-scrollbar { width: 0; height: 0; display: none; }9380-.peach-chirp-pair::before {9379+.peach-pair-pair::-webkit-scrollbar { width: 0; height: 0; display: none; }9380+.peach-pair-pair::before {93819381   content: '';93829382   position: absolute;93839383   inset: 0;@@ -9386,13 +9386,13 @@93869386   background: radial-gradient(ellipse 90% 30% at 50% 0%, color-mix(in srgb, var(--peach-accent) 6%, transparent), transparent 70%);93879387   z-index: 0;93889388 }9389-.peach-chirp-pair > * { position: relative; z-index: 1; }9389+.peach-pair-pair > * { position: relative; z-index: 1; }93909390 93919391 /* Header --------------------------------------------------------------- */9392-.peach-chirp-head {9392+.peach-pair-head {93939393   display: flex; align-items: center; gap: 10px;93949394 }9395-.peach-chirp-back {9395+.peach-pair-back {93969396   width: 32px; height: 32px;93979397   display: inline-flex; align-items: center; justify-content: center;93989398   background: transparent;@@ -9402,11 +9402,11 @@94029402   cursor: pointer;94039403   transition: color 0.15s ease, box-shadow 0.15s ease;94049404 }9405-.peach-chirp-back:hover {9405+.peach-pair-back:hover {94069406   color: var(--peach-accent);94079407   box-shadow: 0 0 10px color-mix(in srgb, var(--peach-accent) 24%, transparent);94089408 }9409-.peach-chirp-title {9409+.peach-pair-title {94109410   font-family: var(--font-display, Georgia, serif);94119411   font-style: italic;94129412   font-size: 24px;@@ -9415,16 +9415,16 @@94159415   color: var(--peach-t0);94169416   line-height: 1;94179417 }9418-.peach-chirp-head-spacer { flex: 1; }9418+.peach-pair-head-spacer { flex: 1; }94199419 94209420 /* Chip row ------------------------------------------------------------- */9421-.peach-chirp-chip-row {9421+.peach-pair-chip-row {94229422   display: flex;94239423   align-items: center;94249424   justify-content: flex-start;94259425   margin-top: 12px;94269426 }9427-.peach-chirp-chip {9427+.peach-pair-chip {94289428   display: inline-flex; align-items: center; gap: 8px;94299429   padding: 5px 10px 5px 8px;94309430   background: color-mix(in srgb, var(--peach-accent) 16%, transparent);@@ -9435,38 +9435,38 @@94359435   letter-spacing: 0.04em;94369436   color: color-mix(in srgb, var(--peach-accent) 70%, var(--peach-t0));94379437 }9438-.peach-chirp-chip-dot {9438+.peach-pair-chip-dot {94399439   width: 6px; height: 6px; border-radius: 50%;94409440   background: var(--peach-accent);94419441   box-shadow: 0 0 6px color-mix(in srgb, var(--peach-accent) 50%, transparent);94429442 }9443-.peach-chirp-chip[data-phase="paired"] {9443+.peach-pair-chip[data-phase="paired"] {94449444   background: color-mix(in srgb, #4f9eda 12%, transparent);94459445   border-color: color-mix(in srgb, #4f9eda 28%, transparent);94469446   color: #76b6e8;94479447 }9448-.peach-chirp-chip[data-phase="paired"] .peach-chirp-chip-dot {9448+.peach-pair-chip[data-phase="paired"] .peach-pair-chip-dot {94499449   background: #76b6e8;94509450   box-shadow: 0 0 6px rgba(118, 182, 232, 0.55);94519451 }9452-.peach-chirp-chip[data-phase="timeout"],9453-.peach-chirp-chip[data-phase="mic_denied"],9454-.peach-chirp-chip[data-phase="version_mismatch"],9455-.peach-chirp-chip[data-phase="handshake_failed"] {9452+.peach-pair-chip[data-phase="timeout"],9453+.peach-pair-chip[data-phase="mic_denied"],9454+.peach-pair-chip[data-phase="version_mismatch"],9455+.peach-pair-chip[data-phase="handshake_failed"] {94569456   background: color-mix(in srgb, var(--peach-warn, #d29257) 14%, transparent);94579457   border-color: color-mix(in srgb, var(--peach-warn, #d29257) 28%, transparent);94589458   color: var(--peach-warn, #d29257);94599459 }9460-.peach-chirp-chip[data-phase="timeout"] .peach-chirp-chip-dot,9461-.peach-chirp-chip[data-phase="mic_denied"] .peach-chirp-chip-dot,9462-.peach-chirp-chip[data-phase="version_mismatch"] .peach-chirp-chip-dot,9463-.peach-chirp-chip[data-phase="handshake_failed"] .peach-chirp-chip-dot {9460+.peach-pair-chip[data-phase="timeout"] .peach-pair-chip-dot,9461+.peach-pair-chip[data-phase="mic_denied"] .peach-pair-chip-dot,9462+.peach-pair-chip[data-phase="version_mismatch"] .peach-pair-chip-dot,9463+.peach-pair-chip[data-phase="handshake_failed"] .peach-pair-chip-dot {94649464   background: var(--peach-warn, #d29257);94659465   box-shadow: 0 0 6px color-mix(in srgb, var(--peach-warn, #d29257) 55%, transparent);94669466 }94679467 94689468 /* Bird stage ----------------------------------------------------------- */9469-.peach-chirp-stage {9469+.peach-pair-stage {94709470   position: relative;94719471   margin: 14px 0 8px;94729472   height: 180px;@@ -9479,7 +9479,7 @@94799479   overflow: hidden;94809480   isolation: isolate;94819481 }9482-.peach-chirp-stage::after {9482+.peach-pair-stage::after {94839483   content: '';94849484   position: absolute;94859485   left: 12%; right: 12%;@@ -9488,7 +9488,7 @@94889488   background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--peach-t0) 14%, transparent), transparent);94899489 }94909490 9491-.peach-chirp-bird-slot {9491+.peach-pair-bird-slot {94929492   position: absolute;94939493   bottom: 8px;94949494   width: 100px;@@ -9497,186 +9497,186 @@94979497   align-items: flex-end;94989498   justify-content: center;94999499 }9500-.peach-chirp-bird-slot-desktop { left: 28px; }9501-.peach-chirp-bird-slot-mobile { right: 28px; }9500+.peach-pair-bird-slot-desktop { left: 28px; }9501+.peach-pair-bird-slot-mobile { right: 28px; }95029502 95039503 /* Mobile bird hops in from the right when handshake begins */9504-.peach-chirp-bird-slot-mobile {9504+.peach-pair-bird-slot-mobile {95059505   opacity: 1;95069506   transform: translateX(-6px);95079507   transition: opacity 0.4s ease, transform 0.65s cubic-bezier(.5, 1.7, .4, 1);95089508 }9509-.peach-chirp-stage.act-listening .peach-chirp-bird-slot-mobile,9510-.peach-chirp-stage.act-chirping .peach-chirp-bird-slot-mobile,9511-.peach-chirp-stage.act-idle .peach-chirp-bird-slot-mobile {9509+.peach-pair-stage.act-listening .peach-pair-bird-slot-mobile,9510+.peach-pair-stage.act-chirping .peach-pair-bird-slot-mobile,9511+.peach-pair-stage.act-idle .peach-pair-bird-slot-mobile {95129512   opacity: 0;95139513   transform: translateX(60px) rotate(8deg);95149514 }9515-.peach-chirp-stage.act-handshake .peach-chirp-bird-slot-desktop,9516-.peach-chirp-stage.act-paired .peach-chirp-bird-slot-desktop {9515+.peach-pair-stage.act-handshake .peach-pair-bird-slot-desktop,9516+.peach-pair-stage.act-paired .peach-pair-bird-slot-desktop {95179517   transform: translateX(6px);95189518   transition: transform 0.5s cubic-bezier(.4, 1.4, .4, 1);95199519 }95209520 95219521 /* Paired: both birds bob together */9522-.peach-chirp-stage.act-paired .peach-chirp-bird-slot {9523-  animation: peach-chirp-happy-bob 1.2s ease-in-out infinite;9522+.peach-pair-stage.act-paired .peach-pair-bird-slot {9523+  animation: peach-pair-happy-bob 1.2s ease-in-out infinite;95249524 }9525-.peach-chirp-stage.act-paired .peach-chirp-bird-slot-mobile { animation-delay: 0.2s; }9526-.peach-chirp-stage.act-paired .peach-chirp-bird-slot-desktop { --bb-x: 6px; }9527-.peach-chirp-stage.act-paired .peach-chirp-bird-slot-mobile { --bb-x: -6px; }9528-@keyframes peach-chirp-happy-bob {9525+.peach-pair-stage.act-paired .peach-pair-bird-slot-mobile { animation-delay: 0.2s; }9526+.peach-pair-stage.act-paired .peach-pair-bird-slot-desktop { --bb-x: 6px; }9527+.peach-pair-stage.act-paired .peach-pair-bird-slot-mobile { --bb-x: -6px; }9528+@keyframes peach-pair-happy-bob {95299529   0%, 100% { transform: translateX(var(--bb-x, 0)) translateY(0); }95309530   50%      { transform: translateX(var(--bb-x, 0)) translateY(-3px); }95319531 }95329532 95339533 /* Bird internal -------------------------------------------------------- */9534-.peach-chirp-bird {9534+.peach-pair-bird {95359535   width: 108px;95369536   height: 108px;95379537   transform-origin: 50% 95%;95389538 }9539-.peach-chirp-bird svg { width: 100%; height: 100%; overflow: visible; }9539+.peach-pair-bird svg { width: 100%; height: 100%; overflow: visible; }95409540 9541-.peach-chirp-bird-body {9541+.peach-pair-bird-body {95429542   transform-origin: 50% 80%;9543-  animation: peach-chirp-bird-bob 2.4s ease-in-out infinite;9543+  animation: peach-pair-bird-bob 2.4s ease-in-out infinite;95449544 }9545-@keyframes peach-chirp-bird-bob {9545+@keyframes peach-pair-bird-bob {95469546   0%, 100% { transform: translateY(0) scale(1, 1); }95479547   50%      { transform: translateY(-1.5px) scale(1.01, 0.99); }95489548 }95499549 9550-.peach-chirp-bird-eye-group {9551-  animation: peach-chirp-blink 5.2s steps(1, end) infinite;9550+.peach-pair-bird-eye-group {9551+  animation: peach-pair-blink 5.2s steps(1, end) infinite;95529552   transform-origin: center;95539553   transform-box: fill-box;95549554 }9555-@keyframes peach-chirp-blink {9555+@keyframes peach-pair-blink {95569556   0%, 92%, 96%, 100% { transform: scaleY(1); }95579557   94%                { transform: scaleY(0.05); }95589558 }95599559 95609560 /* Pose: chirping — beak opens, head bobs, aura blooms */9561-.peach-chirp-bird-pose-chirping .peach-chirp-bird-body {9561+.peach-pair-bird-pose-chirping .peach-pair-bird-body {95629562   animation:9563-    peach-chirp-bird-bob 2.4s ease-in-out infinite,9564-    peach-chirp-squeeze 1.7s ease-in-out infinite;9563+    peach-pair-bird-bob 2.4s ease-in-out infinite,9564+    peach-pair-squeeze 1.7s ease-in-out infinite;95659565 }9566-@keyframes peach-chirp-squeeze {9566+@keyframes peach-pair-squeeze {95679567   0%, 70%, 100% { transform-origin: 50% 85%; }95689568   78%           { transform: scale(1.04, 0.96) translateY(1px); }95699569   86%           { transform: scale(0.98, 1.02); }95709570 }9571-.peach-chirp-bird-pose-chirping .peach-chirp-bird-head-group {9572-  animation: peach-chirp-head-bob 1.7s ease-in-out infinite;9571+.peach-pair-bird-pose-chirping .peach-pair-bird-head-group {9572+  animation: peach-pair-head-bob 1.7s ease-in-out infinite;95739573 }9574-@keyframes peach-chirp-head-bob {9574+@keyframes peach-pair-head-bob {95759575   0%, 70%, 100% { transform: translateY(0) rotate(0); }95769576   78%           { transform: translateY(-3px) rotate(-4deg); }95779577   86%           { transform: translateY(-1px) rotate(-2deg); }95789578 }9579-.peach-chirp-bird-pose-chirping .peach-chirp-bird-beak {9580-  animation: peach-chirp-beak-open 1.7s ease-in-out infinite;9579+.peach-pair-bird-pose-chirping .peach-pair-bird-beak {9580+  animation: peach-pair-beak-open 1.7s ease-in-out infinite;95819581 }9582-@keyframes peach-chirp-beak-open {9582+@keyframes peach-pair-beak-open {95839583   0%, 70%, 100% { transform: rotate(0) scaleX(1); }95849584   78%           { transform: rotate(-14deg) scaleX(1.05) translateY(-1px); }95859585   86%           { transform: rotate(-6deg); }95869586 }9587-.peach-chirp-bird-pose-chirping .peach-chirp-bird-aura {9588-  animation: peach-chirp-aura 1.7s ease-in-out infinite;9587+.peach-pair-bird-pose-chirping .peach-pair-bird-aura {9588+  animation: peach-pair-aura 1.7s ease-in-out infinite;95899589 }9590-@keyframes peach-chirp-aura {9590+@keyframes peach-pair-aura {95919591   0%, 100% { opacity: 0; }95929592   50%      { opacity: 0.8; }95939593 }9594-.peach-chirp-bird-pose-chirping .peach-chirp-bird-tail {9595-  animation: peach-chirp-tail-twitch 1.7s ease-in-out infinite;9594+.peach-pair-bird-pose-chirping .peach-pair-bird-tail {9595+  animation: peach-pair-tail-twitch 1.7s ease-in-out infinite;95969596   transform-origin: 100% 50%;95979597 }9598-@keyframes peach-chirp-tail-twitch {9598+@keyframes peach-pair-tail-twitch {95999599   0%, 75%, 100% { transform: rotate(0); }96009600   82%           { transform: rotate(-3deg) translateX(-1px); }96019601 }96029602 96039603 /* Pose: attentive — head tilts toward partner */9604-.peach-chirp-bird-pose-attentive .peach-chirp-bird-head-group {9605-  animation: peach-chirp-head-tilt 0.6s cubic-bezier(.4, 1.6, .5, 1) both;9604+.peach-pair-bird-pose-attentive .peach-pair-bird-head-group {9605+  animation: peach-pair-head-tilt 0.6s cubic-bezier(.4, 1.6, .5, 1) both;96069606 }9607-@keyframes peach-chirp-head-tilt {9607+@keyframes peach-pair-head-tilt {96089608   0%   { transform: rotate(0) translateY(0); }96099609   60%  { transform: rotate(-10deg) translateY(-1px) translateX(2px); }96109610   100% { transform: rotate(-6deg); }96119611 }9612-.peach-chirp-bird-pose-attentive .peach-chirp-bird-tail {9613-  animation: peach-chirp-tail-cock 0.6s cubic-bezier(.4, 1.6, .5, 1) both;9612+.peach-pair-bird-pose-attentive .peach-pair-bird-tail {9613+  animation: peach-pair-tail-cock 0.6s cubic-bezier(.4, 1.6, .5, 1) both;96149614   transform-origin: 100% 50%;96159615 }9616-@keyframes peach-chirp-tail-cock {9616+@keyframes peach-pair-tail-cock {96179617   0%   { transform: rotate(0); }96189618   100% { transform: rotate(-4deg); }96199619 }96209620 96219621 /* Pose: happy — wing flutter, tuft perk, tail wag */9622-.peach-chirp-bird-pose-happy .peach-chirp-bird-wing {9622+.peach-pair-bird-pose-happy .peach-pair-bird-wing {96239623   transform-origin: 80% 60%;9624-  animation: peach-chirp-wing-flutter 0.32s ease-in-out 5;9624+  animation: peach-pair-wing-flutter 0.32s ease-in-out 5;96259625 }9626-@keyframes peach-chirp-wing-flutter {9626+@keyframes peach-pair-wing-flutter {96279627   0%, 100% { transform: rotate(0) translateY(0); }96289628   50%      { transform: rotate(-16deg) translateY(-2px); }96299629 }9630-.peach-chirp-bird-pose-happy .peach-chirp-bird-tuft {9630+.peach-pair-bird-pose-happy .peach-pair-bird-tuft {96319631   transform-origin: 0% 100%;9632-  animation: peach-chirp-tuft-perk 0.4s ease-in-out 3;9632+  animation: peach-pair-tuft-perk 0.4s ease-in-out 3;96339633 }9634-@keyframes peach-chirp-tuft-perk {9634+@keyframes peach-pair-tuft-perk {96359635   0%, 100% { transform: rotate(0); }96369636   50%      { transform: rotate(-15deg) translateY(-1px); }96379637 }9638-.peach-chirp-bird-pose-happy .peach-chirp-bird-tail {9638+.peach-pair-bird-pose-happy .peach-pair-bird-tail {96399639   transform-origin: 100% 50%;9640-  animation: peach-chirp-tail-wag 0.5s ease-in-out 4;9640+  animation: peach-pair-tail-wag 0.5s ease-in-out 4;96419641 }9642-@keyframes peach-chirp-tail-wag {9642+@keyframes peach-pair-tail-wag {96439643   0%, 100% { transform: rotate(0); }96449644   25%      { transform: rotate(6deg); }96459645   75%      { transform: rotate(-6deg); }96469646 }9647-.peach-chirp-bird-pose-happy .peach-chirp-bird-head-group {9648-  animation: peach-chirp-head-perk 0.5s ease-out;9647+.peach-pair-bird-pose-happy .peach-pair-bird-head-group {9648+  animation: peach-pair-head-perk 0.5s ease-out;96499649 }9650-@keyframes peach-chirp-head-perk {9650+@keyframes peach-pair-head-perk {96519651   0%   { transform: translateY(0); }96529652   40%  { transform: translateY(-3px) rotate(2deg); }96539653   100% { transform: translateY(0); }96549654 }96559655 96569656 /* Pose: sad — body droops forward */9657-.peach-chirp-bird-pose-sad .peach-chirp-bird-body {9657+.peach-pair-bird-pose-sad .peach-pair-bird-body {96589658   transform: translateY(5px) rotate(-2deg);96599659   animation: none;96609660 }9661-.peach-chirp-bird-pose-sad .peach-chirp-bird-head-group {9661+.peach-pair-bird-pose-sad .peach-pair-bird-head-group {96629662   transform: translateY(4px) rotate(8deg);96639663 }9664-.peach-chirp-bird-pose-sad .peach-chirp-bird-tuft { transform: rotate(15deg) translateY(2px); }9665-.peach-chirp-bird-pose-sad .peach-chirp-bird-tail { transform: rotate(8deg) translateY(2px); }9664+.peach-pair-bird-pose-sad .peach-pair-bird-tuft { transform: rotate(15deg) translateY(2px); }9665+.peach-pair-bird-pose-sad .peach-pair-bird-tail { transform: rotate(8deg) translateY(2px); }96669666 9667-.peach-chirp-bird-pose-hidden { opacity: 0; }9667+.peach-pair-bird-pose-hidden { opacity: 0; }96689668 9669-/* Chirp arcs ----------------------------------------------------------- */9670-.peach-chirp-arcs {9669+/* Sound arcs ----------------------------------------------------------- */9670+.peach-pair-arcs {96719671   position: absolute;96729672   top: 18px;96739673   width: 96px;96749674   height: 70px;96759675   pointer-events: none;96769676 }9677-.peach-chirp-arcs-right { right: -60px; }9678-.peach-chirp-arcs-left  { left: -60px; transform: scaleX(-1); }9679-.peach-chirp-arc {9677+.peach-pair-arcs-right { right: -60px; }9678+.peach-pair-arcs-left  { left: -60px; transform: scaleX(-1); }9679+.peach-pair-arc {96809680   position: absolute;96819681   top: 50%;96829682   left: 0;@@ -9687,21 +9687,21 @@96879687   border-color: transparent #f4d5a8 transparent transparent;96889688   border-radius: 50%;96899689   opacity: 0;9690-  animation: peach-chirp-arc-expand 1.7s cubic-bezier(.2, .6, .2, 1) infinite;9690+  animation: peach-pair-arc-expand 1.7s cubic-bezier(.2, .6, .2, 1) infinite;96919691 }9692-@keyframes peach-chirp-arc-expand {9692+@keyframes peach-pair-arc-expand {96939693   0%   { transform: scale(0.4); opacity: 0; }96949694   20%  { opacity: 0.9; }96959695   100% { transform: scale(1.6); opacity: 0; }96969696 }96979697 96989698 /* Flight wave ---------------------------------------------------------- */9699-.peach-chirp-flight-track {9699+.peach-pair-flight-track {97009700   position: absolute;97019701   inset: 32px 36px 38px 36px;97029702   pointer-events: none;97039703 }9704-.peach-chirp-flight-wave {9704+.peach-pair-flight-wave {97059705   position: absolute;97069706   top: 8px;97079707   left: 76px;@@ -9713,31 +9713,31 @@97139713   stroke: #f4d5a8;97149714   fill: none;97159715 }9716-.peach-chirp-flight-wave[data-from="mobile"] { transform: scaleX(-1); }9717-.peach-chirp-flight-wave.is-visible { opacity: 1; }9718-.peach-chirp-flight-path,9719-.peach-chirp-flight-path-2 {9716+.peach-pair-flight-wave[data-from="mobile"] { transform: scaleX(-1); }9717+.peach-pair-flight-wave.is-visible { opacity: 1; }9718+.peach-pair-flight-path,9719+.peach-pair-flight-path-2 {97209720   stroke-dasharray: 240;97219721   stroke-dashoffset: 240;97229722   stroke-linecap: round;97239723   fill: none;97249724 }9725-.peach-chirp-flight-path   { stroke-width: 1.6; stroke: #f4d5a8; }9726-.peach-chirp-flight-path-2 { stroke-width: 1; stroke: #f4d5a8; opacity: 0.55; }9727-.peach-chirp-flight-wave.is-visible .peach-chirp-flight-path {9728-  animation: peach-chirp-fly 700ms cubic-bezier(.2,.6,.2,1) forwards;9725+.peach-pair-flight-path   { stroke-width: 1.6; stroke: #f4d5a8; }9726+.peach-pair-flight-path-2 { stroke-width: 1; stroke: #f4d5a8; opacity: 0.55; }9727+.peach-pair-flight-wave.is-visible .peach-pair-flight-path {9728+  animation: peach-pair-fly 700ms cubic-bezier(.2,.6,.2,1) forwards;97299729 }9730-.peach-chirp-flight-wave.is-visible .peach-chirp-flight-path-2 {9731-  animation: peach-chirp-fly 700ms cubic-bezier(.2,.6,.2,1) 80ms forwards;9730+.peach-pair-flight-wave.is-visible .peach-pair-flight-path-2 {9731+  animation: peach-pair-fly 700ms cubic-bezier(.2,.6,.2,1) 80ms forwards;97329732 }9733-@keyframes peach-chirp-fly {9733+@keyframes peach-pair-fly {97349734   0%   { stroke-dashoffset: 240; opacity: 0; }97359735   20%  { opacity: 1; }97369736   100% { stroke-dashoffset: -120; opacity: 0; }97379737 }97389738 97399739 /* Connection dot ------------------------------------------------------- */9740-.peach-chirp-dot {9740+.peach-pair-dot {97419741   position: absolute;97429742   top: 50%; left: 50%;97439743   transform: translate(-50%, -50%);@@ -9747,8 +9747,8 @@97479747   transition: opacity 0.3s ease;97489748   color: var(--peach-accent);97499749 }9750-.peach-chirp-dot.is-visible { opacity: 1; }9751-.peach-chirp-dot-glow {9750+.peach-pair-dot.is-visible { opacity: 1; }9751+.peach-pair-dot-glow {97529752   position: absolute; top: 50%; left: 50%;97539753   transform: translate(-50%, -50%);97549754   width: 38px; height: 38px;@@ -9756,47 +9756,47 @@97569756   filter: blur(10px);97579757   opacity: 0.55;97589758   background: var(--peach-accent);9759-  animation: peach-chirp-dot-bloom 1.4s ease-out;9759+  animation: peach-pair-dot-bloom 1.4s ease-out;97609760 }9761-.peach-chirp-dot-core {9761+.peach-pair-dot-core {97629762   position: absolute; top: 50%; left: 50%;97639763   transform: translate(-50%, -50%);97649764   width: 8px; height: 8px;97659765   border-radius: 50%;97669766   background: var(--peach-accent);97679767   box-shadow: 0 0 12px currentColor;9768-  animation: peach-chirp-dot-core 1.4s ease-out;9768+  animation: peach-pair-dot-core 1.4s ease-out;97699769 }9770-.peach-chirp-dot-ring {9770+.peach-pair-dot-ring {97719771   position: absolute; top: 50%; left: 50%;97729772   width: 60px; height: 60px;97739773   transform: translate(-50%, -50%);9774-  animation: peach-chirp-dot-ring 1.4s linear;9774+  animation: peach-pair-dot-ring 1.4s linear;97759775   stroke: var(--peach-accent);97769776 }9777-@keyframes peach-chirp-dot-bloom {9777+@keyframes peach-pair-dot-bloom {97789778   0%   { width: 4px; height: 4px; opacity: 0; }97799779   35%  { width: 60px; height: 60px; opacity: 0.7; }97809780   100% { width: 38px; height: 38px; opacity: 0.55; }97819781 }9782-@keyframes peach-chirp-dot-core {9782+@keyframes peach-pair-dot-core {97839783   0%   { width: 0; height: 0; }97849784   35%  { width: 12px; height: 12px; }97859785   100% { width: 8px; height: 8px; }97869786 }9787-@keyframes peach-chirp-dot-ring {9787+@keyframes peach-pair-dot-ring {97889788   0%   { transform: translate(-50%, -50%) scale(0.4); opacity: 0; }97899789   35%  { transform: translate(-50%, -50%) scale(1.0); opacity: 0.6; }97909790   100% { transform: translate(-50%, -50%) scale(1.4); opacity: 0; }97919791 }97929792 97939793 /* Motes — drift upward across the stage */9794-.peach-chirp-motes {9794+.peach-pair-motes {97959795   position: absolute;97969796   inset: 0;97979797   pointer-events: none;97989798 }9799-.peach-chirp-mote {9799+.peach-pair-mote {98009800   position: absolute;98019801   width: 2px; height: 2px;98029802   background: color-mix(in srgb, var(--peach-text) 35%, transparent);@@ -9804,10 +9804,10 @@98049804   bottom: 32px;98059805   left: calc(50% + (var(--mote-i, 0) - 4) * 24px);98069806   opacity: 0;9807-  animation: peach-chirp-mote-drift 6s linear infinite;9807+  animation: peach-pair-mote-drift 6s linear infinite;98089808   animation-delay: calc(var(--mote-i, 0) * 0.7s);98099809 }9810-@keyframes peach-chirp-mote-drift {9810+@keyframes peach-pair-mote-drift {98119811   0%   { transform: translateY(0); opacity: 0; }98129812   10%  { opacity: 0.6; }98139813   90%  { opacity: 0.1; }@@ -9815,19 +9815,19 @@98159815 }98169816 98179817 /* Status copy ---------------------------------------------------------- */9818-.peach-chirp-copy-host {9818+.peach-pair-copy-host {98199819   margin: 4px 4px 10px;98209820   text-align: center;98219821   min-height: 50px;98229822 }9823-.peach-chirp-copy {9824-  animation: peach-chirp-copy-in 0.35s ease both;9823+.peach-pair-copy {9824+  animation: peach-pair-copy-in 0.35s ease both;98259825 }9826-@keyframes peach-chirp-copy-in {9826+@keyframes peach-pair-copy-in {98279827   from { opacity: 0; transform: translateY(4px); }98289828   to   { opacity: 1; transform: translateY(0); }98299829 }9830-.peach-chirp-headline {9830+.peach-pair-headline {98319831   font-family: var(--font-display, Georgia, serif);98329832   font-style: italic;98339833   font-size: 20px;@@ -9837,9 +9837,9 @@98379837   color: var(--peach-t0);98389838   margin-bottom: 6px;98399839 }9840-.peach-chirp-copy-listening .peach-chirp-headline,9841-.peach-chirp-copy-chirping .peach-chirp-headline,9842-.peach-chirp-copy-idle .peach-chirp-headline {9840+.peach-pair-copy-listening .peach-pair-headline,9841+.peach-pair-copy-chirping .peach-pair-headline,9842+.peach-pair-copy-idle .peach-pair-headline {98439843   font-family: inherit;98449844   font-style: normal;98459845   font-weight: 500;@@ -9847,11 +9847,11 @@98479847   color: var(--peach-t0);98489848   letter-spacing: 0;98499849 }9850-.peach-chirp-copy-paired .peach-chirp-headline {9850+.peach-pair-copy-paired .peach-pair-headline {98519851   color: var(--peach-t0);98529852   font-weight: 600;98539853 }9854-.peach-chirp-sub {9854+.peach-pair-sub {98559855   font-size: 12.5px;98569856   line-height: 1.45;98579857   color: var(--peach-t1);@@ -9861,23 +9861,23 @@98619861 }98629862 98639863 /* Status action -------------------------------------------------------- */9864-.peach-chirp-action {9864+.peach-pair-action {98659865   margin: 2px 4px 10px;98669866   margin-top: auto;98679867   display: flex;98689868   flex-direction: column;98699869   gap: 8px;98709870 }9871-.peach-chirp-action-waiting {9871+.peach-pair-action-waiting {98729872   display: flex;98739873   align-items: center;98749874   justify-content: space-between;98759875   gap: 12px;98769876 }9877-.peach-chirp-cancel {9877+.peach-pair-cancel {98789878   min-width: 96px;98799879 }9880-.peach-chirp-listening {9880+.peach-pair-listening {98819881   display: inline-flex; align-items: center; gap: 4px;98829882   font-family: var(--peach-mono, ui-monospace, monospace);98839883   font-size: 9.5px;@@ -9886,28 +9886,28 @@98869886   color: var(--peach-t1);98879887   padding: 8px 10px;98889888 }9889-.peach-chirp-listen-dot {9889+.peach-pair-listen-dot {98909890   width: 4px; height: 4px;98919891   border-radius: 50%;98929892   background: color-mix(in srgb, var(--peach-accent) 55%, transparent);9893-  animation: peach-chirp-listen-pulse 1.2s ease-in-out infinite;9893+  animation: peach-pair-listen-pulse 1.2s ease-in-out infinite;98949894 }9895-.peach-chirp-listen-dot:nth-child(2) { animation-delay: 0.2s; }9896-.peach-chirp-listen-dot:nth-child(3) { animation-delay: 0.4s; }9897-.peach-chirp-listen-label { margin-left: 6px; }9898-@keyframes peach-chirp-listen-pulse {9895+.peach-pair-listen-dot:nth-child(2) { animation-delay: 0.2s; }9896+.peach-pair-listen-dot:nth-child(3) { animation-delay: 0.4s; }9897+.peach-pair-listen-label { margin-left: 6px; }9898+@keyframes peach-pair-listen-pulse {98999899   0%, 100% { opacity: 0.25; transform: scale(0.9); }99009900   50%      { opacity: 1;     transform: scale(1.15); }99019901 }99029902 9903-.peach-chirp-action-handshake {9903+.peach-pair-action-handshake {99049904   display: flex;99059905   flex-direction: column;99069906   align-items: center;99079907   gap: 8px;99089908   padding: 8px 4px;99099909 }9910-.peach-chirp-meter {9910+.peach-pair-meter {99119911   width: 100%;99129912   max-width: 280px;99139913   height: 2px;@@ -9916,19 +9916,19 @@99169916   position: relative;99179917   overflow: hidden;99189918 }9919-.peach-chirp-meter-bar {9919+.peach-pair-meter-bar {99209920   position: absolute;99219921   top: 0; bottom: 0;99229922   width: 30%;99239923   left: -30%;99249924   background: linear-gradient(90deg, transparent, var(--peach-accent), transparent);9925-  animation: peach-chirp-meter-sweep 1.4s ease-in-out infinite;9925+  animation: peach-pair-meter-sweep 1.4s ease-in-out infinite;99269926 }9927-@keyframes peach-chirp-meter-sweep {9927+@keyframes peach-pair-meter-sweep {99289928   0%   { left: -30%; }99299929   100% { left: 100%; }99309930 }9931-.peach-chirp-meter-label {9931+.peach-pair-meter-label {99329932   font-family: var(--peach-mono, ui-monospace, monospace);99339933   font-size: 9.5px;99349934   text-transform: uppercase;@@ -9936,12 +9936,12 @@99369936   color: var(--peach-t1);99379937 }99389938 9939-.peach-chirp-action-paired {9939+.peach-pair-action-paired {99409940   display: flex;99419941   align-items: center;99429942   gap: 10px;99439943 }9944-.peach-chirp-device-confirm {9944+.peach-pair-device-confirm {99459945   flex: 1;99469946   display: inline-flex;99479947   align-items: center;@@ -9954,17 +9954,17 @@99549954   color: var(--peach-t0);99559955   min-width: 0;99569956 }9957-.peach-chirp-device-confirm-glyph {9957+.peach-pair-device-confirm-glyph {99589958   display: inline-flex;99599959   color: #76b6e8;99609960 }9961-.peach-chirp-device-confirm-name {9961+.peach-pair-device-confirm-name {99629962   flex: 1;99639963   overflow: hidden;99649964   text-overflow: ellipsis;99659965   white-space: nowrap;99669966 }9967-.peach-chirp-device-confirm-trust {9967+.peach-pair-device-confirm-trust {99689968   font-family: var(--peach-mono, ui-monospace, monospace);99699969   font-size: 9.5px;99709970   text-transform: uppercase;@@ -9974,16 +9974,16 @@99749974   border-radius: 4px;99759975   background: color-mix(in srgb, #76b6e8 14%, transparent);99769976 }9977-.peach-chirp-done {9977+.peach-pair-done {99789978   min-width: 80px;99799979 }9980-.peach-chirp-retry {9980+.peach-pair-retry {99819981   align-self: center;99829982   display: block;99839983   margin: 6px auto 0;99849984   min-width: 120px;99859985 }9986-.peach-chirp-mic-help {9986+.peach-pair-mic-help {99879987   font-size: 12px;99889988   color: var(--peach-t1);99899989   text-align: center;@@ -9992,11 +9992,11 @@99929992 }99939993 99949994 /* Rest state — bird stage at idle pose, primary CTA + paired list */9995-.peach-chirp-pair[data-phase="idle"] .peach-chirp-stage {9995+.peach-pair-pair[data-phase="idle"] .peach-pair-stage {99969996   /* Slightly shorter stage when at rest — no flight wave or motes to fill it */99979997   height: 160px;99989998 }9999-.peach-chirp-pair-start {9999+.peach-pair-pair-start {1000010000   width: 100%;1000110001   display: inline-flex;1000210002   align-items: center;@@ -10014,16 +10014,16 @@1001410014   cursor: pointer;1001510015   transition: filter 0.15s ease, transform 0.1s ease;1001610016 }10017-.peach-chirp-pair-start:hover { filter: brightness(1.08); }10018-.peach-chirp-pair-start:active { transform: translateY(1px); }10017+.peach-pair-pair-start:hover { filter: brightness(1.08); }10018+.peach-pair-pair-start:active { transform: translateY(1px); }1001910019 10020-.peach-chirp-paired-section {10020+.peach-pair-paired-section {1002110021   margin-top: 14px;1002210022   display: flex;1002310023   flex-direction: column;1002410024   gap: 8px;1002510025 }10026-.peach-chirp-paired-heading {10026+.peach-pair-paired-heading {1002710027   margin: 0;1002810028   font-family: var(--peach-mono, ui-monospace, monospace);1002910029   font-size: 10px;@@ -10034,16 +10034,16 @@1003410034 }1003510035 1003610036 /* Footer --------------------------------------------------------------- */10037-.peach-chirp-foot {10037+.peach-pair-foot {1003810038   margin: 10px -4px -2px;1003910039   margin-top: auto;1004010040 }10041-.peach-chirp-foot-divider {10041+.peach-pair-foot-divider {1004210042   height: 1px;1004310043   background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--peach-t0) 18%, transparent), transparent);1004410044   margin-bottom: 10px;1004510045 }10046-.peach-chirp-foot-text {10046+.peach-pair-foot-text {1004710047   font-size: 11px;1004810048   line-height: 1.5;1004910049   color: var(--peach-t1);@@ -10066,36 +10066,36 @@1006610066 1006710067 /* Reduced motion — stage simplifies to opacity transitions only */1006810068 @media (prefers-reduced-motion: reduce) {10069-  .peach-chirp-bird-body,10070-  .peach-chirp-bird-head-group,10071-  .peach-chirp-bird-beak,10072-  .peach-chirp-bird-wing,10073-  .peach-chirp-bird-tuft,10074-  .peach-chirp-bird-tail,10075-  .peach-chirp-bird-eye-group,10076-  .peach-chirp-bird-aura,10077-  .peach-chirp-arc,10078-  .peach-chirp-flight-path,10079-  .peach-chirp-flight-path-2,10080-  .peach-chirp-dot-glow,10081-  .peach-chirp-dot-core,10082-  .peach-chirp-dot-ring,10083-  .peach-chirp-mote,10084-  .peach-chirp-meter-bar,10085-  .peach-chirp-listen-dot,10086-  .peach-chirp-bird-slot,10087-  .peach-chirp-bird-slot-mobile {10069+  .peach-pair-bird-body,10070+  .peach-pair-bird-head-group,10071+  .peach-pair-bird-beak,10072+  .peach-pair-bird-wing,10073+  .peach-pair-bird-tuft,10074+  .peach-pair-bird-tail,10075+  .peach-pair-bird-eye-group,10076+  .peach-pair-bird-aura,10077+  .peach-pair-arc,10078+  .peach-pair-flight-path,10079+  .peach-pair-flight-path-2,10080+  .peach-pair-dot-glow,10081+  .peach-pair-dot-core,10082+  .peach-pair-dot-ring,10083+  .peach-pair-mote,10084+  .peach-pair-meter-bar,10085+  .peach-pair-listen-dot,10086+  .peach-pair-bird-slot,10087+  .peach-pair-bird-slot-mobile {1008810088     animation: none !important;1008910089     transition: opacity 0.2s linear !important;1009010090   }1009110091 }1009210092 1009310093 /* ─────────────────────────────────────────────────────────────────10094-   Settings → Sync surface (v3 ChirpSync). Wraps the same bird10094+   Settings → Sync surface. Wraps the same bird1009510095    animation used by the pairing flow with a paired-devices list and1009610096    the "Pair a device" CTA.1009710097    ───────────────────────────────────────────────────────────────── */10098-.peach-chirp-settings {10098+.peach-pair-settings {1009910099   position: absolute;1010010100   inset: 0;1010110101   z-index: 3;@@ -10107,7 +10107,7 @@1010710107   box-sizing: border-box;1010810108   overflow-y: auto;1010910109   overflow-x: hidden;10110-  /* Same warm Chirp surface as the pairing screen — unifies the two views. */10110+  /* Same warm surface as the pairing screen — unifies the two views. */1011110111   background:1011210112     radial-gradient(ellipse 70% 50% at 30% 0%, color-mix(in srgb, var(--peach-accent) 10%, transparent), transparent 70%),1011310113     var(--peach-bg);@@ -10116,10 +10116,10 @@1011610116   /* Hide native scrollbar — content fits 99% of the time and a chunky1011710117      gutter ruins the surface. */1011810118   scrollbar-width: none;10119-  animation: peach-chirp-overlay-in 180ms cubic-bezier(0.4, 0, 0.2, 1) both;10119+  animation: peach-pair-overlay-in 180ms cubic-bezier(0.4, 0, 0.2, 1) both;1012010120 }10121-.peach-chirp-settings::-webkit-scrollbar { width: 0; height: 0; display: none; }10122-.peach-chirp-settings::before {10121+.peach-pair-settings::-webkit-scrollbar { width: 0; height: 0; display: none; }10122+.peach-pair-settings::before {1012310123   content: '';1012410124   position: absolute;1012510125   inset: 0;@@ -10127,23 +10127,23 @@1012710127   background: radial-gradient(ellipse 90% 30% at 50% 0%, color-mix(in srgb, var(--peach-accent) 6%, transparent), transparent 70%);1012810128   z-index: 0;1012910129 }10130-.peach-chirp-settings > * { position: relative; z-index: 1; }10130+.peach-pair-settings > * { position: relative; z-index: 1; }1013110131 10132-.peach-chirp-settings--pairing {10132+.peach-pair-settings--pairing {1013310133   padding: 0;1013410134   align-items: stretch;1013510135   justify-content: stretch;1013610136   background: none;1013710137   isolation: auto;1013810138 }10139-.peach-chirp-settings--pairing::before { display: none; }10139+.peach-pair-settings--pairing::before { display: none; }1014010140 10141-.peach-chirp-settings-header {10141+.peach-pair-settings-header {1014210142   display: flex;1014310143   align-items: center;1014410144   gap: 10px;1014510145 }10146-.peach-chirp-settings-title {10146+.peach-pair-settings-title {1014710147   margin: 0;1014810148   font-family: var(--font-display, Georgia, serif);1014910149   font-style: italic;@@ -10153,7 +10153,7 @@1015310153   color: var(--peach-t0);1015410154   letter-spacing: 0.005em;1015510155 }10156-.peach-chirp-settings-section {10156+.peach-pair-settings-section {1015710157   margin: 6px 0 -4px;1015810158   font-size: 11px;1015910159   font-weight: 600;@@ -10161,14 +10161,14 @@1016110161   text-transform: uppercase;1016210162   color: var(--peach-text-muted);1016310163 }10164-.peach-chirp-settings-error {10164+.peach-pair-settings-error {1016510165   font-size: 12px;1016610166   padding: 8px 10px;1016710167   border-radius: 8px;1016810168   background: color-mix(in srgb, var(--peach-danger, #c25b4a) 18%, transparent);1016910169   color: var(--peach-text);1017010170 }10171-.peach-chirp-settings-footer {10171+.peach-pair-settings-footer {1017210172   margin-top: auto;1017310173   padding-top: 18px;1017410174   font-size: 11.5px;@@ -10178,7 +10178,7 @@1017810178 }1017910179 1018010180 /* Hero card shown when no devices are paired yet. */10181-.peach-chirp-hero {10181+.peach-pair-hero {1018210182   display: flex;1018310183   flex-direction: column;1018410184   align-items: center;@@ -10186,12 +10186,12 @@1018610186   padding: 20px 12px 8px;1018710187   text-align: center;1018810188 }10189-.peach-chirp-hero-svg {10189+.peach-pair-hero-svg {1019010190   display: block;1019110191   max-width: 100%;1019210192   filter: drop-shadow(0 4px 12px color-mix(in srgb, var(--peach-accent) 25%, transparent));1019310193 }10194-.peach-chirp-hero-headline {10194+.peach-pair-hero-headline {1019510195   margin: 0;1019610196   font-family: var(--font-display, Georgia, serif);1019710197   font-style: italic;@@ -10201,7 +10201,7 @@1020110201   letter-spacing: 0.005em;1020210202   color: var(--peach-t0);1020310203 }10204-.peach-chirp-hero-sub {10204+.peach-pair-hero-sub {1020510205   margin: 0;1020610206   font-size: 13px;1020710207   line-height: 1.5;@@ -10210,25 +10210,25 @@1021010210   text-wrap: pretty;1021110211 }1021210212 10213-.peach-chirp-pair-cta {10213+.peach-pair-pair-cta {1021410214   display: flex;1021510215   justify-content: center;1021610216   padding: 4px 0 6px;1021710217 }10218-.peach-chirp-pair-button {10218+.peach-pair-pair-button {1021910219   display: inline-flex;1022010220   align-items: center;1022110221   gap: 8px;1022210222   min-width: 220px;1022310223   justify-content: center;1022410224 }10225-.peach-chirp-pair-button-icon {10225+.peach-pair-pair-button-icon {1022610226   flex: 0 0 auto;1022710227 }1022810228 1022910229 /* Paired devices list. Roomy rows that look at home next to the rest1023010230    of Settings; stale rows get a soft warm-warning border tint. */10231-.peach-chirp-device-list {10231+.peach-pair-device-list {1023210232   list-style: none;1023310233   margin: 0;1023410234   padding: 0;@@ -10236,7 +10236,7 @@1023610236   flex-direction: column;1023710237   gap: 8px;1023810238 }10239-.peach-chirp-device-row {10239+.peach-pair-device-row {1024010240   display: flex;1024110241   align-items: center;1024210242   gap: 12px;@@ -10245,10 +10245,10 @@1024510245   background: color-mix(in srgb, var(--peach-bg-elevated, var(--peach-bg)) 88%, var(--peach-accent) 12%);1024610246   border: 1px solid color-mix(in srgb, var(--peach-accent) 12%, transparent);1024710247 }10248-.peach-chirp-device-row[data-stale="true"] {10248+.peach-pair-device-row[data-stale="true"] {1024910249   border-color: color-mix(in srgb, var(--peach-warn, #d29257) 36%, transparent);1025010250 }10251-.peach-chirp-device-icon {10251+.peach-pair-device-icon {1025210252   width: 32px;1025310253   height: 32px;1025410254   display: flex;@@ -10258,14 +10258,14 @@1025810258   color: var(--peach-text);1025910259   background: color-mix(in srgb, var(--peach-accent) 18%, transparent);1026010260 }10261-.peach-chirp-device-info {10261+.peach-pair-device-info {1026210262   flex: 1;1026310263   display: flex;1026410264   flex-direction: column;1026510265   gap: 2px;1026610266   min-width: 0;1026710267 }10268-.peach-chirp-device-name {10268+.peach-pair-device-name {1026910269   font-size: 14px;1027010270   font-weight: 600;1027110271   color: var(--peach-text);@@ -10273,7 +10273,7 @@1027310273   text-overflow: ellipsis;1027410274   white-space: nowrap;1027510275 }10276-.peach-chirp-device-meta {10276+.peach-pair-device-meta {1027710277   font-size: 11.5px;1027810278   color: var(--peach-text-muted);1027910279   display: flex;@@ -10281,7 +10281,7 @@1028110281   align-items: center;1028210282   gap: 8px;1028310283 }10284-.peach-chirp-device-badge {10284+.peach-pair-device-badge {1028510285   font-size: 10.5px;1028610286   font-weight: 500;1028710287   letter-spacing: 0.02em;@@ -10290,26 +10290,26 @@1029010290   background: color-mix(in srgb, var(--peach-accent) 22%, transparent);1029110291   color: var(--peach-text);1029210292 }10293-.peach-chirp-device-stale {10293+.peach-pair-device-stale {1029410294   font-size: 10.5px;1029510295   font-weight: 500;1029610296   color: var(--peach-warn, #d29257);1029710297 }10298-.peach-chirp-device-remove {10298+.peach-pair-device-remove {1029910299   flex: 0 0 auto;1030010300   color: var(--peach-text-muted);1030110301 }10302-.peach-chirp-device-remove:hover {10302+.peach-pair-device-remove:hover {1030310303   color: var(--peach-danger, #c25b4a);1030410304 }10305-.peach-chirp-unpair-confirm {10305+.peach-pair-unpair-confirm {1030610306   display: flex;1030710307   gap: 6px;1030810308   align-items: center;1030910309 }1031010310 1031110311 /* Pro-gate card — soft upsell with the mobile bird perched, chirping. */10312-.peach-chirp-pro-card {10312+.peach-pair-pro-card {1031310313   position: relative;1031410314   margin: 18px 12px;1031510315   padding: 18px 20px 22px;@@ -10330,7 +10330,7 @@1033010330   text-align: center;1033110331   overflow: hidden;1033210332 }10333-.peach-chirp-pro-stage {10333+.peach-pair-pro-stage {1033410334   position: relative;1033510335   width: 220px;1033610336   height: 140px;@@ -10339,7 +10339,7 @@1033910339   justify-content: center;1034010340   margin-bottom: 2px;1034110341 }10342-.peach-chirp-pro-bird-slot {10342+.peach-pair-pro-bird-slot {1034310343   width: 140px;1034410344   height: 132px;1034510345   display: flex;@@ -10347,35 +10347,16 @@1034710347   justify-content: center;1034810348   filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.35));1034910349 }10350-.peach-chirp-pro-bird-slot .peach-chirp-bird {10350+.peach-pair-pro-bird-slot .peach-pair-bird {1035110351   width: 100%;1035210352   height: 100%;1035310353 }10354-.peach-chirp-pro-bird-slot .peach-chirp-bird svg {10354+.peach-pair-pro-bird-slot .peach-pair-bird svg {1035510355   width: 100%;1035610356   height: 100%;1035710357   overflow: visible;1035810358 }10359-.peach-chirp-pro-chirp {10360-  position: absolute;10361-  top: 14px;10362-  right: 8px;10363-  width: 96px;10364-  height: 80px;10365-  color: var(--peach-accent);10366-  animation: peach-chirp-pulse 2.6s ease-in-out infinite;10367-  transform-origin: 0% 50%;10368-  pointer-events: none;10369-}10370-@keyframes peach-chirp-pulse {10371-  0%, 100% { opacity: 0.35; transform: translateX(0) scale(0.92); }10372-  45%      { opacity: 1;    transform: translateX(2px) scale(1); }10373-  70%      { opacity: 0.6;  transform: translateX(4px) scale(1.04); }10374-}10375-@media (prefers-reduced-motion: reduce) {10376-  .peach-chirp-pro-chirp { animation: none; opacity: 0.7; }10377-}10378-.peach-chirp-pro-headline {10359+.peach-pair-pro-headline {1037910360   margin: 4px 0 0;1038010361   font-family: var(--font-display, "Cormorant Garamond", serif);1038110362   font-style: italic;@@ -10386,17 +10367,17 @@1038610367   max-width: 280px;1038710368   line-height: 1.25;1038810369 }10389-.peach-chirp-pro-body {10370+.peach-pair-pro-body {1039010371   margin: 0;1039110372   font-size: 13px;1039210373   line-height: 1.55;1039310374   color: var(--peach-t1);1039410375   max-width: 300px;1039510376 }10396-.peach-chirp-pro-cta {10377+.peach-pair-pro-cta {1039710378   margin-top: 4px;1039810379 }10399-.peach-chirp-pro-foot {10380+.peach-pair-pro-foot {1040010381   margin: 2px 0 0;1040110382   font-family: "IBM Plex Mono", "SFMono-Regular", Menlo, monospace;1040210383   font-size: 0.625rem;

view file

src/popup/views/PairDevice.test.tsx+1 −1
@@ -99,7 +99,7 @@9999     expect(input.getAttribute("inputmode")).toBeNull();100100     expect(input.getAttribute("maxlength")).toBe("32");101101     // birds always animate on the code screens (design correction)102-    expect(container.querySelector(".peach-chirp-bird-desktop")).toBeTruthy();102+    expect(container.querySelector(".peach-pair-bird-desktop")).toBeTruthy();103103   });104104 105105   it("uppercases and regroups a pairing code as it is typed", () => {

view file

src/popup/views/PairDevice.tsx+23 −23
@@ -10,7 +10,7 @@1010 // so it is always the side that dials.1111 //1212 // The pairing itself runs in the background (code-pairing.ts) and reaches13-// this view via the PAIR_WITH_CODE / DESKTOP_PAIR_* messages.13+// this view via the PAIR_WITH_CODE / CODE_PAIR_* messages.1414 1515 import {1616   Component,@@ -86,7 +86,7 @@8686 export const PairDeviceView: Component<PairDeviceViewProps> = (props) => {8787   // The whole NK pairing runs in the background; this view drives the UI and8888   // the out-of-band SAS confirmation round-trip via the PAIR_WITH_CODE /89-  // DESKTOP_PAIR_* messages. The SAS gate is what authenticates the peer89+  // CODE_PAIR_* messages. The SAS gate is what authenticates the peer9090   // (audit HIGH — pairing initiator authentication), not the pairing token.9191   const [phase, setPhase] = createSignal<PairPhase>("enter");9292   const [code, setCode] = createSignal("");@@ -209,11 +209,11 @@209209 210210   // The bird stage — always animating — shared by every pairing screen.211211   const birdStage = (active: boolean) => (212-    <div class={`peach-chirp-stage ${active ? "act-handshake" : "act-listening"}`} aria-hidden="true">213-      <div class="peach-chirp-bird-slot peach-chirp-bird-slot-desktop">212+    <div class={`peach-pair-stage ${active ? "act-handshake" : "act-listening"}`} aria-hidden="true">213+      <div class="peach-pair-bird-slot peach-pair-bird-slot-desktop">214214         <DesktopBird pose="chirping" />215215       </div>216-      <div class="peach-chirp-bird-slot peach-chirp-bird-slot-mobile">216+      <div class="peach-pair-bird-slot peach-pair-bird-slot-mobile">217217         <MobileBird pose="attentive" />218218       </div>219219     </div>@@ -231,19 +231,19 @@231231 232232   // Code pairing — birds animate on every screen below.233233   const pairingScreen = () => (234-    <div class="peach-chirp-pair peach-desktop-pair" data-phase={phase()} role="dialog" aria-label="Pair a device with a code">235-      <header class="peach-chirp-head">236-        <button class="peach-chirp-back" aria-label="Back" onClick={() => props.onBack()}>{backArrow}</button>237-        <div class="peach-chirp-title">Enter a code</div>238-        <div class="peach-chirp-head-spacer" />234+    <div class="peach-pair-pair peach-desktop-pair" data-phase={phase()} role="dialog" aria-label="Pair a device with a code">235+      <header class="peach-pair-head">236+        <button class="peach-pair-back" aria-label="Back" onClick={() => props.onBack()}>{backArrow}</button>237+        <div class="peach-pair-title">Enter a code</div>238+        <div class="peach-pair-head-spacer" />239239       </header>240240 241241       {birdStage(phase() !== "enter")}242242 243243       <Show when={phase() === "enter"}>244244         <div class="peach-desktop-enter">245-          <div class="peach-chirp-headline">Enter the code from your phone</div>246-          <div class="peach-chirp-sub">245+          <div class="peach-pair-headline">Enter the code from your phone</div>246+          <div class="peach-pair-sub">247247             Open Peach on your phone, tap “Pair a device”, and type the code it shows.248248             Both devices need to be on the same Wi-Fi.249249           </div>@@ -263,7 +263,7 @@263263             onInput={(e) => onCodeInput((e.target as HTMLInputElement).value)}264264             onKeyDown={(e) => { if (e.key === "Enter") void handleConnect(); }}265265           />266-          <div class="peach-chirp-action">266+          <div class="peach-pair-action">267267             <button class="peach-btn peach-btn-ghost" onClick={() => props.onBack()}>Cancel</button>268268             <button269269               class="peach-btn peach-btn-primary peach-desktop-connect"@@ -278,21 +278,21 @@278278 279279       <Show when={phase() === "connecting"}>280280         <div class="peach-desktop-searching">281-          <div class="peach-chirp-headline">Connecting…</div>282-          <div class="peach-chirp-sub">Reaching your phone over the local network.</div>281+          <div class="peach-pair-headline">Connecting…</div>282+          <div class="peach-pair-sub">Reaching your phone over the local network.</div>283283         </div>284284       </Show>285285 286286       <Show when={phase() === "sas"}>287287         <div class="peach-desktop-confirm" style="display:flex;flex-direction:column;align-items:center;gap:12px;padding:8px 18px 16px;text-align:center;">288-          <div class="peach-chirp-headline">Confirm this code matches on your phone:</div>288+          <div class="peach-pair-headline">Confirm this code matches on your phone:</div>289289           <div290290             class="peach-desktop-sas"291291             style="font-size:30px;font-weight:700;letter-spacing:0.32em;font-family:'IBM Plex Mono',monospace;color:var(--peach-accent);padding:6px 0 2px;"292292           >293293             {sas()}294294           </div>295-          <div class="peach-chirp-sub" style="max-width:240px;">295+          <div class="peach-pair-sub" style="max-width:240px;">296296             Only continue if this 6-digit code is identical on both screens. This is297297             what proves you're talking to your own device.298298           </div>@@ -309,11 +309,11 @@309309 310310       <Show when={phase() === "paired"}>311311         <div class="peach-desktop-paired">312-          <div class="peach-chirp-headline">Paired!</div>313-          <div class="peach-chirp-sub">312+          <div class="peach-pair-headline">Paired!</div>313+          <div class="peach-pair-sub">314314             {pairedDevice()?.deviceName ? `Connected to ${pairedDevice()!.deviceName}` : "Connected to your phone"}315315           </div>316-          <div class="peach-chirp-action">316+          <div class="peach-pair-action">317317             <button class="peach-btn peach-btn-primary" onClick={() => props.onBack()}>Done</button>318318           </div>319319         </div>@@ -321,9 +321,9 @@321321 322322       <Show when={phase() === "error"}>323323         <div class="peach-desktop-error">324-          <div class="peach-chirp-headline">{errorCopy(errorKind()).headline}</div>325-          <div class="peach-chirp-sub">{errorCopy(errorKind()).sub}</div>326-          <div class="peach-chirp-action">324+          <div class="peach-pair-headline">{errorCopy(errorKind()).headline}</div>325+          <div class="peach-pair-sub">{errorCopy(errorKind()).sub}</div>326+          <div class="peach-pair-action">327327             <button class="peach-btn peach-btn-ghost" onClick={() => props.onBack()}>Cancel</button>328328             <button class="peach-btn peach-btn-primary" onClick={() => startFlow()}>Try again</button>329329           </div>

view file

src/popup/views/Settings.tsx+2 −2
@@ -297,14 +297,14 @@297297 298298   async function loadPairedDevices() {299299     if (!isPro()) return;300-    const r = (await sendMessage({ type: "CHIRP_LIST_PAIRED_DEVICES" })) as {300+    const r = (await sendMessage({ type: "LIST_PAIRED_DEVICES" })) as {301301       ok: boolean;302302       data?: { devices: PairedDevice[] };303303     };304304     if (r.ok) setPairedDevices(r.data?.devices ?? []);305305   }306306   async function unpairDevice(deviceId: string) {307-    await sendMessage({ type: "CHIRP_UNPAIR_DEVICE", payload: { deviceId } });307+    await sendMessage({ type: "UNPAIR_DEVICE", payload: { deviceId } });308308     setConfirmUnpair(null);309309     await loadPairedDevices();310310   }

view file

src/shared/types.ts+3 −3
@@ -300,9 +300,9 @@300300   | "GET_LOCAL_IDENTITY"301301   | "GET_ADOPTION_MATERIAL"302302   | "COMPLETE_PAIRING"303-  | "CHIRP_LIST_PAIRED_DEVICES"304-  | "CHIRP_UNPAIR_DEVICE"305-  | "CHIRP_RENAME_LOCAL_DEVICE"303+  | "LIST_PAIRED_DEVICES"304+  | "UNPAIR_DEVICE"305+  | "RENAME_LOCAL_DEVICE"306306   // Code pairing. PAIR_WITH_CODE / CODE_PAIR_CONFIRM are popup→bg requests307307   // handled in the switch; CODE_PAIR_SAS / CODE_PAIR_RESULT are bg→popup pushes.308308   | "PAIR_WITH_CODE"

view file