A compact house ad that shares the extension's top row with search. The bar gives up half the row and the unit adapts to any panel width.
SearchTopbar · ui/blocks/SearchTopbar.vue — the row; gains the promo slot after QuickSearchQuickSearch · ui/components/QuickSearch.vue — untouched; goes from 100% of the row to flex: 1 1 50%HousePromo · house-ads system — new topbar variant; every class stays in the vetted house-promo family (R14).search-topbar row — two members trade one axis; the row is also the container the unit's width tiers query (R10)<script setup>
import { ref } from 'vue'
import QuickSearch from '@/components/QuickSearch.vue'
import HousePromo from '@/components/HousePromo.vue'
import { useAccountStore } from '@/store/account'
const account = useAccountStore()
const $searchTopbar = ref(null)
</script>
<template>
<nav id="sub-topbar" class="block search-topbar" ref="$searchTopbar">
<QuickSearch
:search-surface-ref="$searchTopbar"
menu-id="topbar"
search-id="search-topbar" />
<HousePromo v-if="!account.isPro" variant="topbar" />
</nav>
</template>
<!-- one link, no inner controls; creative comes from the house set -->
<a
v-if="variant === 'topbar'"
class="house-promo house-promo--topbar"
:aria-label="creative.aria"
@click.prevent="openGoPro()"
href="#"
>
<Emoji class="house-promo__emoji" :str="creative.emoji" />
<Text type="body/m-med" class="house-promo__line">
<b class="house-promo__lead">{{ creative.lead }}</b><span class="house-promo__tail"> · {{ creative.tail }}</span>
</Text>
<Text type="body/s-med" class="house-promo__chip">{{ creative.chip }}</Text>
</a>
<HousePromo variant="topbar" />
<!-- gate: v-if="!account.isPro" — guests + Free, same eligibility as the web house units -->
<!-- creative shown here: { emoji: '✨', lead: 'Go Pro', tail: 'Ad-free', chip: '$5/mo',
aria: 'Go Pro. Ad-free EmojiCopy for $5 a month.' } -->
/* the row — SearchTopbar.vue. Search goes from 100% to half;
the row becomes the container the unit's tiers query. */
.block.search-topbar {
display: flex;
align-items: center;
gap: var(--sp-4);
align-self: stretch;
container-type: inline-size;
container-name: searchrow;
}
.block.search-topbar .field-region { flex: 1 1 50%; width: auto; min-width: 0; }
/* (today: .field-region { width: 100% } — the slot build replaces it with the flex basis) */
/* the unit — HousePromo variant `topbar`. Matches the field's 48px
height and 12px radius; the 2px visible border tells it apart
from an input. */
.house-promo--topbar {
flex: 0 1 auto;
min-width: 0;
max-width: 50%;
display: flex;
align-items: center;
gap: var(--sp-2);
height: 48px;
padding: 0 var(--sp-4);
border: 2px solid var(--c-border-secondary);
border-radius: 12px;
background: var(--c-surface-primary);
text-decoration: none;
white-space: nowrap;
cursor: pointer;
transition: border-color .2s ease;
}
.house-promo--topbar:hover { border-color: light-dark(var(--green-700), var(--green-500)); }
.house-promo--topbar:focus-visible {
outline: 2px solid light-dark(var(--green-700), var(--green-500));
outline-offset: 2px;
}
.house-promo--topbar .house-promo__emoji { width: 18px; height: 18px; flex: none; }
.house-promo--topbar .house-promo__line {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
color: var(--c-text-secondary); /* type via Text f:body/m-med */
}
.house-promo--topbar .house-promo__lead {
font-weight: 700;
color: light-dark(var(--green-700), var(--green-500));
}
.house-promo--topbar .house-promo__chip {
flex: none;
padding: 2px var(--sp-2);
border-radius: var(--r-sm);
background: var(--green-700);
color: var(--c-white); /* type via Text f:body/s-med */
}
/* width tiers — the unit only ever gets smaller; search never
drops below its half of the row */
@container searchrow (max-width: 619px) {
.house-promo--topbar .house-promo__chip { display: none; }
}
@container searchrow (max-width: 459px) {
.house-promo--topbar .house-promo__tail { display: none; }
}
@container searchrow (max-width: 339px) {
.house-promo--topbar { padding: 0 var(--sp-3); }
.house-promo--topbar .house-promo__line { display: none; }
}
/* mini mode — rides the shipped body.app:mini switch, same as
.quick-search's own 36px override */
body.app\:mini .house-promo--topbar { height: 36px; padding: 0 var(--sp-3); }
body.app\:mini .house-promo--topbar .house-promo__line { font-size: 1.3rem; }
body.app\:mini .house-promo--topbar .house-promo__emoji { width: 16px; height: 16px; }
HousePromo · variant topbar — same unit as card A; nothing here is a new component.search-topbar + container queries — pure CSS adaptation, no JS resize listeners in the app (R10)/* the row is the container; the unit steps down in tiers and
ellipsizes between them. Search keeps flex: 1 1 50% and always
wins the tug — the unit's max-width: 50% caps it at half. */
.block.search-topbar {
display: flex;
align-items: center;
gap: var(--sp-4);
container-type: inline-size;
container-name: searchrow;
}
.block.search-topbar .field-region { flex: 1 1 50%; width: auto; min-width: 0; }
.house-promo--topbar { flex: 0 1 auto; min-width: 0; max-width: 50%; white-space: nowrap; }
.house-promo--topbar .house-promo__line { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
@container searchrow (max-width: 619px) {
.house-promo--topbar .house-promo__chip { display: none; }
}
@container searchrow (max-width: 459px) {
.house-promo--topbar .house-promo__tail { display: none; }
}
@container searchrow (max-width: 339px) {
.house-promo--topbar { padding: 0 var(--sp-3); }
.house-promo--topbar .house-promo__line { display: none; }
}
HousePromo · variant topbar — identical chrome across all three; only the creative object changes/* 1 · literal (shown in cards A + B) */
{ emoji: '✨', lead: 'Go Pro', tail: 'Ad-free', chip: '$5/mo',
aria: 'Go Pro. Ad-free EmojiCopy for $5 a month.' }
/* 2 · one Pro feature at a time — rotates per panel open */
{ emoji: '✨', lead: 'Ad-free', tail: 'with Pro', chip: '$5/mo', aria: 'Ad-free with Pro. EmojiCopy Pro is $5 a month.' }
{ emoji: '📚', lead: 'Unlimited collections', tail: 'with Pro', chip: '$5/mo', aria: 'Unlimited collections with Pro. EmojiCopy Pro is $5 a month.' }
{ emoji: '🧠', lead: 'Smart Recents', tail: 'with Pro', chip: '$5/mo', aria: 'Smart Recents with Pro. EmojiCopy Pro is $5 a month.' }
/* 3 · price line */
{ emoji: '✨', lead: 'EmojiCopy Pro', tail: '$5/mo', chip: 'cancel anytime',
aria: 'EmojiCopy Pro is $5 a month. Cancel anytime.' }
/* No take-specific CSS. All three render through the same
.house-promo--topbar rules from card A: bold green lead,
secondary tail, solid green-700 chip, identical tiers.
Take 2's longer leads ("Unlimited collections") ellipsize a
step earlier between tiers — acceptable, the tail drops next. */