The page that opens in a new tab right after someone installs the Chrome extension. It points at the puzzle icon in the toolbar and shows what that icon looks like. Two versions, differing only in which end of the arrow the icon sits on.
Click the puzzle icon in your toolbar, then click the pin next to EmojiCopy.
Questions or issues? Contact us
apps/chrome/public/installed.html — replaces the current 22-line file. No JS, no build step, no Vue. Vite copies this file straight through, so everything it needs lives inside it.<div class="ip">
<!-- the puzzle icon itself, sitting at the same distance from the right
edge as the real one, at the far end of the arrow -->
<span class="target" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13
2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7
2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7s2.7 1.21 2.7
2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>
</span>
<!-- the arrow, two paths, no library -->
<div class="ip__arrow" aria-hidden="true">
<svg viewBox="0 0 240 76" fill="none">
<path class="__trail" d="M8 70 C 32 44, 98 24, 230 22" stroke="currentColor"
stroke-width="3" stroke-linecap="round" stroke-dasharray="1 9"/>
<path d="M216 13 L 234 22 L 216 31" stroke="currentColor"
stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<img class="ip__mark" src="https://cdn.joypixels.com/emojicopy/branding/1.0/emojicopy-icon.png" alt="">
<h1 class="ip__title">One last step.</h1>
<p class="ip__sub">Click the puzzle icon in your toolbar, then click the pin next to EmojiCopy.</p>
<p class="ip__foot">Questions or issues?
<a href="https://joypixels.com/contact">Contact us</a></p>
</div>
.ip {
/* How far Chrome's extensions (puzzle) icon sits from the RIGHT edge of
the window. Chrome right-anchors that icon, so this one offset holds
at every window width. The target and the arrow both key off it. */
--puzzle-right: 97px;
position: relative;
font-family: Inter, system-ui, sans-serif;
color: #0F1012; /* metal-950 */
background: #fff;
padding: 40px 32px 48px;
text-align: center;
min-height: 320px;
}
.ip__mark { width: 52px; height: 52px; margin: 0 auto 16px; display: block; }
.ip__title { font-family: 'DM Sans', system-ui, sans-serif; font-weight: 900;
font-size: 32px; line-height: 1.1; letter-spacing: -.03em; margin-bottom: 10px; }
.ip__sub { font-size: 16px; line-height: 1.55; color: #616678; /* metal-600 */
max-width: 34ch; margin: 0 auto; }
.ip__foot { margin-top: 40px; font-size: 13px; color: #7C8292; } /* metal-500 */
.ip__foot a { color: #20AD03; font-weight: 700; text-decoration: none; } /* green-700 */
.ip__foot a:hover { text-decoration: underline; }
/* the target · deliberately NOT a button. Just the glyph, in the same grey
as the real toolbar icon: no chip, no ring, no pointer events. */
.target {
position: absolute; top: 6px; right: calc(var(--puzzle-right) - 18px);
width: 36px; height: 36px; display: grid; place-items: center;
color: #4B4F5C; /* metal-700 */
pointer-events: none; /* nothing to click, so nothing to hover either */
}
.target svg { width: 22px; height: 22px; display: block; }
/* the arrow · the dots travel along it toward the icon */
.ip__arrow {
position: absolute; top: 2px; right: calc(var(--puzzle-right) + 27px);
width: 240px; height: 76px;
pointer-events: none; color: #30D909; /* green-600 */
}
.ip__arrow svg { width: 100%; height: 100%; overflow: visible; }
.ip__arrow .__trail { animation: trail-flow 1s linear infinite; }
@keyframes trail-flow {
to { stroke-dashoffset: -10; } /* one dash + one gap, so it loops seamlessly */
}
@media (prefers-reduced-motion: reduce) {
.ip__arrow .__trail { animation: none; }
}
/* Narrow windows: the copy needs the full width, and the toolbar icons
crowd together, so the pointer stops being accurate. Drop it. */
@media (max-width: 720px) {
.ip__arrow, .target { display: none; }
}
Click the puzzle icon in your toolbar, then click the pin next to EmojiCopy.
Questions or issues? Contact us
apps/chrome/public/installed.html — replaces the current 22-line file. No JS, no build step, no Vue. Vite copies this file straight through, so everything it needs lives inside it.<div class="ip ip--start">
<!-- the puzzle icon itself, parked at the START of the arrow so it reads
as "this icon" before the arrow says where it lives -->
<span class="target" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13
2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7
2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7s2.7 1.21 2.7
2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>
</span>
<!-- the arrow, two paths, no library -->
<div class="ip__arrow" aria-hidden="true">
<svg viewBox="0 0 240 100" fill="none">
<path class="__trail" d="M8 74 C 80 84, 170 74, 226 18" stroke="currentColor"
stroke-width="3" stroke-linecap="round" stroke-dasharray="1 9"/>
<path d="M209 21 L 228 16 L 223 35" stroke="currentColor"
stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<img class="ip__mark" src="https://cdn.joypixels.com/emojicopy/branding/1.0/emojicopy-icon.png" alt="">
<h1 class="ip__title">One last step.</h1>
<p class="ip__sub">Click the puzzle icon in your toolbar, then click the pin next to EmojiCopy.</p>
<p class="ip__foot">Questions or issues?
<a href="https://joypixels.com/contact">Contact us</a></p>
</div>
.ip {
/* How far Chrome's extensions (puzzle) icon sits from the RIGHT edge of
the window. Chrome right-anchors that icon, so this one offset holds
at every window width. The target and the arrow both key off it. */
--puzzle-right: 97px;
position: relative;
font-family: Inter, system-ui, sans-serif;
color: #0F1012; /* metal-950 */
background: #fff;
padding: 40px 32px 48px;
text-align: center;
min-height: 320px;
}
.ip__mark { width: 52px; height: 52px; margin: 0 auto 16px; display: block; }
.ip__title { font-family: 'DM Sans', system-ui, sans-serif; font-weight: 900;
font-size: 32px; line-height: 1.1; letter-spacing: -.03em; margin-bottom: 10px; }
.ip__sub { font-size: 16px; line-height: 1.55; color: #616678; /* metal-600 */
max-width: 34ch; margin: 0 auto; }
.ip__foot { margin-top: 40px; font-size: 13px; color: #7C8292; } /* metal-500 */
.ip__foot a { color: #20AD03; font-weight: 700; text-decoration: none; } /* green-700 */
.ip__foot a:hover { text-decoration: underline; }
/* the target · deliberately NOT a button. Just the glyph, in the same grey
as the real toolbar icon: no chip, no ring, no pointer events.
Here it sits at the START of the arrow, level with the tail, so it reads
as a label for the thing the arrow then goes and finds. It no longer keys
off --puzzle-right; only the arrow tip does. */
.ip--start .target {
position: absolute; top: 58px; right: 326px;
width: 36px; height: 36px; display: grid; place-items: center;
color: #4B4F5C; /* metal-700 */
pointer-events: none; /* nothing to click, so nothing to hover either */
}
.target svg { width: 22px; height: 22px; display: block; }
/* the arrow · flipped arc. It leaves the icon almost level, dips, then
sweeps up hard into the toolbar. The dots travel along it. */
.ip__arrow {
position: absolute; top: 2px; right: calc(var(--puzzle-right) - 12px);
width: 240px; height: 100px;
pointer-events: none; color: #30D909; /* green-600 */
}
.ip__arrow svg { width: 100%; height: 100%; overflow: visible; }
.ip__arrow .__trail { animation: trail-flow 1s linear infinite; }
@keyframes trail-flow {
to { stroke-dashoffset: -10; } /* one dash + one gap, so it loops seamlessly */
}
@media (prefers-reduced-motion: reduce) {
.ip__arrow .__trail { animation: none; }
}
/* Narrow windows: the copy needs the full width, and the toolbar icons
crowd together, so the pointer stops being accurate. Drop it. */
@media (max-width: 720px) {
.ip__arrow, .target { display: none; }
}