PageSourceSearch

https://indiehq.com/

html indiehq.com collected 2026-10-02 13:43:15 UTC 97,098 bytes, 1,523 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%230D0D12'/%3E%3Cpath d='M16 4l3.09 6.26L26 11.27l-5 4.87L22.18 23 16 19.77 9.82 23 11 16.14 6 11.27l6.91-1.01L16 4z' fill='%2321CF7E'/%3E%3C/svg%3E">
5<!-- Google Consent Mode default — runs first; CookieYes loads last per GCM docs -->
5<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('consent','default',{ad_storage:'denied',ad_user_data:'denied',ad_personalization:'denied',analytics_storage:'denied',functionality_storage:'granted',security_storage:'granted',wait_for_update:500});</script>
5
6<!-- Google tag (gtag.js) -->
vendor: 97 bytes, lines 6-7
6
7<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" async src="https://www.googletagmanager.com/gtag/js?id=
7G-9XK9DCMS5N
vendor: 12 bytes, line 7
7"></script>
8<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
vendor: 118 bytes, line 8
8window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','
8G-9XK9DCMS5N
vendor: 3 bytes, line 8
8');
8</script>
8<!-- Start cookieyes banner -->
8<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" id="cookieyes" type="text/javascript" src="https://cdn-cookieyes.com/client_data/7603e8a4c81a65b5baf2b18efc2a925b/script.js"></script>
8<!-- End cookieyes banner -->
9
10<meta charset="UTF-8">
11<meta name="viewport" content="width=device-width, initial-scale=1.0">
12<title>IndieHQ — Everything indie agencies need. One front door.</title>
13<!-- Indie HQ homepage · Homepage 26.0706.5 · see CHANGELOG.md -->
14<meta name="version" content="26.0708.3">
15<meta name="description" content="IndieHQ is the home for everything Indie Agency News has built for independent agencies — events, shows, tools, community, and coaching, all in one place.">
16<style>
17  :root {
18    --ink: #0D0D12;          /* near-black */
19    --paper: #FAFAF8;        /* warm off-white */
20    --accent: #21CF7E;       /* IAN electric green — the Indie@Cannes colorway */
21    --accent-deep: #0C9B53;  /* green that reads on light backgrounds */
22    --grey: #56565E;
23    --line: #0D0D12;         /* borders are ink — hard, editorial */
24    --tint: #E9FAF0;         /* light green hover tint */
25  }
26  * { margin: 0; padding: 0; box-sizing: border-box; }
27  /* No orphans: balance headings, prettify body */
28  h1, h2, h3, h4 { text-wrap: balance; }
29  p, li, blockquote, figcaption { text-wrap: pretty; }
30  html { scroll-behavior: smooth; }
31  body {
32    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
33    background: var(--paper);
34    color: var(--ink);
35    line-height: 1.5;
36    -webkit-font-smoothing: antialiased;
37  }
38  a { color: inherit; text-decoration: none; }
39  .wrap { max-width: 1200px; margin: 0 auto; padding: 0 28px; }
40
41  /* ---------- Type ---------- */
42  h1, h2, h3 { font-weight: 800; letter-spacing: -0.03em; line-height: 1.05; }
43  .kicker {
44    display: inline-block;
45    font-size: .78rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
46    color: var(--accent-deep); margin-bottom: 16px;
47  }
48  .dark .kicker { color: var(--accent); }
49
50  /* ---------- Buttons ---------- */
51  .btn {
52    display: inline-block; padding: 14px 28px;
53    font-weight: 700; font-size: .95rem; cursor: pointer;
54    border: 2px solid var(--ink); border-radius: 4px;
55    background: transparent; color: var(--ink);
56    transition: background .15s ease, color .15s ease, border-color .15s ease;
57  }
58  .btn:hover { background: var(--ink); color: var(--paper); }
59  .btn-solid { background: var(--ink); color: var(--paper); }
60  .btn-solid:hover { background: var(--accent); border-color: var(--accent); color: var(--ink); }
61  .btn-accent { background: var(--accent); border-color: var(--accent); color: var(--ink); }
62  .btn-accent:hover { background: var(--ink); border-color: var(--ink); color: var(--accent); }
63  .dark .btn { border-color: var(--paper); color: var(--paper); }
64  .dark .btn:hover { background: var(--paper); color: var(--ink); }
65
66  /* ---------- Header ---------- */
67  header {
68    position: sticky; top: 0; z-index: 50;
69    background: var(--paper);
70    border-bottom: 2px solid var(--ink);
71  }
72  .header-inner { display: flex; align-items: center; gap: 36px; height: 72px; }
73  .wordmark { font-weight: 800; font-size: 1.3rem; letter-spacing: -.02em; white-space: nowrap; }
74  .wordmark .hq { color: var(--accent-deep); }
75  nav.main { display: flex; gap: 26px; font-size: .95rem; font-weight: 600; }
76  nav.main a { padding: 4px 0; border-bottom: 2px solid transparent; }
77  nav.main a:hover { border-bottom-color: var(--accent); }
78  .header-cta { margin-left: auto; display: flex; align-items: center; gap: 12px; }
79  .header-cta .btn { padding: 10px 20px; font-size: .88rem; }
80  .login-link { font-weight: 700; font-size: .92rem; margin-right: 4px; }
81  .login-link:hover { color: var(--accent-deep); }
82  /* mobile nav (hamburger) */
83  .nav-toggle { display: none; background: none; border: 0; cursor: pointer; padding: 8px; margin-left: auto; }
84  .nav-toggle span { display: block; width: 24px; height: 2.5px; background: var(--ink); border-radius: 2px; margin: 5px 0; transition: .2s; }
85  .mob-only { display: none !important; }
86  @media (max-width: 960px) {
87    .nav-toggle { display: block; }
88    .header-cta { display: none; }
89    .header-inner { position: relative; gap: 16px; }
90    nav.main { display: none; position: absolute; top: 100%; left: 0; right: 0; background: var(--paper); border-bottom: 2px solid var(--ink); box-shadow: 0 14px 26px rgba(13,13,18,.10); flex-direction: column; gap: 0; padding: 6px 0; }
91    nav.main.open { display: flex; }
92    nav.main a { padding: 15px 22px; border-bottom: 1px solid rgba(13,13,18,.08); font-size: 1.05rem; }
93    nav.main a:last-child { border-bottom: 0; }
94    .mob-only { display: block !important; }
95  }
96
97  /* ---------- Hero (black, statement) ---------- */
98  .hero {
99    background: var(--ink); color: var(--paper);
100    padding: 110px 0 100px;
101  }
102  .hero h1 {
103    font-size: clamp(2.8rem, 7vw, 5.2rem);
104    max-width: 15ch;
105  }
106  .hero h1 .accent { color: var(--accent); }
107  .hero .flag { width: 64px; height: 12px; background: var(--accent); margin-bottom: 36px; }
108  .hero p { margin-top: 28px; font-size: 1.2rem; max-width: 560px; color: #C9C9CF; }
109  .hero-cta { margin-top: 40px; display: flex; gap: 14px; flex-wrap: wrap; }
110
111  /* ---------- Sections ---------- */
112  section { padding: 88px 0; }
113  .section-head { margin-bottom: 44px; max-width: 720px; }
114  .section-head h2 { font-size: clamp(1.9rem, 4vw, 2.9rem); }
115  .section-head p { margin-top: 14px; font-size: 1.08rem; color: var(--grey); }
116  .dark .section-head p { color: #C9C9CF; }
117  .see-all {
118    display: inline-block; margin-top: 18px;
119    font-weight: 700; border-bottom: 2px solid var(--accent);
120    padding-bottom: 2px;
121  }
122  .see-all:hover { color: var(--accent-deep); }
123  .dark .see-all:hover { color: var(--accent); }
124
125  /* ---------- Card grids (hard-edged, bordered) ---------- */
126  .grid { display: grid; gap: 0; border: 2px solid var(--line); }
127  .grid-3 { grid-template-columns: repeat(3, 1fr); }
128  .grid-2 { grid-template-columns: repeat(2, 1fr); }
129  .grid-2 .cell:last-child { border-right: none; }
130  /* Events — horizontal rail: shows every upcoming event, swipe for more (nothing hidden in a 3-cap) */
131  .evrail { display: flex; overflow-x: auto; border: 2px solid var(--line);
132    scroll-snap-type: x proximity; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
133  .evrail::-webkit-scrollbar { height: 8px; }
134  .evrail::-webkit-scrollbar-thumb { background: var(--line); }
135  .evrail::-webkit-scrollbar-track { background: transparent; }
136  .evrail .cell { flex: 0 0 300px; scroll-snap-align: start; }
137  @media (max-width: 600px) { .evrail .cell { flex: 0 0 82%; } }
138  .evfoot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 14px; }
139  .evfoot .see-all { margin: 0; }
140  .evnav { display: flex; gap: 8px; }
141  .evbtn { width: 42px; height: 42px; border: 2px solid var(--line); background: #fff; color: var(--ink);
142    font-size: 22px; line-height: 1; cursor: pointer; display: grid; place-items: center;
143    transition: background .12s, border-color .12s, opacity .12s; }
144  .evbtn:hover:not(:disabled) { background: var(--ink); color: var(--paper); border-color: var(--ink); }
145  .evbtn:disabled { opacity: .28; cursor: default; }
146  .cell .evby { font-size: .78rem; color: var(--grey); margin-top: 8px; letter-spacing: .01em; }
147  .cell .evby b { color: var(--ink); font-weight: 700; }
148  .cell-feature { display: block; padding: 34px 32px; border: 2px solid var(--line); border-top: none; cursor: pointer; transition: background .15s; }
149  .cell-feature .badge { position: static; }
150  .cell-feature h3 { font-size: 1.7rem; margin: 14px 0 10px; }
151  .cell-feature p { max-width: 620px; font-size: 1rem; }
152  .cell-feature .go { margin-top: 20px; display: inline-block; font-weight: 700; }
153  .feature-tag { font-size: .72rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--accent-deep); margin-left: 12px; }
154  .cell-feature:hover .go { color: var(--accent-deep); }
155  .cell {
156    padding: 32px 28px; border-right: 2px solid var(--line);
157    display: flex; flex-direction: column; position: relative;
158    background: var(--paper);
159    transition: background .15s ease;
160  }
161  .cell:last-child { border-right: none; }
162  .cell:hover { background: var(--tint); }
163  .cell h3 { font-size: 1.3rem; margin-bottom: 10px; }
164  .cell p { font-size: .95rem; color: var(--grey); flex: 1; }
165  .cell .go { margin-top: 22px; font-weight: 700; font-size: .92rem; }
166  .cell:hover .go { color: var(--accent-deep); }
167  .badge {
168    position: absolute; top: 0; right: 0;
169    font-size: .68rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
170    padding: 6px 12px; background: var(--accent); color: var(--ink);
171  }
172  .event-date { font-weight: 800; font-size: .85rem; letter-spacing: .06em; text-transform: uppercase; color: var(--accent-deep); margin-bottom: 14px; }
173  /* ---- Summit feature (page-width, highlighted) ---- */
174  .summit-feature { display:grid; grid-template-columns:1.4fr 1fr; gap:34px; align-items:center;
175    background:var(--ink); color:var(--paper); border:2px solid var(--ink); border-radius:6px;
176    padding:36px 40px; margin-bottom:26px; position:relative; overflow:hidden; }
177  .summit-feature::before { content:""; position:absolute; top:-40%; right:-8%; width:52%; height:180%;
178    background:radial-gradient(circle, rgba(33,222,115,.16) 0%, transparent 62%); pointer-events:none; }
179  .summit-feature > * { position:relative; z-index:1; }
180  .summit-kick { font-size:.72rem; font-weight:800; letter-spacing:.14em; text-transform:uppercase; color:var(--accent); margin-bottom:12px; }
181  .summit-feature h3 { font-size:clamp(1.7rem,3vw,2.5rem); line-height:1.0; letter-spacing:-.02em; }
182  .summit-where { margin-top:12px; font-size:1rem; color:#C9C9CF; }
183  .summit-where strong { color:var(--paper); }
184  .summit-tier { margin-top:16px; font-size:.95rem; color:#C9C9CF; }
185  .summit-tier b { color:var(--accent); font-weight:800; }
186  .summit-seats { margin-top:18px; max-width:420px; }
187  .summit-bar { height:9px; background:rgba(255,255,255,.15); border-radius:99px; overflow:hidden; margin-bottom:9px; }
188  .summit-bar > i { display:block; height:100%; background:var(--accent); border-radius:99px; }
189  .summit-seats .lab { font-size:.82rem; font-weight:700; color:#9A9AA4; }
190  .summit-seats .lab b { color:var(--paper); }
191  .summit-right { text-align:center; }
192  .countdown { display:flex; gap:9px; justify-content:center; margin-bottom:20px; }
193  .cd-box { background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.16); border-radius:8px; padding:12px 0; min-width:64px; flex:0 1 64px; }
194  .cd-box .n { font-size:1.9rem; font-weight:800; letter-spacing:-.03em; line-height:1; font-variant-numeric:tabular-nums; }
195  .cd-box .l { font-size:.6rem; font-weight:800; text-transform:uppercase; letter-spacing:.08em; color:#8C8C95; margin-top:6px; }
196  .summit-cta { display:inline-block; background:var(--accent); color:var(--ink); font-weight:800; padding:15px 28px; border-radius:4px; font-size:1rem; transition:background .15s; }
197  .summit-feature:hover .summit-cta { background:var(--paper); }
198  .summit-sub { display:block; margin-top:10px; font-size:.7rem; letter-spacing:.06em; text-transform:uppercase; color:#8C8C95; }
199  @media (max-width:760px){ .summit-feature { grid-template-columns:1fr; padding:28px 22px; gap:24px; } .summit-right { text-align:left; } .countdown { justify-content:flex-start; } .cd-box { flex:1 1 0; } }
200  .cell-img { height: 158px; background: #101018 center/cover no-repeat; margin: -32px -28px 22px; border-bottom: 2px solid var(--line); }
201
202  /* ---------- Live Tracker (prominent black band) ---------- */
203  #tracker {
204    background: var(--ink); color: var(--paper);
205    border-top: 2px solid var(--ink); border-bottom: 2px solid var(--ink);
206    padding: 80px 0;
207    overflow: hidden;
208  }
209  .live-pill {
210    display: inline-flex; align-items: center; gap: 8px;
211    font-size: .75rem; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
212    color: var(--ink); background: var(--accent);
213    padding: 6px 14px; margin-bottom: 18px;
214  }
215  .live-dot {
216    width: 8px; height: 8px; border-radius: 50%; background: var(--ink);
217    animation: blink 1.4s ease-in-out infinite;
218  }
219  @keyframes blink { 0%,100% { opacity: 1; } 50% { opacity: .25; } }
220  #tracker h2 { font-size: clamp(2rem, 4.5vw, 3.2rem); max-width: 18ch; }
221  #tracker .tracker-sub { margin-top: 14px; font-size: 1.1rem; color: #C9C9CF; max-width: 560px; }
222  .tracker-panel { margin-top: 30px; border: 2px solid var(--paper); border-radius: 10px; overflow: hidden; background: #fff; box-shadow: 0 24px 70px rgba(0,0,0,.38); }
223  .tracker-credit { margin-top: 16px; font-size: .82rem; letter-spacing: .02em; color: #8E8E98; font-weight: 600; }
224  .tracker-credit a { color: var(--accent); text-decoration: none; border-bottom: 1px solid rgba(33,222,115,.45); padding-bottom: 1px; }
225  .tracker-credit a:hover { color: #fff; border-bottom-color: #fff; }
226  .pixel-strip { display: flex; gap: 6px; margin: 40px 0 34px; }
227  .pixel-col { display: flex; flex-direction: column; gap: 6px; flex: 1; }
228  .px {
229    width: 100%; aspect-ratio: 1; background: var(--accent);
230    opacity: .15;
231  }
232  .px.on { opacity: 1; }
233  .ticker-window { border-top: 2px solid var(--paper); border-bottom: 2px solid var(--paper); padding: 18px 0; }
234  .ticker-track {
235    display: flex; gap: 64px; white-space: nowrap; width: max-content;
236    animation: ticker 40s linear infinite;
237  }
238  .ticker-window:hover .ticker-track { animation-play-state: paused; }
239  @keyframes ticker { from { transform: translateX(0); } to { transform: translateX(-50%); } }
240  .tick { font-weight: 700; font-size: 1.02rem; }
241  .tick .t-tag { color: var(--accent); font-size: .72rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; margin-right: 12px; }
242  #tracker .hero-cta { margin-top: 36px; }
243
244  /* ---------- News (editorial list) ---------- */
245  #news { background: #F1F1EC; border-bottom: 2px solid var(--ink); }
246  #meet { background: var(--paper); border-bottom: 2px solid var(--ink); }
247  .news-list { border-top: 2px solid var(--ink); }
248  .news-item {
249    display: flex; gap: 28px; align-items: baseline;
250    padding: 26px 4px; border-bottom: 2px solid var(--ink);
251    transition: background .15s ease;
252  }
253  .news-item:hover { background: var(--tint); }
254  .news-item .tag {
255    flex: 0 0 130px; font-size: .72rem; font-weight: 800;
256    letter-spacing: .1em; text-transform: uppercase; color: var(--accent-deep);
257  }
258  .news-item h3 { font-size: clamp(1.05rem, 2.2vw, 1.45rem); font-weight: 700; letter-spacing: -.01em; }
259  .news-item .arrow { margin-left: auto; font-weight: 800; opacity: 0; transition: opacity .15s ease; }
260  .news-item:hover .arrow { opacity: 1; }
261
262  /* ---------- Member HQ (black band) ---------- */
263  #members { background: var(--ink); color: var(--paper); }
264  #members .grid { border-color: var(--paper); }
265  #members .cell { background: var(--ink); border-color: var(--paper); }
266  #members .cell:hover { background: #14241A; }
267  #members .cell p { color: #C9C9CF; }
268  #members .cell-feature { background: #0F1A13; border-color: var(--paper); }
269  #members .cell-feature:hover { background: #14241A; }
270  #members .cell-feature p { color: #C9C9CF; }
271  #members .feature-tag { color: var(--accent); }
272  #members .mh-group { display:flex; align-items:center; gap:10px; margin:34px 0 14px; }
273  #members .mh-group:first-of-type { margin-top:26px; }
274  #members .mh-group .bar { width:4px; height:16px; background:var(--accent); flex:0 0 auto; }
275  #members .mh-group h3 { font-size:.82rem; font-weight:800; letter-spacing:.12em; text-transform:uppercase; color:var(--accent); margin:0; }
276
277  /* ---------- Front Desk (premium) ---------- */
278  #front-desk .desk {
279    border: 2px solid var(--ink); padding: 56px 48px;
280    display: grid; grid-template-columns: 1fr 1fr; gap: 48px; align-items: center;
281    position: relative;
282  }
283  #front-desk h2 { font-size: clamp(1.9rem, 4vw, 2.9rem); }
284  #front-desk .desk-copy p { margin-top: 14px; font-size: 1.05rem; color: var(--grey); }
285  .desk-form { display: flex; flex-direction: column; gap: 12px; }
286  .desk-form input {
287    padding: 16px 18px; font-size: 1rem; font-family: inherit;
288    border: 2px solid var(--ink); border-radius: 4px; background: #fff; outline: none;
289  }
290  .desk-form input:focus { border-color: var(--accent-deep); }
291  .desk-note { font-size: .85rem; color: var(--grey); }
292  /* ---------- Feature bands (Partners / Commons) ---------- */
293  .band { border: 2px solid var(--ink); padding: 48px 44px; display: grid; grid-template-columns: 1.6fr 1fr; gap: 40px; align-items: center; }
294  .band .kicker { margin-bottom: 12px; }
295  .band h2 { font-size: clamp(1.8rem, 4vw, 2.7rem); }
296  .band p { margin-top: 14px; font-size: 1.05rem; color: var(--grey); max-width: 640px; }
297  .band-cta { text-align: right; }
298  .partners-feature { background: var(--tint); }
299  #sister-cities { padding-top: 0; }
300  #sister-cities .band { background: var(--tint); border-top: 8px solid var(--accent); }
301  .band p.sc-runs { margin-top: 18px; font-size: .92rem; color: var(--ink); }
302  .sc-runs b { font-weight: 800; }
303  .sc-runs span, #sister-cities .nw { white-space: nowrap; }
304  .pchips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
305  .pchips span { font-size: .8rem; font-weight: 700; border: 1.5px solid var(--ink); border-radius: 99px; padding: 6px 13px; background: #fff; }
306  @media (max-width: 760px) { .band { grid-template-columns: 1fr; gap: 24px; padding: 32px 26px; } .band-cta { text-align: left; } }
307
308  /* ---------- Footer (black) ---------- */
309  footer {
310    background: var(--ink); color: var(--paper);
311    padding: 64px 0 72px; font-size: .92rem;
312  }
313  .footer-grid { display: flex; justify-content: space-between; gap: 40px; flex-wrap: wrap; }
314  .footer-brand { max-width: 320px; }
315  .footer-brand .wordmark { font-size: 1.4rem; }
316  .footer-brand .wordmark .hq { color: var(--accent); }
317  .footer-brand p { margin-top: 12px; color: #9A9AA4; }
318  .footer-links { display: flex; gap: 56px; flex-wrap: wrap; }
319  .footer-links h4 { font-size: .75rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: #9A9AA4; margin-bottom: 14px; }
320  .footer-links ul { list-style: none; display: flex; flex-direction: column; gap: 9px; }
321  .footer-links a:hover { color: var(--accent); }
322  .footer-legal { margin-top: 48px; padding-top: 24px; border-top: 1px solid #2A2A33; color: #9A9AA4; font-size: .82rem; }
323
324  /* ---------- Responsive ---------- */
325  @media (max-width: 960px) {
326    .grid-3 { grid-template-columns: repeat(2, 1fr); }
327    .grid-3 .cell:nth-child(2n) { border-right: none; }
328    .grid-3 .cell:nth-child(-n+2) { border-bottom: 2px solid var(--line); }
329    #front-desk .desk { grid-template-columns: 1fr; padding: 36px 28px; }
330    .pixel-strip .pixel-col:nth-child(n+25) { display: none; }
331  }
332  @media (max-width: 600px) {
333    .grid-3 { grid-template-columns: 1fr; }
334    .grid-2 { grid-template-columns: 1fr; }
335    .cell { border-right: none !important; border-bottom: 2px solid var(--line); }
336    .grid .cell:last-child { border-bottom: none; }
337    .hero { padding: 72px 0 64px; }
338    .news-item { flex-direction: column; gap: 6px; }
339    .news-item .tag { flex: none; }
340    .pixel-strip .pixel-col:nth-child(n+15) { display: none; }
341  }
342{RULE}
343  /* mobile-stack guard */
344  @media (max-width:600px){ .grid,.grid-2,.grid-3,.grid-4,.three,.cards,.stats,.nums,.board,.tiles,.topics,.solo{ grid-template-columns:1fr !important; } }
345
346  /* ---- Tighter, app-like spacing: tablet + mobile ---- */
347  .scoreboard-feature { background: var(--tint); }
348  @media (max-width: 1024px){ section{ padding:60px 0; } #tracker{ padding:60px 0; } .section-head{ margin-bottom:32px; } .hero{ padding:88px 0 68px; } }
349  @media (max-width: 700px){ .wrap{ padding:0 20px; } section{ padding:42px 0; } #tracker{ padding:42px 0; } .section-head{ margin-bottom:20px; } .hero{ padding:60px 0 48px; } .hero p{ font-size:1.06rem; margin-top:18px; } .hero-cta{ margin-top:26px; } .band{ padding:26px 22px; } }
350  @media(max-width:600px){ .wordmark img, .ihq-logo{ height:40px !important; } }
351  /* QuickCoach two-column block stacks on phones */
352  @media (max-width: 760px){ .qc-split{ grid-template-columns:1fr !important; gap:26px !important; } }
353  /* clearance for the fixed Holdco Watch ticker */
354  body{ padding-bottom:80px; }
355
356  /* ===== Member-first landing: when signed in, lead with what you can do ===== */
357  .member-hero{ display:none; }
358  html.ihq-member .hero{ display:none; }            /* hide the prospect pitch for members */
359  html.ihq-member .member-hero{ display:block; background:var(--ink,#0D0D12); color:#fff; padding:64px 0 56px; }
360  .member-hero .wrap{ max-width:1100px; margin:0 auto; padding:0 32px; }
361  .member-hero .mh-kicker{ font-size:.78rem; font-weight:800; letter-spacing:.16em; text-transform:uppercase; color:var(--accent,#21DE73); margin-bottom:12px; }
362  .member-hero h1{ font-size:clamp(2rem,4vw,3rem); line-height:1.03; letter-spacing:-.03em; margin:0; text-wrap:balance; }
363  .member-hero h1 .accent{ color:var(--accent,#21DE73); }
364  .member-hero .mh-sub{ color:#C8C8D0; font-size:1.1rem; margin:14px 0 26px; max-width:640px; text-wrap:pretty; }
365  .member-hero .mh-chips{ display:flex; flex-wrap:wrap; gap:10px; }
366  .member-hero .mh-chips a{ display:inline-flex; align-items:center; gap:7px; background:transparent; color:#fff; border:1.5px solid rgba(255,255,255,.32); border-radius:999px; padding:9px 16px; font-size:.95rem; font-weight:700; text-decoration:none; transition:background .12s ease,color .12s ease,border-color .12s ease; }
367  .member-hero .mh-chips a:hover{ background:var(--accent,#21DE73); color:var(--ink,#0D0D12); border-color:var(--accent,#21DE73); }
368  .member-hero .mh-chips a.primary{ background:var(--accent,#21DE73); color:var(--ink,#0D0D12); border-color:var(--accent,#21DE73); }
369  .member-hero .mh-chips a.primary:hover{ filter:brightness(1.05); }
370  html.ihq-member #members{ border-top:none; }
371  .member-hero .mh-news{ margin-top:30px; border-top:1px solid rgba(255,255,255,.18); padding-top:22px; }
372  .member-hero .mh-news-h{ font-size:.72rem; font-weight:800; letter-spacing:.14em; text-transform:uppercase; color:#9A9AA2; margin-bottom:14px; }
373  .member-hero .mh-news-list{ display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:12px; }
374  .member-hero .mh-news-item{ display:block; text-decoration:none; color:#fff; border:1px solid rgba(255,255,255,.16); border-radius:8px; padding:13px 15px; transition:border-color .12s ease,background .12s ease; }
375  .member-hero .mh-news-item:hover{ border-color:var(--accent,#21DE73); background:rgba(255,255,255,.05); }
376  .member-hero .mh-news-item .nt{ display:inline-block; font-size:.62rem; font-weight:800; letter-spacing:.1em; text-transform:uppercase; color:var(--accent,#21DE73); margin-bottom:6px; }
377  .member-hero .mh-news-item h4{ font-size:.98rem; font-weight:700; line-height:1.25; margin:0; letter-spacing:-.01em; text-wrap:pretty; }
378  /* Indie Stages spotlight — the big Member HQ feature */
379  .stage-spotlight{ display:flex; gap:28px; flex-wrap:wrap; align-items:center; justify-content:space-between; background:#FAFAF8; color:#0D0D12; border:2px solid #21CF7E; border-radius:16px; padding:30px 32px; margin-bottom:22px; text-decoration:none;
379 transition:box-shadow .15s ease; }
380  .stage-spotlight:hover{ box-shadow:0 0 0 4px rgba(33,207,126,.28); }
381  .stage-spotlight .ss-left{ flex:1; min-width:280px; }
382  .stage-spotlight .ss-tag{ font-size:.7rem; font-weight:800; letter-spacing:.12em; text-transform:uppercase; color:#0C9B53; }
383  .stage-spotlight h3{ font-size:1.9rem; margin:10px 0 10px; letter-spacing:-.02em; line-height:1.05; }
384  .stage-spotlight p{ color:#333; margin:0 0 18px; max-width:54ch; font-size:1rem; }
385  .stage-spotlight .ss-cta{ display:inline-block; background:#0D0D12; color:#fff; font-weight:800; padding:12px 24px; border-radius:9px; font-size:.98rem; }
386  .stage-spotlight:hover .ss-cta{ background:#21CF7E; color:#0D0D12; }
387  .stage-spotlight .ss-right{ display:flex; flex-wrap:wrap; gap:8px; max-width:300px; }
388  .stage-spotlight .ss-chip{ border:1.5px solid #0D0D12; border-radius:20px; padding:6px 13px; font-size:.8rem; font-weight:700; }
389  @media(max-width:640px){ .stage-spotlight h3{ font-size:1.5rem; } .stage-spotlight .ss-right{ max-width:none; } }
390  @media(max-width:700px){ html.ihq-member .member-hero{ padding:40px 0 34px; } .member-hero .wrap{ padding:0 20px; } .member-hero .mh-sub{ font-size:1rem; } }
391</style>
392<!-- SEO -->
393<link rel="canonical" href="https://indiehq.com/">
394<meta property="og:type" content="website">
395<meta property="og:site_name" content="IndieHQ">
396<meta property="og:title" content="IndieHQ — Everything indie agencies need. One front door.">
397<meta property="og:description" content="IndieHQ is the home for everything Indie Agency News has built for independent agencies — events, shows, tools, community, and coaching, all in one place.">
398<meta property="og:url" content="https://indiehq.com/">
399<meta property="og:image" content="https://media.indiehq.com/IndieHQ%20Logos/indiehq_1200x630_vmheum.png">
400<meta property="og:image:width" content="1200">
401<meta property="og:image:height" content="630">
402<meta name="twitter:card" content="summary_large_image">
403<meta name="twitter:title" content="IndieHQ — Everything indie agencies need. One front door.">
404<meta name="twitter:description" content="IndieHQ is the home for everything Indie Agency News has built for independent agencies — events, shows, tools, community, and coaching, all in one place.">
405<meta name="twitter:image" content="https://media.indiehq.com/IndieHQ%20Logos/indiehq_1200x630_vmheum.png">
406<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","name":"IndieHQ","legalName":"Indie Agency News","url":"https://indiehq.com","logo":"https://media.indiehq.com/IndieHQ%20Logos/PNG/Color/IHQ__Color_WhiteBackground_Horizontal_xsbzda.png?height=240","description":"IndieHQ is the home for the independent agency community — coaching, awards, community, research, and live events — from Indie Agency News.","sameAs":["https://indieagency.news"]}</script>
vendor: 1 bytes, line 406
406
407<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","name":"IndieHQ","url":"https://indiehq.com"}</script>
407
408</head>
409<body>
410<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
411  /* Member-first landing: flag the page BEFORE paint so the prospect hero never flashes. */
412  (function(){
413    try {
414      var p = JSON.parse(localStorage.getItem("ihq_session") || "null");
415      if (p && (!p.exp || Date.now() < p.exp) && p.role !== "team") {
416        document.documentElement.className += " ihq-member";
417      }
418    } catch (e) {}
419  })();
420</script>
420
421
422<header>
423  <div class="wrap header-inner">
424    <a class='wordmark' href='/' style='display:flex;align-items:center;'><img src="https://media.indiehq.com/IndieHQ%20Logos/PNG/Color/IHQ__Color_WhiteBackground_Horizontal_xsbzda.png?height=240" alt="Indie HQ" style="height:44px;width:189px;object-fit:cover;display:block;"></a>
425    <nav class="main">
426      <a href="https://indieagency.news">News</a>
427      <a href="https://ihqevents.com/">Events</a>
428      <a href='/directory'>Directory</a>
429      <a href='/commons'>Community</a>
430      <a href='/top40'>Awards</a>
431      <a class="nav-enter" href="https://top40pa.juried.is" style="display:inline-flex;align-items:center;line-height:1;background:var(--accent);color:var(--ink);padding:6px 12px;border-radius:999px;font-weight:800;font-size:.82rem;white-space:nowrap;">Enter Top 40 &rarr;</a>
432      <a href="/partners">Partners</a>
433      <a href="/member-hq">Member HQ</a>
434      <a class='mob-only' href='/login'>Sign in</a>
435      <a class='mob-only' href='/join'>Become a member</a>
436    </nav>
437    <div class="header-cta">
438      <a class='login-link' href='/login'>Sign in</a>
439      <a class='btn btn-accent' href='/join'>Become a member</a>
440    </div>
441    <button class="nav-toggle" aria-label="Open menu" aria-expanded="false"><span></span><span></span><span></span></button>
442  </div>
443</header>
444
445<!-- ===== Jury recruitment promo ribbon ===== -->
446<style>
447  .jury-ribbon{ background:var(--accent); color:var(--ink); border-bottom:2px solid var(--ink); }
448  .jury-ribbon-inner{ max-width:1200px; margin:0 auto; padding:10px 28px; display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
449  .jury-ribbon-txt{ font-size:.95rem; }
450  .jury-ribbon-cta{ font-weight:800; text-decoration:underline; text-underline-offset:3px; white-space:nowrap; }
451  .jury-ribbon-x{ margin-left:auto; background:none; border:0; font-size:1.35rem; line-height:1; cursor:pointer; color:var(--ink); opacity:.65; }
452  .jury-ribbon-x:hover{ opacity:1; }
453</style>
454<div id="cfe-ribbon" class="jury-ribbon">
455  <div class="jury-ribbon-inner">
456    <img src="https://ihq-awards.b-cdn.net/Show%20Logos/IHQ__Top%2040%20Black.png" alt="Top 40" decoding="async" style="height:26px;width:auto;display:block;flex:0 0 auto;">
457    <span class="jury-ribbon-txt"><strong>Top 40: People + Agencies 2026 &mdash; Call for Entries is open.</strong> <span id="cfe-price">Main deadline $179 through Sat., Oct. 17</span> &middot; Members save 25%.</span>
458    <a class="jury-ribbon-cta" href="https://top40pa.juried.is">Enter now &rarr;</a>
459    <button type="button" class="jury-ribbon-x" aria-label="Dismiss" onclick="var b=document.getElementById('cfe-ribbon');if(b)b.style.display='none';try{localStorage.setItem('ihq_top40cfe_ribbon_v2','1');}catch(e){}">&times;</button>
460  </div>
461</div>
462<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
463/* Top 40 P+A ribbon — deadline copy advances by itself (matches top40.html pricing).
464   Main $179 through Sat Oct 17 -> Final $199 through Sat Oct 31 -> ribbon hides after entries close. */
465(function(){
466  var r=document.getElementById('cfe-ribbon'); if(!r) return;
467  try{ if(localStorage.getItem('ihq_top40cfe_ribbon_v2')==='1'){ r.style.display='none'; return; } }catch(e){}
468  var now=new Date(), pt=document.getElementById('cfe-price');
469  if(now>=new Date('2026-11-01T00:00:00-07:00')){ r.style.display='none'; return; }
470  if(now>=new Date('2026-10-18T00:00:00-07:00') && pt){ pt.innerHTML='Final deadline $199 through Sat., Oct. 31'; }
471})();
472</script>
472
473<style>
474  #nepal-ribbon{ background:#DC143C; color:#fff; border-bottom:2px solid #0D0D12; }
475  #nepal-ribbon .jury-ribbon-cta{ color:#fff; }
476  #nepal-ribbon .jury-ribbon-x{ color:#fff; }
477</style>
478<div id="nepal-ribbon" class="jury-ribbon">
479  <div class="jury-ribbon-inner">
480    <img src="https://ian-media.b-cdn.net/IndieHQ%20Site%20Images/nepal%20fav.png" alt="Nepal" decoding="async" style="height:22px;width:auto;display:block;flex:0 0 auto;">
481    <span class="jury-ribbon-txt"><strong>Stand with Nepal.</strong> Our first forward is out &mdash; $1,030, 100% of what members gave, sent to Nepal's official relief fund.</span>
482    <a class='jury-ribbon-cta' href='/nepal-relief'>Add to it &rarr;</a>
483    <button type="button" class="jury-ribbon-x" aria-label="Dismiss" onclick="var b=document.getElementById('nepal-ribbon');if(b)b.style.display='none';try{localStorage.setItem('ihq_nepal_ribbon','1');}catch(e){}">&times;</button>
484  </div>
485</div>
486<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">try{if(localStorage.getItem('ihq_nepal_ribbon')==='1'){var _nr=document.getElementById('nepal-ribbon');if(_nr)_nr.style.display='none';}}catch(e){}</script>
486
487
488<!-- ===== Is It IP? launch ribbon (powered by Toerek) ===== -->
489<style>
490  #isitip-ribbon{ background:var(--ink); color:#fff; border-bottom:2px solid #0D0D12; }
491  #isitip-ribbon .jury-ribbon-cta{ color:var(--accent); }
492  #isitip-ribbon .jury-ribbon-x{ color:#fff; }
493</style>
494<div id="isitip-ribbon" class="jury-ribbon">
495  <div class="jury-ribbon-inner">
496    <span class="jury-ribbon-txt"><strong>Is It IP?</strong> A free 2-minute gut-check on what your agency owns &mdash; powered by Toerek Law | Legal + Creative.</span>
497    <a class="jury-ribbon-cta" href="/is-it-ip">Take the quiz &rarr;</a>
498    <button type="button" class="jury-ribbon-x" aria-label="Dismiss" onclick="var b=document.getElementById('isitip-ribbon');if(b)b.style.display='none';try{localStorage.setItem('ihq_isitip_ribbon','1');}catch(e){}">&times;</button>
499  </div>
500</div>
501<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">try{if(localStorage.getItem('ihq_isitip_ribbon')==='1'){var _ir=document.getElementById('isitip-ribbon');if(_ir)_ir.style.display='none';}}catch(e){}</script>
501
502
503<!-- ===== Member welcome band (signed-in members only; hoists the launchpad up top) ===== -->
504<div class="member-hero">
505  <div class="wrap">
506    <div class="mh-kicker">Welcome back</div>
507    <h1 id="mh-greeting">You&rsquo;re in. <span class="accent">Here&rsquo;s your HQ.</span></h1>
508    <p class="mh-sub">Everything you get as a member &mdash; QuickCoach, your community, all your tools &mdash; lives in one place now.</p>
509    <div class="mh-chips">
510      <a class="primary" href="/member-hq">Go to your Member HQ &rarr;</a>
511      <a href='/how-to'>New here? Start with the guide &rarr;</a>
512    </div>
513    <div class="mh-news" id="mh-news" hidden>
514      <div class="mh-news-h">Fresh from the newsroom &mdash; the news never stops</div>
515      <div class="mh-news-list" id="mh-news-list"></div>
516    </div>
517    <div class="mh-optin" id="mh-optin" hidden style="margin-top:18px;padding:13px 16px;border:1px solid rgba(128,128,128,.32);border-radius:12px;display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;justify-content:space-between;">
518      <span class="mh-optin-txt" style="font-weight:600;">Want the IndieHQ newsletter? The best of the indie world, straight to your inbox.</span>
519      <span style="display:flex;gap:12px;align-items:center;flex-wrap:wrap;">
520        <button type="button" id="mh-optin-yes" class="primary" style="border:0;cursor:pointer;font:inherit;">Yes, sign me up</button>
521        <button type="button" id="mh-optin-no" style="background:none;border:0;color:inherit;opacity:.7;text-decoration:underline;text-underline-offset:3px;cursor:pointer;font:inherit;">No thanks</button>
522      </span>
523    </div>
524  </div>
525</div>
526
527<!-- ===== Hero — the statement ===== -->
528<div class="hero">
529  <div class="wrap">
530    <div class="flag"></div>
531    <div id="mkt-kicker" style="font-size:.72rem;font-weight:800;letter-spacing:.15em;text-transform:uppercase;color:#21CF7E;margin-bottom:12px;">The Global Home for Independent Agencies</div>
532    <h1 id="mkt-h1">Independence is beautiful. And it&rsquo;s <span class="accent">better together.</span></h1>
533    <div class="hero-rot" style="display:flex;align-items:center;gap:14px;min-height:2rem;margin:16px 0 4px;flex-wrap:wrap;">
534      <span id="mkt-rot" style="font-size:1.5rem;font-weight:800;color:#21CF7E;letter-spacing:-.02em;transition:opacity .3s;">Sharpen your website.</span>
535      <span id="mkt-rot-dots" style="display:flex;gap:6px;"></span>
536    </div>
537    <p id="mkt-sub">One roof for the work of running an indie: read the news, sharpen the craft, get seen, and grow across a global community of independent agencies.</p>
538    <div class="hero-cta" style="flex-direction:column;align-items:flex-start;gap:12px;">
539      <a class='btn btn-accent' href='/join'>Join the community</a>
540      <a class="btn" href="/member-hq">Already a member? Head here &rarr;</a>
541      <a href='/check' style='color:#21CF7E;font-weight:700;font-size:.95rem;text-decoration:underline;text-underline-offset:3px;'>Not sure? Check whether your agency is already a member &rarr;</a>
542    </div>
543  </div>
544</div>
545<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
546(function(){
547  var ROT=["Sharpen your website.","Polish an op-ed.","Strengthen an awards entry.","Tighten your pitch to the trades.","Share your work on Indie Agency News.","Get the research and intelligence to run smarter.","Lean on a global indie community.","Post a role, or find your next one."];
548  var el=document.getElementById("mkt-rot"),dots=document.getElementById("mkt-rot-dots"),hero=document.querySelector(".hero");
549  if(!el||!dots)return;
550  ROT.forEach(function(_,i){var d=document.createElement("span");d.style.cssText="width:7px;height:7px;border-radius:50%;display:block;transition:background .2s;background:"+(i===0?"#21CF7E":"#3a3a42");dots.appendChild(d);});
551  var di=dots.children,idx=0,paused=false,reduce=window.matchMedia&&matchMedia("(prefers-reduced-motion: reduce)").matches;
552  if(hero){hero.addEventListener("mouseenter",function(){paused=true;});hero.addEventListener("mouseleave",function(){paused=false;});}
553  if(!reduce){setInterval(function(){if(paused)return;idx=(idx+1)%ROT.length;el.style.opacity="0";setTimeout(function(){el.textContent=ROT[idx];el.style.opacity="1";for(var k=0;k<di.length;k++){di[k].style.background=(k===idx?"#21CF7E":"#3a3a42");}},300);},2600);}
554})();
555</script>
555
556
557
558
559<!-- ===== 360+ member agencies - auto-scrolling marquee (live from members-feed) ===== -->
560<style>
561  #agency-scroll{padding:52px 0 48px;text-align:center;}
562  #agency-scroll .amn{font-size:3rem;font-weight:900;color:#0C9B53;letter-spacing:-.03em;line-height:1;}
563  #agency-scroll h2{font-size:1.5rem;letter-spacing:-.02em;margin:6px 0 4px;}
564  #agency-scroll .amsub{color:#56565E;max-width:56ch;margin:0 auto;}
565  #agency-scroll .amlink{color:#0C9B53;font-weight:800;margin-top:8px;display:inline-block;text-decoration:none;}
566  .amarq{margin-top:16px;overflow:hidden;position:relative;-webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);}
567  .amarq .atrack{display:flex;gap:12px;width:max-content;}
568  .amarq .atrack.a{animation:amscroll 70s linear infinite;}
569  .amarq .atrack.b{animation:amscrollb 86s linear infinite;}
570  .amarq:hover .atrack{animation-play-state:paused;}
571  a.achip{white-space:nowrap;border:2px solid #0D0D12;border-radius:999px;padding:9px 18px;font-weight:700;font-size:1rem;background:#fff;color:#0D0D12;text-decoration:none;}
572  a.achip:hover{background:#0D0D12;color:#FAFAF8;}
573  @keyframes amscroll{from{transform:translateX(0);}to{transform:translateX(-50%);}}
574  @keyframes amscrollb{from{transform:translateX(-50%);}to{transform:translateX(0);}}
575  @media(prefers-reduced-motion:reduce){ .amarq .atrack{animation:none;} }
576</style>
577<section id="agency-scroll">
578  <div class="wrap">
579    <div class="amn">360+</div>
580    <h2>independent agencies call it home.</h2>
581    <p class="amsub">
581From two-person shops to household names &mdash; the largest community of indies anywhere.</p>
582    <input id="amsearch" type="search" placeholder="Find agencies you know" autocomplete="off" style="width:100%;max-width:460px;margin:16px auto 0;display:block;padding:12px 15px;border:2px solid #0D0D12;border-radius:10px;font-size:1rem;font-family:inherit;">
583    <div id="amresultcount" style="font-size:.85rem;color:#56565E;margin-top:8px;min-height:1.1rem;"></div>
584    <a class='amlink' href='/directory'>Meet them all in the Directory &rarr;</a>
585  </div>
586  <div id="amhits" class="wrap" style="display:none;flex-wrap:wrap;gap:9px;justify-content:center;margin-top:8px;"></div>
587  <div id="ammarqwrap">
588    <div class="amarq"><div class="atrack a" id="atrackA"></div></div>
589    <div class="amarq"><div class="atrack b" id="atrackB"></div></div>
590  </div>
591</section>
592<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
593(function(){
594  var A=document.getElementById("atrackA"),B=document.getElementById("atrackB");
595  if(!A||!B)return;
596  function esc(s){return String(s).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");}
597  var FALLBACK=["Cactus","Sukle","Karsh Hagan","Zeus Jones","Duncan Channon","Oberland","Orci","Big Communications","Fortnight Collective","Territorial","FUSE Create","Goodway Group","Moontide","Saylor","Delve","Response Media","fivebyfive","Chameleon Collective","Odd Notion","MNSTR","Glow","Harmonium Group","Flight PR","Where Eagles Dare"];
598  function render(names){
599    for(var i=names.length-1;i>0;i--){var j=Math.floor(Math.random()*(i+1));var t=names[i];names[i]=names[j];names[j]=t;}
600    var half=Math.ceil(names.length/2);
601    function fill(el,arr){el.innerHTML=arr.map(function(n){return '<a class="achip" href="directory.html">'+esc(n)+'</a>';}).join("")+arr.map(function(n){return '<a class="achip" href="directory.html">'+esc(n)+'</a>';}).join("");}
602    fill(A,names.slice(0,half));fill(B,names.slice(half));
603    [A,B].forEach(function(el){ var w=el.scrollWidth/2; if(w>0){ el.style.animationDuration=Math.max(40,Math.round(w/50))+"s"; } });
604  }
605  fetch("/.netlify/functions/members-feed").then(function(r){return r.json();}).then(function(d){
606    var names=((d&&d.members)||[]).map(function(m){return m&&m.name;}).filter(Boolean);
607    render(names.length>=12?names:FALLBACK.slice());
608  }).catch(function(){render(FALLBACK.slice());});
609  var q=document.getElementById("amsearch"),hits=document.getElementById("amhits"),marq=document.getElementById("ammarqwrap"),rc=document.getElementById("amresultcount");
610  if(q){q.addEventListener("input",function(){
611    var v=q.value.trim().toLowerCase();
612    if(!v){hits.style.display="none";if(marq)marq.style.display="block";rc.textContent="";return;}
613    if(marq)marq.style.display="none";hits.style.display="flex";
614    var names=[]; try{ names=Array.prototype.slice.call(document.querySelectorAll("#atrackA .achip,#atrackB .achip")).map(function(a){return a.textContent;}); }catch(e){}
615    var uniq={},list=[]; names.forEach(function(n){var k=n.toLowerCase(); if(!uniq[k]){uniq[k]=1;list.push(n);}});
616    var m=list.filter(function(n){return n.toLowerCase().indexOf(v)>-1;});
617    hits.innerHTML=m.slice(0,60).map(function(n){return '<a class="achip" href="directory.html">'+String(n).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")+'</a>';}).join("");
618    rc.textContent=m.length?(m.length+" agencies match \u201c"+q.value+"\u201d"):("No match yet for \u201c"+q.value+"\u201d \u2014 the full list is in the Directory.");
619  });}
620})();
621</script>
621
622
623
624
625<!-- ===== Live Tracker — the prominent band ===== -->
626<section id="tracker" class="dark">
627  <div class="wrap">
628    <span class="live-pill"><span class="live-dot"></span> Live</span>
629    <h2 id="trk-h2">The indie world, as it happens.</h2>
630    <p class="tracker-sub" id="trk-sub">The Live Tracker is the real-time pulse of what independent agencies are doing, winning, and talking about — right now.</p>
631    <div class="tracker-panel">
632      <iframe
633        id="trk-frame"
634        data-liveblog="O5W3tA2AZCE1Oh9cqOKG"
635        width="100%"
636        height="800"
637        title="Indie News Tracker Q3 2026 — Part 2"
638        src="https://embed.timepath.co/liveblog/O5W3tA2AZCE1Oh9cqOKG"
639        frameborder="0"
640        scrolling="yes"
641        allow="encrypted-media; clipboard-read; clipboard-write; fullscreen"
642        referrerpolicy="no-referrer-when-downgrade"
643        loading="lazy"
644        style="display:block;border:0;background:#fff;width:100%;"
645      ></iframe>
646    </div>
647    <p class="tracker-credit">Powered by <a href="https://timepath.co" target="_blank" rel="noopener">Timepath</a></p>
648    
648<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" type="text/javascript">(function () {
649      var FRAME_ORIGIN = "https://embed.timepath.co";
650      var el = document.getElementById("trk-frame");
651      if (!el) return;
652      var currentId = el.getAttribute("data-liveblog") || "O5W3tA2AZCE1Oh9cqOKG"; // mutable — the Site Content slot can swap it
653      var raf = null;
654      function setHeight(px) { if (raf) return; raf = requestAnimationFrame(function () { el.style.height = String(px) + "px"; raf = null; }); }
655      function onMessage(e) {
656        if (!e || e.origin !== FRAME_ORIGIN) return;
657        var d = e.data && typeof e.data === "object" ? e.data : null;
658        if (!d || d.liveblogId !== currentId) return;
659        if (typeof d.frameHeight === "number" && d.frameHeight > 0 && d.frameHeight < 100000) { setHeight(d.frameHeight); }
660      }
661      function handshake() {
662        try { el.contentWindow && el.contentWindow.postMessage({ parentUrl: window.location.href, liveblogId: currentId, v: "2.0" }, FRAME_ORIGIN); } catch (err) {}
663      }
664      window.addEventListener("message", onMessage);
665      el.addEventListener("load", handshake); // fires on first load AND whenever the src is swapped
666      // Let the content loader point the Tracker at a new liveblog with no redeploy.
667      window.__setTracker = function (id) {
668        id = String(id || "").trim();
669        if (!id || id === currentId) return;
670        currentId = id;
671        el.src = FRAME_ORIGIN + "/liveblog/" + id;
672      };
673    })();</script>
673
674  </div>
675</section>
676
677<!-- ===== Editable homepage content (Site Content slots) — team edits in the hub, no redeploy.
678     Every slot has a baked-in default above, so if this fetch is slow or fails the page is unchanged. ===== -->
679<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" type="text/javascript">(function () {
680  var D = {
681    hero_headline: "Independence is beautiful. And it's",
682    hero_headline_accent: "better together.",
683    hero_subhead: "One roof for the work of running an indie: read the news, sharpen the craft, get seen, and grow across a global community of independent agencies.",
684    tracker_heading: "The indie world, as it happens.",
685    tracker_sub: "The Live Tracker is the real-time pulse of what independent agencies are doing, winning, and talking about — right now.",
686    tracker_liveblog_id: "O5W3tA2AZCE1Oh9cqOKG"
687  };
688  function esc(s) { return String(s == null ? "" : s).replace(/[&<>"]/g, function (c) { return { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" }[c]; }); }
689  function setText(id, v) { var el = document.getElementById(id); if (el && v != null) el.textContent = v; }
690  fetch("/.netlify/functions/home-content").then(function (r) { return r.json(); }).then(function (res) {
691    var c = (res && res.content) || {};
692    function val(k) { return (c[k] != null && String(c[k]).trim() !== "") ? String(c[k]) : D[k]; }
693    var h1 = document.getElementById("mkt-h1");
694    if (h1) h1.innerHTML = esc(val("hero_headline")) + ' <span class="accent">' + esc(val("hero_headline_accent")) + '</span>';
695    setText("mkt-sub", val("hero_subhead"));
696    setText("trk-h2", val("tracker_heading"));
697    setText("trk-sub", val("tracker_sub"));
698    if (window.__setTracker) window.__setTracker(val("tracker_liveblog_id"));
699  }).catch(function () { /* keep baked-in defaults */ });
700})();</script>
700
701
702<!-- ===== Events ===== -->
703<section id="events">
704  <div class="wrap">
705    <div class="section-head">
706      <span class="kicker">Live programming</span>
707      <h2>Show up. It's the whole point.</h2>
708      <p>Summits, sessions, and shows — where the indie community actually gets together.</p>
709    </div>
710
711    <!-- Page-width highlighted feature: the flagship Summit -->
712    <a class="summit-feature" href="https://indie27.com/">
713      <div class="summit-left">
714        <div class="summit-kick">★ The main event · 2027</div>
715        <h3>Indies Rising Global Summit</h3>
716        <p class="summit-where"><strong>Portland, OR</strong> · Tuesday, April 13, 2027 · Portland Center Stage at The Armory</p>
717        <p class="summit-tier">Current rate: <b>Turbo Early Bird — $599</b> (through Dec 31). <b>$99</b> saves your spot at today's tier.</p>
718        <div class="summit-seats">
719          <div class="summit-bar"><i style="width:12.5%"></i></div>
720          <div class="lab"><b>50</b> of 400 seats reserved · <b>350 left</b></div>
721        </div>
722      </div>
723      <div class="summit-right">
724        <div class="countdown" id="summitCountdown" data-date="2027-04-13T09:00:00-07:00">
725          <div class="cd-box"><div class="n" data-cd="d">—</div><div class="l">Days</div></div>
726          <div class="cd-box"><div class="n" data-cd="h">—</div><div class="l">Hrs</div></div>
727          <div class="cd-box"><div class="n" data-cd="m">—</div><div class="l">Min</div></div>
728          <div class="cd-box"><div class="n" data-cd="s">—</div><div class="l">Sec</div></div>
729        </div>
730        <span class="summit-cta">Reserve your seat — $99 →</span>
731        <span class="summit-sub">Locks in today's tier price</span>
732      </div>
733    </a>
734
735    <div class="evrail" id="eventsGrid">
736      <!-- Live from ihqevents.com via /.netlify/functions/events-feed — a horizontal rail of every
737           upcoming event. The cards below are a fallback shown only if the feed is unreachable. -->
738      <a class="cell" href="https://ihqevents.com/e/trivia-sf">
739        <div class="cell-img" style="background-image:url('https://media.indiehq.com/Events:%20Trivia/trivia__sf_bhmfwb.png')"></div>
740        <span class="event-date">Thu · Jul 16</span>
741        <h3>IAN Trivia Battle</h3>
742        <p>Four departments. One winner.</p>
743        <span class="go">Register →</span>
744      </a>
745      <a class="cell" href="https://ihqevents.com/e/showoff-boulder">
746        <div class="cell-img" style="background-image:url('https://media.indiehq.com/Events:%20Show%20Off/Boulder_Show_Off_byl4cp.png')"></div>
747        <span class="event-date">Wed · Aug 5</span>
748        <h3>IAN Show Off — Boulder</h3>
749        <p>Show off your work.</p>
750        <span class="go">Register →</span>
751      </a>
752      <a class="cell" href="https://ihqevents.com/e/showoff-dc">
753        <div class="cell-img" style="background-image:url('https://media.indiehq.com/Events:%20Show%20Off/DC_Show_Off_qhfpmb.png')"></div>
754        <span class="event-date">Tue · Oct 13</span>
755        <h3>IAN Show Off — Washington DC</h3>
756        <p>Show off your work.</p>
757        <span class="go">Register →</span>
758      </a>
759    </div>
760    <div class="evfoot">
761      <a class="see-all" href="https://ihqevents.com/">See all events</a>
762      <div class="evnav" id="evNav">
763        <button type="button" class="evbtn" id="evPrev" aria-label="Scroll to previous events" disabled>&#8249;</button>
764        <button type="button" class="evbtn" id="evNext" aria-label="Scroll to more events">&#8250;</button>
765      </div>
766    </div>
767  </div>
768</section>
769
770<!-- ===== Sister Cities (public · member benefit) — the one home-page entry point.
771     Reuses the .band pattern (same as Scoreboard / Partners). Destination: /sister-cities ===== -->
772<section id="sister-cities">
773  <div class="wrap">
774    <div class="band">
775      <div>
776        <span class="kicker"><span class="nw">A member benefit</span> &middot; <span class="nw">Since 2024</span></span>
777        <h2>Two markets. A few months. No agenda, just good company.</h2>
778        <p>One of our most-loved traditions is back for a new round. Fresh pairings, new friends, and a standing excuse to get to know the indies in another market. The friendships tend to outlast the&nbsp;round.</p>
779        <!-- Sister Cities stats. Hardcoded, current as of 2026-09-28.
780             Source: Airtable base appE6rDw2wQZxOUXA, table tblUdIGCzLO13EINq.
781             Refresh at each round changeover. Owner: Sister Cities project. -->
782        <p class="sc-runs"><span><b>Fall 2026</b></span> &middot; <span><b>24</b> markets</span> &middot; <span><b>12</b> pairings</span> &middot; <span><b>357</b> agencies</span> &middot; <span>Through <b>December 31, 2026</b></span></p>
783      </div>
784      <div class="band-cta"><a class='btn btn-accent' href='/sister-cities'>Find your market &rarr;</a></div>
785    </div>
786  </div>
787</section>
788
789<!-- ===== IAN Shows — upcoming, from the Shows table (shows-feed). Hidden until there are Booked shows. ===== -->
790<section id="ian-shows" hidden>
791  <div class="wrap">
792    <div class="section-head">
793      <span class="kicker">On IAN TV</span>
794      <h2>Coming up on our stages</h2>
795    </div>
796    <div class="grid grid-3" id="shows-grid"></div>
797    <a class='see-all' hidden href='/indie-stages' id='shows-host-cta'>Want to host one? Get on our stages &rarr;</a>
798  </div>
799</section>
800<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
801(function(){
802  function esc(s){return (s==null?"":String(s)).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;","\"":"&quot;"}[c];});}
803  function fdate(s){ if(!s) return ""; var d=new Date(s+"T00:00"); return isNaN(d)?"":d.toLocaleDateString(undefined,{month:"short",day:"numeric"}); }
804  fetch("/.netlify/functions/shows-feed").then(function(r){return r.json();}).then(function(d){
805    var shows=(d&&d.shows)||[];
806    var up=shows.filter(function(s){return s.status==="Booked";});
807    if(!up.length) return;               // section stays hidden until a show is booked
808    up.sort(function(a,b){ return (a.airDate||"").localeCompare(b.airDate||""); });
809    document.getElementById("shows-grid").innerHTML = up.slice(0,3).map(function(s){
810      var meta=[s.format, fdate(s.airDate)].filter(Boolean).map(esc).join(" · ");
811      return '<div class="cell"><span class="event-date">'+esc(s.type||"Show")+(meta?' · '+meta:'')+'</span>'+
812        '<h3>'+esc(s.title)+'</h3>'+(s.description?'<p>'+esc(String(s.description).slice(0,140))+'</p>':'')+'</div>';
813    }).join("");
814    if(up.some(function(s){return s.needsHost;})) document.getElementById("shows-host-cta").hidden=false;
815    document.getElementById("ian-shows").hidden=false;
816  }).catch(function(){});
817})();
818</script>
818
819
820<!-- ===== News (editorial list) ===== -->
821<section id="news">
822  <div class="wrap">
823    <div class="section-head">
824      <span class="kicker">Indie Agency News</span>
825      <h2>The latest from the newsroom</h2>
826    </div>
827    <div class="news-list">
828      <!-- Static fallback — the live feed (news-feed.js) replaces this with real headlines on load,
829           and serves last-known headlines from cache when indieagency.news is down. This graceful
830           row only shows in a true cold outage (feed unreachable AND nothing cached yet). -->
831      <div class="news-item" style="cursor:default">
832        <span class="tag">Newsroom</span>
833        <h3>Fresh headlines are on their way — the newsroom is catching up. Check back in a moment.</h3>
834      </div>
835    </div>
836    <a class="see-all" href="https://indieagency.news" target="_blank" rel="noopener">Read all the news</a>
837  </div>
838</section>
839
840<!-- ===== Meet an Indie Agency (signature collection) ===== -->
841<section id="meet">
842  <div class="wrap">
843    <div class="section-head">
844      <span class="kicker">Signature series</span>
845      <h2>Meet an Indie Agency</h2>
846      <p>The shops behind the work — who they are, how they think, and what makes them worth knowing.</p>
847    </div>
848    <div class="news-list">
849      <!-- Static fallback — meet-an-indie-feed.js replaces this with real profiles on load, and
850           serves last-known profiles from cache when indieagency.news is down. This graceful row
851           only shows in a true cold outage (feed unreachable AND nothing cached yet). -->
852      <div class="news-item" style="cursor:default">
853        <span class="tag">Meet an Indie Agency</span>
854        <h3>More agency profiles are loading — check back in a moment.</h3>
855      </div>
856    </div>
857    <a class="see-all" href="https://indieagency.news/meet-an-indie-agency/" target="_blank" rel="noopener">Meet more agencies</a>
858  </div>
859</section>
860
861<!-- ===== What you get (the 5 C's) — value pitch, right under the hero ===== -->
862<section id="members" class="dark">
863  <div class="wrap">
864    <div class="section-head">
865      <span class="kicker">The featured member benefit</span>
866      <h2>QuickCoach &mdash; expert feedback on your work.</h2>
867      <p>The most powerful thing in your membership. Send us your website or an awards entry &mdash; or a pitch, an op-ed, a panel &mdash; and get back a real, scored expert review, with specific fixes, before it ever ships.</p>
868    </div>
869
870    <div class="qc-split" style="display:grid;grid-template-columns:1fr 1fr;gap:38px;align-items:center;margin:24px 0 6px;">
871      <div>
872        <div style="font-size:.72rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:#21CF7E;">What you can run through it</div>
873        <ul style="list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:9px;font-size:1.02rem;">
874          <li>&rarr;&nbsp; Your website or messaging</li>
875          <li>&rarr;&nbsp; An awards entry</li>
876          <li>&rarr;&nbsp; A new-business pitch</li>
877          <li>&rarr;&nbsp; An op-ed or byline</li>
878          <li>&rarr;&nbsp; A conference panel or talk</li>
879        </ul>
880        <div style="margin-top:22px;display:flex;gap:14px 16px;flex-wrap:wrap;align-items:center;">
881          <a class='btn btn-accent' href='/quickcoach-tour'>See how QuickCoach works &rarr;</a>
882          <a class='see-all' href='/join'>Become a member</a>
883        </div>
884      </div>
885      <div style="background:#FAFAF8;color:#0D0D12;border-radius:16px;padding:24px 22px;box-shadow:10px 12px 0 rgba(33,207,126,.9);">
886        <div style="font-size:.72rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:#0C9B53;">How it works</div>
887        <div style="display:flex;gap:14px;align-items:flex-start;margin-top:16px;">
888          <div style="flex:0 0 30px;height:30px;border-radius:999px;background:#EAF9F1;border:2px solid #21CF7E;color:#0C9B53;font-weight:900;display:flex;align-items:center;justify-content:center;">1</div>
889          <div><div style="font-weight:800;">Send us your work</div><div style="color:#56565E;font-size:.92rem;">A website, a pitch, an op-ed, an award entry &mdash; whatever you want sharper.</div></div>
890        </div>
891        <div style="display:flex;gap:14px;align-items:flex-start;margin-top:14px;">
892          <div style="flex:0 0 30px;height:30px;border-radius:999px;background:#EAF9F1;border:2px solid #21CF7E;color:#0C9B53;font-weight:900;display:flex;align-items:center;justify-content:center;">2</div>
893          <div><div style="font-weight:800;">Scored, then checked by a human</div><div style="color:#56565E;font-size:.92rem;">Our model scores it against a real rubric &mdash; an expert makes sure it&rsquo;s right.</div></div>
894        </div>
895        <div style="display:flex;gap:14px;align-items:flex-start;margin-top:14px;">
896          <div style="flex:0 0 30px;height:30px;border-radius:999px;background:#EAF9F1;border:2px solid #21CF7E;color:#0C9B53;font-weight:900;display:flex;align-items:center;justify-content:center;">3</div>
897          <div><div style="font-weight:800;">You get specific fixes back</div><div style="color:#56565E;font-size:.92rem;">A clear page you can act on &mdash; specific, scored, ready to use.</div></div>
898        </div>
899      </div>
900    </div>
901
902    <!-- Member quote spotlight (one at a time, from the Airtable Testimonials table) -->
903    <div data-ihq-quotes data-use="Homepage" data-kind="spotlight" hidden style="margin-top:40px;"></div>
904
905    <!-- Front Desk strip — the "ask us anything" door, surfaced above the membership grid -->
906    <a class='fd-strip' href='/frontdesk' style='margin-top:40px;
906display:flex;align-items:center;gap:18px;flex-wrap:wrap;text-decoration:none;color:#FAFAF8;border:2px solid #21CF7E;border-radius:14px;padding:18px 22px;background:rgba(33,207,126,.08);'>
907      <span style="flex:0 0 auto;width:42px;height:42px;border-radius:999px;background:#21CF7E;color:#0D0D12;display:flex;align-items:center;justify-content:center;font-weight:900;font-size:1.25rem;" aria-hidden="true">?</span>
908      <span style="flex:1 1 280px;">
909        <span style="display:block;font-weight:800;font-size:1.12rem;">Not sure where to start? Ask the Front Desk.</span>
910        <span style="display:block;color:rgba(250,250,248,.72);font-size:.95rem;margin-top:2px;">Anything at all. A real person on our team gets back to you.</span>
911      </span>
912      <span style="flex:0 0 auto;background:#21CF7E;color:#0D0D12;font-weight:800;padding:10px 18px;border-radius:8px;white-space:nowrap;">Ask the Front Desk &rarr;</span>
913    </a>
914
915    <div style="margin-top:32px;border-top:2px solid rgba(250,250,248,.2);padding-top:24px;">
916      <span class="kicker">And everything else in your membership</span>
917      <div class="grid grid-3" style="margin-top:16px;">
918        <a class="cell" href="https://indieagency.news" target="_blank" rel="noopener" style="text-decoration:none;color:inherit;">
919          <span class="badge">Coverage</span>
920          <h3>Get your story told</h3>
921          <p>Daily coverage at Indie Agency News &mdash; a real spotlight for your news, work and wins.</p>
922          <span class="go">Read the coverage &rarr;</span>
923        </a>
924        <a class='cell' href='/commons' style='text-decoration:none;color:inherit;'>
925          <span class="badge">Community</span>
926          <h3>Find your people</h3>
927          <p>A mentor who&rsquo;s been where you are, and peers who get it. Real, verified people.</p>
928          <span class="go">Into the Commons &rarr;</span>
929        </a>
930        <a class='cell' href='/top40' style='text-decoration:none;color:inherit;'>
931          <span class="badge">Celebration</span>
932          <h3>Recognition you deserve</h3>
933          <p>Awards and stages to show your agency&rsquo;s unique brilliance.</p>
934          <span class="go">See the awards &rarr;</span>
935        </a>
936        <a class='cell' href='/preferred-partners' style='text-decoration:none;color:inherit;'>
937          <span class="badge">Connection</span>
938          <h3>The right intro, when you need it</h3>
939          <p>Vetted partner vendors, peer networks and mentors, and help when you need it.</p>
940          <span class="go">Meet the partners &rarr;</span>
941        </a>
942        <a class='cell' href='/indie-blueprint-home' style='text-decoration:none;color:inherit;'>
943          <span class="badge">Blueprint</span>
944          <h3>Research, intel and tools</h3>
945          <p>Indie Blueprints help you address the most critical and current issues agencies face.</p>
946          <span class="go">Open the Blueprints &rarr;</span>
947        </a>
948        <a class='cell' href='/perks' style='text-decoration:none;color:inherit;'>
949          <span class="badge">Value</span>
950          <h3>Member perks</h3>
951          <p>Real deals on the tools indie shops actually use, negotiated for the community.</p>
952          <span class="go">See the perks &rarr;</span>
953        </a>
954      </div>
955    </div>
956
957    <div style="margin-top:26px;display:flex;gap:14px 20px;flex-wrap:wrap;align-items:center;">
958      <a class='btn btn-accent' href='/join'>Become a member</a>
959      <a class='see-all' href='/how-to'>See how it all works &rarr;</a>
960    </div>
961  </div>
962</section>
963
964<!-- ===== Cannes Indie Scoreboard (call-out · external) ===== -->
965<section id="scoreboard">
966  <div class="wrap">
967    <div class="band scoreboard-feature">
968      <div>
969        <span class="kicker">Cannes Indie Scoreboard</span>
970        <h2>How did indies do at Cannes this year?</h2>
971        <p>Our annual scorecard tracks how independent agencies stacked up on the Croisette &mdash; the wins, the Lions, and the indies who punched above their weight.</p>
972      </div>
973      <div class="band-cta"><a class="btn btn-accent" href="https://indiescoreboard.com/" target="_blank" rel="noopener">See the scoreboard &rarr;</a></div>
974    </div>
975  </div>
976</section>
977
978<!-- ===== Preferred Partners (public · featured) ===== -->
979<section id="partners-band">
980  <div class="wrap">
981    <div class="band partners-feature">
982      <div>
983        <span class="kicker">Preferred Partners</span>
984        <h2>The partners we vouch for.</h2>
985        <p>Vetted help for the work you don't do in-house &mdash; sorted by what you actually need, with the proof and a warm intro a click away.</p>
986        <div class="pchips">
987          <span>Media</span><span>Data</span><span>Measurement</span><span>Performance</span><span>Finance</span><span>Legal</span><span>Social</span><span>Talent</span>
988        </div>
989      </div>
990      <div class="band-cta"><a class='btn btn-accent' href='/preferred-partners'>Meet the partners &rarr;</a></div>
991    </div>
992  </div>
993</section>
994
995<!-- ===== HOLDCO WATCH — live LED ticker ===== -->
996<link href="https://fonts.googleapis.com/css2?family=VT323&family=Share+Tech+Mono&display=swap" rel="stylesheet">
997<style>
998  .hcw-wrap{position:fixed;left:0;right:0;bottom:0;z-index:9999}
999  .hcw-src{background:#000;border-top:1px solid #1a1a1a;color:#5a5a5a;font-size:11px;
1000    letter-spacing:.06em;text-align:center;padding:3px 12px;white-space:nowrap;
1001    font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif}
1002  .hcw{position:relative;height:46px;
1003    background:linear-gradient(180deg,#111 0%,#000 55%,#0a0a0a 100%);
1004    border-top:1px solid #2a2a2a;box-shadow:0 -8px 24px rgba(0,0,0,.55);
1005    display:flex;align-items:stretch;overflow:hidden;
1006    font-family:"VT323","Share Tech Mono",monospace}
1007  .hcw-cap{flex:0 0 auto;display:flex;align-items:center;gap:9px;padding:0 16px;background:#000;
1008    border-right:1px solid #222;color:#ffb02e;font-size:22px;letter-spacing:.06em;
1009    text-shadow:0 0 6px rgba(255,176,46,.55);white-space:nowrap;position:relative;z-index:5}
1010  .hcw-dot{width:9px;height:9px;border-radius:50%;background:#ff3b30;
1011    box-shadow:0 0 8px #ff3b30;animation:hcw-blink 1.6s steps(1) infinite}
1012  @keyframes hcw-blink{50%{opacity:.25}}
1013  .hcw-live{font-size:15px;letter-spacing:.15em;color:#4a4a4a}
1014  .hcw-live.on{color:#37e06b;text-shadow:0 0 6px rgba(55,224,107,.6)}
1015  .hcw-track{position:relative;flex:1 1 auto;overflow:hidden}
1016  .hcw-move{display:flex;width:max-content;height:100%;align-items:center;
1017    animation:hcw-scroll 70s linear infinite;will-change:transform}
1018  .hcw-track:hover .hcw-move{animation-play-state:paused}
1019  @keyframes hcw-scroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}
1020  .hcw-cell{display:inline-flex;align-items:baseline;gap:8px;padding:0 26px;font-size:23px;
1021    line-height:1;white-space:nowrap}
1022  .hcw-sym{color:#ffb02e;text-shadow:0 0 5px rgba(255,176,46,.45)}
1023  .hcw-px{color:#f2f2f2;text-shadow:0 0 4px rgba(255,255,255,.25)}
1024  .hcw-chg,.hcw-yoy{font-size:20px}
1025  .hcw-up{color:#37e06b;text-shadow:0 0 6px rgba(55,224,107,.5)}
1026  .hcw-down{color:#ff3b30;text-shadow:0 0 6px rgba(255,59,48,.5)}
1027  .hcw-yoy .hcw-k{color:#7d7d7d;text-shadow:none}
1028  .hcw-sep{color:#8a6a2a;padding:0 2px;font-size:20px}
1029  .hcw::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:3;
1030    background-image:radial-gradient(circle,rgba(0,0,0,.62) .9px,transparent 1.4px);
1031    background-size:3px 3px;mix-blend-mode:multiply}
1032  .hcw::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:4;
1033    background:linear-gradient(180deg,rgba(255,255,255,.05),transparent 40%)}
1034  @media (prefers-reduced-motion:reduce){.hcw-move{animation-duration:200s}}
1035  @media (max-width:600px){.hcw-cap{font-size:18px;padding:0 10px}.hcw-cell{font-size:20px;padding:0 18px}}
1036</style>
1037<div class="hcw-wrap" aria-label="Live advertising holding company stock ticker">
1038  <div class="hcw-src">Data: Yahoo Finance</div>
1039  <div class="hcw">
1040    <div class="hcw-cap"><span class="hcw-dot"></span>HOLDCO&nbsp;WATCH<span class="hcw-live">LIVE</span></div>
1041    <div class="hcw-track"><div class="hcw-move" id="hcw-tape"></div></div>
1042  </div>
1043</div>
1044<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
1045(function(){
1046  var HOLDCOS = [
1047    { sym:"OMC",  y:"OMC",      px:83.45,  cur:"USD", day:-0.4,  yoy:14.8 },
1048    { sym:"PUB",  y:"PUB.PA",   px:85.64,  cur:"EUR", day: 0.6,  yoy: 4.5 },
1049    { sym:"WPP",  y:"WPP",      px:18.49,  cur:"USD", day:-0.3,  yoy:-48.2 },
1050    { sym:"4324", y:"4324.T",   px:3443,   cur:"JPY", day: 2.6,  yoy:-0.2 },
1051    { sym:"HAVAS",y:"HAVAS.AS", px:17.15,  cur:"EUR", day:-0.3,  yoy: 3.6 },
1052    { sym:"STGW", y:"STGW",     px:7.93,   cur:"USD", day: 0.8,  yoy:55.0 },
1053    { sym:"ACN",  y:"ACN",      px:135.23, cur:"USD", day:-1.1,  yoy:-49.1 },
1054    { sym:"IBM",  y:"IBM",      px:217.07, cur:"USD", day:-25.2, yoy:-21.6 }
1055  ];
1056  var CUR = { USD:"$", EUR:"€", JPY:"¥", GBP:"£", GBp:"£" };
1057  function fmtPrice(v,cur){ var s=CUR[cur]||""; return cur==="JPY"
1058    ? s+Math.round(v).toLocaleString("en-US") : s+Number(v).toFixed(2); }
1059  function skeleton(c){ return '<span class="hcw-cell" data-sym="'+c.sym+'">'
1060    +'<span class="hcw-sym">'+c.sym+'</span><span class="hcw-px"></span>'
1061    +'<span class="hcw-chg"></span><span class="hcw-yoy"></span>'
1062    +'<span class="hcw-sep">&bull;</span></span>'; }
1063  var tape = HOLDCOS.map(skeleton).join("");
1064  document.getElementById("hcw-tape").innerHTML = tape + tape;
1065  function paint(c){
1066    var nodes = document.querySelectorAll('.hcw-cell[data-sym="'+c.sym+'"]');
1067    for (var i=0;i<nodes.length;i++){
1068      var el=nodes[i];
1069      el.querySelector(".hcw-px").textContent = fmtPrice(c.px,c.cur);
1070      var chg=el.querySelector(".hcw-chg");
1071      chg.textContent=(c.day>=0?"▲":"▼")+Math.abs(c.day).toFixed(1)+"%";
1072      chg.className="hcw-chg "+(c.day>=0?"hcw-up":"hcw-down");
1073      var yoy=el.querySelector(".hcw-yoy");
1074      yoy.innerHTML='<span class="hcw-k">1Y</span> '+(c.yoy>=0?"+":"")+c.yoy.toFixed(1)+"%";
1075      yoy.className="hcw-yoy "+(c.yoy>=0?"hcw-up":"hcw-down");
1076    }
1077  }
1078  HOLDCOS.forEach(paint);
1079  function getQuote(y){
1080    var api="https://query1.finance.yahoo.com/v8/finance/chart/"+y+"?range=1y&interval=1d";
1081    var proxies=[
1082      function(u){return "https://api.allorigins.win/raw?url="+encodeURIComponent(u);},
1083      function(u){return "https://corsproxy.io/?url="+encodeURIComponent(u);}
1084    ];
1085    return (function tryNext(i){
1086      if(i>=proxies.length) return Promise.resolve(null);
1087      return fetch(proxies[i](api),{cache:"no-store"}).then(function(r){
1088        if(!r.ok) throw 0; return r.json();
1089      }).then(function(j){
1090        var res=j.chart.result[1], m=res.meta, price=m.regularMarketPrice;
1091        var prev=(m.chartPreviousClose!=null?m.chartPreviousClose:(m.previousClose!=null?m.previousClose:price));
1092        var closes=(res.indicators.quote[1].close||[]).filter(function(x){return x!=null;});
1093        var ago=closes.length?closes[1]:price;
1094        return { px:price, cur:m.currency||"USD",
1095                 day:((price-prev)/prev)*100, yoy:((price-ago)/ago)*100 };
1096      }).catch(function(){ return tryNext(i+1); });
1097    })(0);
1098  }
1099  function refresh(){
1100    var live=false;
1101    Promise.all(HOLDCOS.map(function(c){
1102      return getQuote(c.y).then(function(q){
1103        if(q){ c.px=q.px; c.cur=q.cur; c.day=q.day; c.yoy=q.yoy; paint(c); live=true; }
1104      });
1105    })).then(function(){ if(live) document.querySelector(".hcw-live").classList.add("on"); });
1106  }
1107  refresh();
1108  setInterval(refresh, 60000);
1109})();
1110</script>
1110
1111<!-- ===== end HOLDCO WATCH ===== -->
1112
1113<footer>
1114  <div class="wrap">
1115    <div class="footer-grid">
1116      <div class="footer-brand">
1117        <div class="wordmark">Indie <span class="hq">HQ</span></div>
1118        <p>By Indie Agency News. The global home independent agencies deserve.</p>
1119      </div>
1120      <div class="footer-links">
1121        <div>
1122          <h4>Go</h4>
1123          <ul>
1124            <li><a href='/directory'>Directory</a></li>
1125            <li><a href='/sister-cities'>Sister Cities</a></li>
1126            <li><a href="#tracker">Live Tracker</a></li>
1127            <li><a href="https://ihqevents.com/">Events</a></li>
1128            <li><a href="https://indieagency.news" target="_blank" rel="noopener">News</a></li>
1129            <li><a href='/preferred-partners'>Preferred Partners</a></li>
1130            <li><a href='/partners'>Sponsorship</a></li>
1131            <li><a href='/top40-winners'>Top 40 Awards</a></li>
1132          </ul>
1133        </div>
1134        <div>
1135          <h4>Belong</h4>
1136          <ul>
1137            <li><a href="#open">Community</a></li>
1138            <li><a href="/member-hq">Member HQ</a></li>
1139            <li><a href='/frontdesk'>Front Desk</a></li>
1140            <li><a href='/join'>Become a member</a></li>
1141            <li><a href='/login'>Sign in</a></li>
1142          </ul>
1143        </div>
1144        <div>
1145          <h4>Talk to us</h4>
1146          <ul>
1147            <li><a href='/frontdesk'>Front Desk (members)</a></li>
1148            <li><span class="ihq-mail" data-u="aloha" data-anon="sign in to reach us" data-anon-href="/login.html"></span></li>
1149          </ul>
1150        </div>
1151      </div>
1152    </div>
1153    <div class="footer-legal">© 2026 Creative Bohemian LLC. Indie Agency News and Indie HQ are brands of Creative Bohemian LLC. All rights reserved. · <a href='/privacy' style='color:var(--accent);font-weight:700;'>Privacy Policy</a> · <a href='/terms' style='color:var(--accent);font-weight:700;'>Terms of Service</a></div>
1154  </div>
1155</footer>
1156
1157<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
1158  // Pixel strip — the Indie@Cannes grid motif, gently flickering like a live signal
1159  (function () {
1160    var strip = document.getElementById('pixelStrip');
1161    if (!strip) return;
1162    var cols = 36, rows = 3, pixels = [];
1163    for (var c = 0; c < cols; c++) {
1164      var col = document.createElement('div');
1165      col.className = 'pixel-col';
1166      for (var r = 0; r < rows; r++) {
1167        var px = document.createElement('div');
1168        px.className = 'px' + (Math.random() > 0.35 ? ' on' : '');
1169        col.appendChild(px); pixels.push(px);
1170      }
1171      strip.appendChild(col);
1172    }
1173    setInterval(function () {
1174      for (var i = 0; i < 6; i++) {
1175        var p = pixels[Math.floor(Math.random() * pixels.length)];
1176        p.classList.toggle('on');
1177      }
1178    }, 700);
1179  })();
1180
1181  // Ticker — duplicate the track so the loop is seamless
1182  (function () {
1183    var track = document.getElementById('tickerTrack');
1184    if (track) track.innerHTML += track.innerHTML;
1185  })();
1186
1187  // Live events — pull the soonest few from ihqevents.com via the same-origin relay.
1188  // If the feed is unreachable, the baked-in fallback cards stay put.
1189  (function () {
1190    var grid = document.getElementById('eventsGrid');
1191    if (!grid) return;
1192    function esc(s){ return (s==null?'':String(s)).replace(/[&<>"]/g,function(c){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]; }); }
1193    function fmt(iso){
1194      var d = new Date((iso||'') + 'T00:00:00');
1195      if (isNaN(d)) return 'Date TBA';
1196      var wk = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][d.getDay()];
1197      var mo = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][d.getMonth()];
1198      return wk + ' · ' + mo + ' ' + d.getDate();
1199    }
1200    fetch('/.netlify/functions/events-feed').then(function(r){ return r.json(); }).then(function(d){
1201      var evs = (d && d.events) || [];
1202      if (!evs.length) return;   // keep the fallback cards
1203      var cards = evs.map(function(e){
1204        var mem = e.memberEvent;
1205        var href = mem ? esc(e.registerUrl || 'https://ihqevents.com/') : ('https://ihqevents.com/e/' + esc(e.slug));
1206        var ext = mem ? ' target="_blank" rel="noopener"' : '';
1207        var dateLine = (mem ? 'Member Event · ' : '') + fmt(e._d);
1208        return '<a class="cell" href="' + href + '"' + ext + '>' +
1209          (e.banner ? '<div class="cell-img" style="background-image:url(\'' + esc(e.banner) + '\')"></div>' : '') +
1210          '<span class="event-date">' + esc(dateLine) + '</span>' +
1211          '<h3>' + esc(String(e.name || '').replace(/^IAN\s+/i, '')) + '</h3>' +
1212          '<p>' + esc(e.tagline || (e.type && e.market ? e.type + ' · ' + e.market : (mem ? 'Free · register' : ''))) + '</p>' +
1213          (e.sponsor ? '<div class="evby">Presented by <b>' + esc(e.sponsor) + '</b></div>' : '') +
1214          '<span class="go">Register →</span></a>';
1215      });
1216      grid.innerHTML = cards.join('');
1217    }).catch(function(){ /* keep the fallback cards */ });
1218  })();
1219
1220  // Events rail — prev/next arrows scroll the row; the control hides when everything already fits.
1221  (function () {
1222    var rail = document.getElementById('eventsGrid');
1223    var prev = document.getElementById('evPrev'), next = document.getElementById('evNext'), nav = document.getElementById('evNav');
1224    if (!rail || !prev || !next || !nav) return;
1225    function step(){ return Math.max(300, Math.round(rail.clientWidth * 0.8)); }
1226    function update(){
1227      var overflow = rail.scrollWidth - rail.clientWidth > 4;
1228      nav.style.display = overflow ? 'flex' : 'none';
1229      var x = rail.scrollLeft;
1230      prev.disabled = x <= 2;
1231      next.disabled = x + rail.clientWidth >= rail.scrollWidth - 2;
1232    }
1233    prev.addEventListener('click', function(){ rail.scrollBy({ left: -step(), behavior: 'smooth' }); });
1234    next.addEventListener('click', function(){ rail.scrollBy({ left: step(), behavior: 'smooth' }); });
1235    rail.addEventListener('scroll', update, { passive: true });
1236    window.addEventListener('resize', update);
1237    new MutationObserver(update).observe(rail, { childList: true });
1237 // re-check when the feed injects cards
1238    update();
1239  })();
1240
1241  // Newsroom — latest posts from indieagency.news via the same-origin relay.
1242  // Category-agnostic (newest first). If unreachable, the placeholder rows stay.
1243  (function () {
1244    var list = document.querySelector('#news .news-list');
1245    if (!list) return;
1246    function esc(s){ return (s==null?'':String(s)).replace(/[&<>"]/g,function(c){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]; }); }
1247    fetch('/.netlify/functions/news-feed').then(function(r){ return r.json(); }).then(function(d){
1248      var items = (d && d.items) || [];
1249      if (!items.length) return;   // keep the placeholder rows
1250      list.innerHTML = items.map(function(i){
1251        return '<a class="news-item" href="' + esc(/^https?:\/\//i.test(i.url) ? i.url : '#') + '" target="_blank" rel="noopener">' +
1252          '<span class="tag">' + esc(i.category) + '</span>' +
1253          '<h3>' + esc(i.title) + '</h3>' +
1254          '<span class="arrow">&rarr;</span></a>';
1255      }).join('');
1256    }).catch(function(){ /* keep the placeholder rows */ });
1257  })();
1258
1259  // Meet an Indie Agency — latest profiles from indieagency.news (self-configuring category).
1260  (function () {
1261    var list = document.querySelector('#meet .news-list');
1262    if (!list) return;
1263    function esc(s){ return (s==null?'':String(s)).replace(/[&<>"]/g,function(c){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]; }); }
1264    fetch('/.netlify/functions/meet-an-indie-feed').then(function(r){ return r.json(); }).then(function(d){
1265      var items = (d && d.items) || [];
1266      if (!items.length) return;   // keep the placeholder rows
1267      list.innerHTML = items.slice(0,6).map(function(i){
1268        return '<a class="news-item" href="' + esc(/^https?:\/\//i.test(i.url) ? i.url : '#') + '" target="_blank" rel="noopener">' +
1269          '<span class="tag">' + esc(i.category) + '</span>' +
1270          '<h3>' + esc(i.title) + '</h3>' +
1271          '<span class="arrow">&rarr;</span></a>';
1272      }).join('');
1273    }).catch(function(){ /* keep the placeholder rows */ });
1274  })();
1275
1276  // Summit countdown → April 13, 2027 (Portland).
1277  (function () {
1278    var el = document.getElementById('summitCountdown'); if (!el) return;
1279    var target = new Date(el.getAttribute('data-date')).getTime();
1280    function pad(n){ return (n < 10 ? '0' : '') + n; }
1281    function set(k, v){ var n = el.querySelector('[data-cd="' + k + '"]'); if (n) n.textContent = v; }
1282    function tick() {
1283      var diff = target - Date.now(); if (diff < 0) diff = 0;
1284      set('d', Math.floor(diff / 86400000));
1285      set('h', pad(Math.floor(diff % 86400000 / 3600000)));
1286      set('m', pad(Math.floor(diff % 3600000 / 60000)));
1287      set('s', pad(Math.floor(diff % 60000 / 1000)));
1288    }
1289    tick(); setInterval(tick, 1000);
1290  })();
1291</script>
1291
1292
1293<!--
1294  WIRING NOTES (for Pat):
1295  1. Outseta: swap every [data-outseta] link for the real Outseta embed/auth links once the account exists.
1296     Gated items [data-gated] check Outseta paid status (fail closed). FRONT DESK IS MEMBERS-ONLY (decision Jul 1).
1297  2. Live Tracker ticker + Events: content reads from Airtable via Make. Placeholders marked above.
1298  3. News list: WIRED — news-feed.js relays the latest 10 posts from indieagency.news (category-agnostic).
1299  4. Front Desk form: /front-desk page posts to the Make webhook (Airtable + R2), behind the Outseta gate.
1300  5. Deploy: drop this folder into a Netlify site; point indiehq.com at it.
1301-->
1302
1303<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="feedback-widget.js" defer></script>
vendor: 1 bytes, line 1303
1303
1304<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="ihq-tips.js" defer></script>
1304
1305<!-- Mobile hamburger is owned solely by mobile-nav.js (one handler sitewide).
1306     A second inline handler here caused a double-toggle that cancelled itself out. -->
1307<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="mobile-nav.js" defer></script>
vendor: 1 bytes, line 1307
1307
1308<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="nav-back.js" defer></script>
vendor: 1 bytes, line 1308
1308
1309<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="signin-cue.js" defer></script>
vendor: 1 bytes, line 1309
1309
1310<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="ihq-brand.js" defer></script>
1310
1311<!-- ===== IndieHQ first-run welcome ===== -->
1312<style>
1313.ihqwm-overlay{position:fixed;inset:0;background:rgba(13,13,18,.55);backdrop-filter:blur(3px);z-index:99999;display:flex;align-items:center;justify-content:center;padding:20px;}
1314.ihqwm-overlay[hidden]{display:none;}
1315.ihqwm-card{background:#FAFAF8;color:#0D0D12;max-width:520px;width:100%;border-radius:18px;padding:30px 28px 22px;box-shadow:0 24px 70px rgba(0,0,0,.35);position:relative;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,sans-serif;animation:ihqwm-in .22s ease-out;}
1316@keyframes ihqwm-in{from{opacity:0;transform:translateY(10px) scale(.98);}to{opacity:1;transform:none;}}
1317.ihqwm-x{position:absolute;top:12px;right:15px;border:0;background:none;font-size:26px;line-height:1;color:#56565E;cursor:pointer;}
1318.ihqwm-kicker{color:#0C9B53;font-weight:700;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;margin-bottom:8px;}
1319.ihqwm-title{font-size:1.6rem;margin:0 0 8px;line-height:1.15;}
1320.ihqwm-sub{color:#56565E;font-size:.98rem;line-height:1.5;margin:0 0 18px;}
1321.ihqwm-actions{display:flex;flex-direction:column;gap:10px;}
1322.ihqwm-act{display:block;text-decoration:none;color:#0D0D12;border:1px solid #0D0D12;border-radius:12px;padding:13px 15px;transition:background .15s,transform .15s;}
1323.ihqwm-act:hover{background:#E9FAF0;transform:translateY(-1px);}
1324.ihqwm-act-h{display:block;font-weight:700;font-size:1rem;}
1325.ihqwm-act-s{display:block;color:#56565E;font-size:.86rem;margin-top:2px;}
1326.ihqwm-skip{display:block;width:100%;margin-top:16px;border:0;background:none;color:#56565E;font-size:.9rem;cursor:pointer;text-decoration:underline;}
1327.ihqwm-launch{display:inline-flex;align-items:center;gap:6px;margin:2px 0 14px;background:#21CF7E;color:#08301c;border:0;border-radius:999px;padding:8px 15px;font-weight:700;font-size:.85rem;cursor:pointer;}
1328.ihqwm-launch:hover{filter:brightness(1.06);}
1329</style>
1330<div id="ihqwm" class="ihqwm-overlay" hidden role="dialog" aria-modal="true" aria-labelledby="ihqwm-title">
1331  <div class="ihqwm-card">
1332    <button class="ihqwm-x" id="ihqwm-x" aria-label="Close">&times;</button>
1333    <div class="ihqwm-kicker">Welcome in</div>
1334    <h3 id="ihqwm-title" class="ihqwm-title">Welcome to IndieHQ</h3>
1335    <p class="ihqwm-sub">You&rsquo;re part of the independent agency community now. Here are three good first moves &mdash; or explore on your own.</p>
1336    <div class="ihqwm-actions">
1337      <a class='ihqwm-act' data-ihqwm='go' href='/commons'><span class="ihqwm-act-h">Say hi in the Commons</span><span class="ihqwm-act-s">Meet your people &mdash; 360+ indie agencies.</span></a>
1338      <a class='ihqwm-act' data-ihqwm='go' href='/quickcoach'><span class="ihqwm-act-h">Run your first QuickCoach</span><span class="ihqwm-act-s">Fast, useful feedback before it goes out.</span></a>
1339      <a class='ihqwm-act' data-ihqwm='go' href='/frontdesk'><span class="ihqwm-act-h">Ask the Front Desk anything</span><span class="ihqwm-act-s">A real person, ready to help.</span></a>
1340    </div>
1341    <button class="ihqwm-skip" id="ihqwm-skip" type="button">I&rsquo;ll explore on my own</button>
1342  </div>
1343</div>
1344<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
1345(function(){
1346  var KEY="ihq_session", SEEN="ihq_welcomed";
1347  function sess(){try{var p=JSON.parse(localStorage.getItem(KEY)||"null");if(!p)return null;if(p.exp&&Date.now()>p.exp)return null;return p;}catch(e){return null;}}
1348  var s=sess(), ov=document.getElementById("ihqwm"), launch=document.getElementById("ihqwm-launch");
1349  if(!ov)return;
1350  function seen(){try{localStorage.setItem(SEEN,"1");}catch(e){}}
1351  function esc(e){if(e.key==="Escape")close();}
1352  function open(){ov.hidden=false;document.addEventListener("keydown",esc);}
1353  function close(){ov.hidden=true;seen();document.removeEventListener("keydown",esc);}
1354  if(s){
1355    var fn=((s.name||"").trim().split(/\s+/)[1]||"");
1356    var t=document.getElementById("ihqwm-title");
1357    if(t)t.textContent=fn?("Welcome in, "+fn+"!"):"Welcome to IndieHQ";
1358    if(launch){launch.hidden=false;launch.addEventListener("click",open);}
1359  }
1360  var x=document.getElementById("ihqwm-x"), sk=document.getElementById("ihqwm-skip");
1361  if(x)x.addEventListener("click",close);
1362  if(sk)sk.addEventListener("click",close);
1363  ov.addEventListener("click",function(e){if(e.target===ov)close();});
1364  Array.prototype.forEach.call(ov.querySelectorAll('[data-ihqwm="go"]'),function(a){a.addEventListener("click",seen);});
1365  /* Onboarding now lives on /member-hq (its own first-visit nudge), and members land
1366     there at sign-in — so the marketing homepage no longer auto-pops a welcome mat. */
1367})();
1368</script>
1368
1369
1370<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="service-notice.js" defer></script>
vendor: 1 bytes, line 1370
1370
1371<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="email-reveal.js" defer></script>
vendor: 1 bytes, line 1371
1371
1372<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
1373  /* Member-first landing: greet by name + hoist the Member HQ launchpad to the top. */
1374  (function(){
1375    try{
1376      var p = JSON.parse(localStorage.getItem("ihq_session") || "null");
1377      if(!p || (p.exp && Date.now() >= p.exp) || p.role === "team") return;
1378      var first = ((p.name || "").trim().split(/\s+/)[0] || "").replace(/[<>&"]/g, "");
1379      var g = document.getElementById("mh-greeting");
1380      if(g && first) g.innerHTML = "Welcome back, " + first + ". <span class=\"accent\">Here’s your HQ.</span>";
1381      var members = document.getElementById("members");
1382      var band = document.querySelector(".member-hero");
1383      if(members && band && band.parentNode){ band.insertAdjacentElement("afterend", members); }
1384      // Pull a few live headlines into the welcome — news stays front and center.
1385      var nwrap = document.getElementById("mh-news"), nlist = document.getElementById("mh-news-list");
1386      if(nwrap && nlist){
1387        var nesc = function(s){ return (s==null?"":String(s)).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;","\"":"&quot;"}[c];}); };
1388        fetch("/.netlify/functions/news-feed").then(function(r){ return r.json(); }).then(function(d){
1389          var items = (d && d.items) || [];
1390          if(!items.length) return;
1391          nlist.innerHTML = items.slice(0,3).map(function(i){
1392            return '<a class="mh-news-item" href="' + nesc(/^https?:\/\//i.test(i.url) ? i.url : '#') + '" target="_blank" rel="noopener">' +
1393              '<span class="nt">' + nesc(i.category) + '</span><h4>' + nesc(i.title) + '</h4></a>';
1394          }).join("");
1395          nwrap.hidden = false;
1396        }).catch(function(){});
1397      }
1398      // Newsletter opt-in nudge — show only to signed-in members who aren't on the list yet.
1399      try{
1400        if(!localStorage.getItem("ihq_nl_dismissed")){
1401          var tok = p.session;
1402          fetch("/.netlify/functions/newsletter-status",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({session:tok})})
1403            .then(function(r){return r.json();}).then(function(d){
1404              if(!d || d.subscribed !== false) return;
1405              var box=document.getElementById("mh-optin"); if(!box) return;
1406              box.hidden=false;
1407              var yes=document.getElementById("mh-optin-yes"), no=document.getElementById("mh-optin-no");
1408              if(yes) yes.addEventListener("click",function(){
1409                yes.disabled=true; yes.textContent="Adding you…";
1410                fetch("/.netlify/functions/newsletter-status",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({session:tok,action:"subscribe"})})
1411                  .then(function(r){return r.json();}).then(function(){
1412                    box.innerHTML='<span class="mh-optin-txt" style="font-weight:600;">You’re on the list. ✓ Welcome aboard.</span>';
1413                    try{localStorage.setItem("ihq_nl_dismissed","1");}catch(e){}
1414                  }).catch(function(){ yes.disabled=false; yes.textContent="Yes, sign me up"; });
1415              });
1416              if(no) no.addEventListener("click",function(){ box.hidden=true; try{localStorage.setItem("ihq_nl_dismissed","1");}catch(e){} });
1417            }).catch(function(){});
1418        }
1419      }catch(e){}
1420    }catch(e){}
1421  })();
1422</script>
1422
1423
1424<!-- ===== Is It IP? homepage pop-up (public · one-time per browser · powered by Toerek) ===== -->
1425<style>
1426  #ipHome{position:fixed;inset:0;z-index:10000;background:rgba(13,13,18,.62);display:flex;align-items:center;justify-content:center;padding:20px;}
1427  #ipHome[hidden]{display:none;}
1428  #ipHome .ipbox{background:var(--paper);border:2px solid var(--ink);border-radius:16px;max-width:440px;width:100%;padding:26px;box-shadow:0 24px 60px rgba(0,0,0,.35);}
1429  #ipHome img.iplogo{height:32px;width:auto;display:block;margin-bottom:14px;}
1430  #ipHome h2{font-size:1.6rem;margin:0 0 8px;color:var(--ink);}
1431  #ipHome p{margin:0 0 18px;color:#3a3a42;font-size:1rem;line-height:1.5;}
1432  #ipHome .ipcta{display:flex;flex-wrap:wrap;gap:10px 14px;align-items:center;}
1433  #ipHome .ipgo{background:var(--accent);color:var(--ink);font-weight:800;padding:12px 22px;border-radius:999px;text-decoration:none;border:2px solid var(--accent);}
1434  #ipHome .iplater{background:none;border:0;color:var(--ink);opacity:.6;font-size:.95rem;cursor:pointer;text-decoration:underline;text-underline-offset:3px;}
1435  #ipHome .iplater:hover{opacity:1;}
1436</style>
1437<div id="ipHome" hidden role="dialog" aria-modal="true" aria-labelledby="ipHomeH">
1438  <div class="ipbox">
1439    <img class="iplogo" src="https://media.indiehq.com/IndieHQ%20Site%20Images/Preferred%20Partner/Toerek/Legal___Creative.png" alt="Toerek L
1439aw | Legal + Creative">
1440    <h2 id="ipHomeH">Is it IP?</h2>
1441    <p>You made something and want to protect it &mdash; but half the time, the thing agencies try to own can&rsquo;t be owned at all. Take the free 2-minute gut-check and get a plain read. Powered by Toerek Law | Legal + Creative.</p>
1442    <div class="ipcta">
1443      <a class="ipgo" id="ipHomeGo" href="/is-it-ip">Take the gut-check &rarr;</a>
1444      <button type="button" class="iplater" id="ipHomeLater">Maybe later</button>
1445    </div>
1446  </div>
1447</div>
1448<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
1449  (function () {
1450    function run() {
1451      var force = /[?&]ip=1/.test(location.search);            // /?ip=1 forces it (test/demo)
1452      var KEY = "ihq_isitip_home_v1", seen = false;
1453      try { seen = localStorage.getItem(KEY) === "1"; } catch (e) {}
1454      var ov = document.getElementById("ipHome"); if (!ov) return;
1455      function done() { try { if (!force) localStorage.setItem(KEY, "1"); } catch (e) {} ov.setAttribute("hidden", ""); }
1456      function open() { ov.removeAttribute("hidden"); }
1457      if (force) open();
1458      else if (!seen) setTimeout(open, 1400);                  // gentle delay so it doesn't slam on load
1459      var go = document.getElementById("ipHomeGo"); if (go) go.addEventListener("click", done);
1460      var later = document.getElementById("ipHomeLater"); if (later) later.addEventListener("click", done);
1461      ov.addEventListener("click", function (e) { if (e.target === ov) done(); });
1462      document.addEventListener("keydown", function (e) { if (e.key === "Escape" && !ov.hasAttribute("hidden")) done(); });
1463    }
1464    if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", run);
1465    else run();
1466  })();
1467</script>
1467
1468<!-- ===== IndieHQ Radio — homepage mini player (appears only while a show is live) ===== -->
1469<style>
1470  #ianRadioBar{position:fixed;left:0;right:0;bottom:0;z-index:60;display:none;align-items:center;gap:12px;
1471    background:rgba(13,13,18,.97);backdrop-filter:blur(8px);border-top:2px solid var(--accent);
1472    padding:9px 14px calc(9px + env(safe-area-inset-bottom));color:#fff;}
1473  #ianRadioBar .rb-play{width:42px;height:42px;border-radius:50%;border:none;background:var(--accent);color:#0D0D12;flex:0 0 auto;display:flex;align-items:center;justify-content:center;cursor:pointer;}
1474  #ianRadioBar .rb-play svg{width:18px;height:18px;}
1475  #ianRadioBar .rb-meta{min-width:0;flex:1;}
1476  #ianRadioBar .rb-k{font-size:.62rem;letter-spacing:.14em;text-transform:uppercase;font-weight:800;color:var(--accent);display:flex;align-items:center;gap:6px;}
1477  #ianRadioBar .rb-dot{width:7px;height:7px;border-radius:50%;background:var(--accent);animation:rbpulse 1.4s ease-in-out infinite;}
1478  @keyframes rbpulse{0%,100%{opacity:1}50%{opacity:.35}}
1479  #ianRadioBar .rb-t{font-size:.9rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
1480  #ianRadioBar .rb-open{color:#fff;text-decoration:none;font-weight:700;font-size:.82rem;white-space:nowrap;opacity:.85;}
1481  #ianRadioBar .rb-x{background:none;border:0;color:#fff;opacity:.5;font-size:1.2rem;line-height:1;cursor:pointer;padding:4px;}
1482</style>
1483<div id="ianRadioBar">
1484  <button class="rb-play" id="rbPlay" aria-label="Play IndieHQ Radio"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg></button>
1485  <div class="rb-meta">
1486    <div class="rb-k"><span class="rb-dot"></span>Good Day Advertising &middot; Live</div>
1487    <div class="rb-t" id="rbTitle">On air now</div>
1488  </div>
1489  <a class="rb-open" href="/radio">Open player &rarr;</a>
1490  <button class="rb-x" id="rbX" aria-label="Hide">&times;</button>
1491</div>
1492<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="radio-config.js"></script>
vendor: 1 bytes, line 1492
1492
1493<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==">
1494(function(){
1495  var CFG=window.IAN_RADIO||{}; var SID=(CFG.STATION_ID||"").trim();
1496  if(!SID) return;                                   // nothing shows until the station ID is set
1497  if(CFG.HOME_BAR!==true) return;                    // manual switch: homepage bar only when we flip HOME_BAR on for a real show (station is "online" during automation too)
1498  try{ if(sessionStorage.getItem("ian_radio_bar_off")==="1") return; }catch(e){}
1499  var STREAM="https://streams.radio.co/"+SID+"/listen", STATUS="/.netlify/functions/radio-status?s="+encodeURIComponent(SID);
1500  var bar=document.getElementById("ianRadioBar"), play=document.getElementById("rbPlay"),
1501      title=document.getElementById("rbTitle"), x=document.getElementById("rbX");
1502  var audio=new Audio(); audio.preload="none";
1503  var PLAY='<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>';
1504  var PAUSE='<svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 5h4v14H6zM14 5h4v14h-4z"/></svg>';
1505  play.addEventListener("click",function(){
1506    if(audio.paused){ if(audio.src!==STREAM)audio.src=STREAM; audio.play().then(function(){play.innerHTML=PAUSE;}).catch(function(){}); }
1507    else { audio.pause(); play.innerHTML=PLAY; }
1508  });
1509  x.addEventListener("click",function(){ audio.pause(); bar.style.display="none"; try{sessionStorage.setItem("ian_radio_bar_off","1");}catch(e){} });
1510  function poll(){
1511    fetch(STATUS).then(function(r){return r.json();}).then(function(d){
1512      var online=d.status==="online";
1513      if(d.streaming_hostname) STREAM="https://"+d.streaming_hostname+"/"+SID+"/listen"; // real stream host (streams.radio.co 403s)
1514      bar.style.display = online ? "flex" : "none";  // only while a show is live
1515      if(online){ title.textContent=(d.current_track&&d.current_track.title)||"On air now"; }
1516    }).catch(function(){});
1517  }
1518  poll(); setInterval(poll,30000);
1519})();
1520</script>
vendor: 1 bytes, line 1520
1520
1521<script nonce="4ZpV9mdUbRwVjmlyHiDdGQ==" src="/ihq-quotes.js" data-use="Homepage" defer></script>
1521
1522</body>
1523</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.