source: Klonkt/src/views/partials/profile-header.ejs@ 7eddb3b

main
Last change on this file since 7eddb3b was 7eddb3b, checked in by Robin Genis <roboburr@…>, 2 months ago

feat(profile): fediverse-follow button in the avatar summary modal

  • views/partials/profile-header.ejs — add a neat accent-pill "follow via the fediverse" button to the .pf-summary modal (gated on _showFollow = apEnabled + not owner). Reuses the existing .profile-fedi-link delegated handler (prompt for your server → bounce to authorize_interaction) via data-fedi-actor-slug; same fediverse icon as the header; + CSS.
  • Property mode set to 100644
File size: 20.0 KB
Line 
1<!-- Profile header (v9 structure)
2 Body class controls collapse:
3 .on-home → full size, avatar + bio + links
4 .on-post → compact, just avatar + name
5 .on-special → compact (archive/search/tag pages)
6 .on-admin → hidden (admin pages don't show profile)
7-->
8
9<%
10// Show profile-header unless we're on an admin page or the site explicitly
11// disabled it via profile_enabled=0.
12const _showProfile = site
13 && (site.profile_enabled === undefined || site.profile_enabled !== 0)
14 && !(typeof bodyClass !== 'undefined' && bodyClass.indexOf('on-admin') >= 0);
15
16// profile_name and profile_bio used to be optional overrides exposed in the
17// admin form. P62 removed those form fields — title and description are the
18// single source of truth. We still consult the override columns first for
19// backward compat with any legacy data, but the form no longer writes them.
20const _displayName = (site && (site.profile_name || site.title)) || '';
21const _bioText = (site && (site.profile_bio || site.description || site.tagline)) || '';
22
23// Parse profile_links JSON column once.
24let _profileLinks = [];
25if (site && site.profile_links) {
26 try { _profileLinks = JSON.parse(site.profile_links) || []; } catch (e) { _profileLinks = []; }
27}
28
29// Profile-summary (lightbox) helpers — used by the avatar + the summary modal.
30const _base = (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '';
31const _avatarUrl = (site && site.profile_photo) || ((typeof siteOwnerAvatar !== 'undefined' && siteOwnerAvatar) || '');
32const _platforms = (typeof platforms_catalog !== 'undefined' && platforms_catalog) || {};
33const _linkHref = function (p, u) { u = String(u || '').trim(); if (p === 'email' && u && u.indexOf('mailto:') !== 0) return 'mailto:' + u; if (p === 'phone' && u && !/^tel:/i.test(u)) return 'tel:' + u.replace(/[^\d+]/g, ''); return u; };
34const _linkVal = function (u) { return String(u || '').replace(/^(mailto:|tel:|https?:\/\/)/i, '').replace(/\/$/, ''); };
35const _isPrem = (typeof isPremium !== 'undefined' && isPremium);
36let _sinceStr = ''; try { if (site && site.created_at) _sinceStr = new Date(site.created_at).toLocaleDateString('nl-NL', { day: '2-digit', month: 'short', year: 'numeric' }); } catch (e) {}
37%>
38
39<% if (_showProfile) { %>
40<aside class="profile-header" aria-label="Site profile">
41 <div class="container profile-header-inner">
42
43 <% if (_avatarUrl) { %>
44 <%# With a real photo: clicking opens the profile-summary modal (photo + details). %>
45 <button type="button" class="profile-photo" data-pf-summary aria-label="<%= _displayName || 'Profile' %>">
46 <img src="<%= _avatarUrl %>" alt="">
47 </button>
48 <% } else { %>
49 <a class="profile-photo" href="<%= _base %>/"
50 hx-get="<%= _base %>/?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
51 hx-push-url="<%= _base %>/" hx-indicator="#pcms-loading" aria-label="Home">
52 <% if (site.enable_audio_player && (typeof audioEnabled === 'undefined' || audioEnabled)) { %>
53 <span class="profile-photo-fallback profile-photo-fallback--music" aria-hidden="true">
54 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
55 <path d="M9 17V5l12-2v12"/>
56 <circle cx="6" cy="17" r="3"/>
57 <circle cx="18" cy="15" r="3"/>
58 </svg>
59 </span>
60 <% } else { %>
61 <span class="profile-photo-fallback" aria-hidden="true"><%= (_displayName || '?').charAt(0).toUpperCase() %></span>
62 <% } %>
63 </a>
64 <% } %>
65
66 <div class="profile-info">
67 <h2 class="profile-name">
68 <a href="<%= (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '' %>/"
69 hx-get="<%= (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '' %>/?partial=1"
70 hx-target="#pcms-main" hx-swap="innerHTML"
71 hx-push-url="<%= (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '' %>/"
72 hx-indicator="#pcms-loading">
73 <%= _displayName %>
74 </a>
75 </h2>
76 <% if (_bioText) { %>
77 <p class="profile-bio"><%= _bioText %></p>
78 <% } %>
79
80 <%# Follow-via-fediverse: a compact icon in the links row (keeps the header
81 short), and hidden for the owner — you don't follow yourself. %>
82 <% var _showFollow = (typeof canManageFedi === 'undefined' || !canManageFedi) && site && site.slug && (typeof apEnabled === 'undefined' || apEnabled); %>
83 <% if (_profileLinks.length || _showFollow) { %>
84 <% const _platforms = (typeof platforms_catalog !== 'undefined' && platforms_catalog) || {}; %>
85 <ul class="profile-links" aria-label="External links">
86 <% _profileLinks.forEach(function(l) {
87 const meta = _platforms[l.platform];
88 if (!meta) return; %>
89 <li>
90 <a class="profile-link profile-link--<%= l.platform %>"
91 href="<%= l.platform === 'email' && l.url.indexOf('mailto:') !== 0 ? ('mailto:' + l.url) : l.url %>"
92 target="<%= l.platform === 'email' ? '_self' : '_blank' %>"
93 rel="noopener noreferrer"
94 aria-label="<%= meta.label %>"
95 title="<%= meta.label %>"
96 style="--brand: <%= meta.brand %>">
97 <%- meta.svg %>
98 </a>
99 </li>
100 <% }); %>
101 <% if (_showFollow) { %>
102 <li style="order:-1">
103 <button type="button" class="profile-link profile-fedi-link" data-fedi-actor-slug="<%= site.slug %>"
104 aria-label="<%= t('fedi.profile_follow') %>" title="<%= t('fedi.profile_follow') %>"><svg viewBox="151 31 530 530" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><g transform="translate(6.6789703,-32.495842)"><path d="M257.1,266.8c-4.9,9.4-12.6,17.1-22.1,22l121.3,121.8l29.2-14.8L257.1,266.8z M417.1,427.4l-29.2,14.8l61.5,61.7c4.9-9.4,12.6-17.1,22.1-22L417.1,427.4z"/><path d="M557.5,315l-68.7,34.8l5.1,32.4l77.7-39.4C564.1,335.2,559.2,325.5,557.5,315z M448.9,370l-162.4,82.3c7.5,7.6,12.4,17.3,14.1,27.8L454,402.4L448.9,370z"/><path d="M396.7,167.3l-78.4,153l23.1,23.2l83-162C414,179.7,404.3,174.7,396.7,167.3z M298,360l-39.7,77.5c10.5,1.8,20.2,6.7,27.7,14.2l35.1-68.5L298,360z"/><path d="M234.3,289.1c-8,4-16.9,5.9-25.8,5.4c-1.7-0.1-3.3-0.3-5-0.5l23.2,148.2c8-4,16.9-5.9,25.8-5.4c1.7,0.1,3.3,0.3,5,0.5L234.3,289.1z"/><path d="M300.8,480.8c0.5,3.4,0.7,6.9,0.5,10.4c-0.4,7.1-2.3,14-5.5,20.4l148.2,23.8c-0.5-3.4-0.7-6.9-0.5-10.4c0.4-7.1,2.3-14,5.5-20.4L300.8,480.8z"/><path d="M572.1,343.3l-68.4,133.6c10.5,1.8,20.2,6.7,27.7,14.2l68.4-133.6C589.4,355.8,579.7,350.8,572.1,343.3z"/><path d="M478.8,154.4c-4.9,9.4-12.6,17.1-22.1,22l105.9,106.4c4.9-9.4,12.6-17.1,22.1-22L478.8,154.4z"/><path d="M382.1,138.9l-133.9,67.9c7.5,7.6,12.4,17.3,14.1,27.8l133.9-67.9C388.7,159.1,383.8,149.4,382.1,138.9z"/><path d="M456.5,176.6c-8.1,4.1-17.1,6.1-26.2,5.6c-1.5-0.1-3-0.3-4.5-0.5l11.9,76l32.4,5.2L456.5,176.6z M444.5,301.8l28.1,179.6c7.9-3.9,16.7-5.7,25.4-5.2c1.8,0.1,3.6,0.3,5.4,0.6L476.8,307L444.5,301.8z"/><path d="M262.4,235.2c0.6,3.5,0.7,7,0.6,10.6c-0.4,7-2.2,13.9-5.4,20.2l76,12.2l14.9-29.2L262.4,235.2z M392.7,256.1l-14.9,29.2l179.6,28.9c-0.5-3.4-0.7-6.9-0.5-10.3c0.4-7.1,2.3-14.1,5.5-20.5L392.7,256.1z"/><circle cx="433" cy="130.6" r="47"/><circle cx="608.4" cy="306.6" r="47"/><circle cx="495.1" cy="527.8" r="47"/><circle cx="249.7" cy="488.4" r="47"/><circle cx="211.3" cy="242.9" r="47"/></g></svg></button>
105 </li>
106 <% } %>
107 </ul>
108 <% } %>
109 </div>
110
111 </div>
112</aside>
113
114<%# Profile-summary modal — opened by clicking the avatar. Shows photo + title + subtitle
115 + contact details + start date + premium status. %>
116<% if (_avatarUrl) { %>
117<div class="pf-summary">
118 <div class="pf-summary-card" role="dialog" aria-label="<%= _displayName %>">
119 <button type="button" class="pf-summary-close" aria-label="Sluiten">&times;</button>
120 <img class="pf-summary-photo" src="<%= _avatarUrl %>" alt="">
121 <h3 class="pf-summary-name"><%= _displayName %></h3>
122 <span class="pf-summary-prem<%= _isPrem ? ' is-prem' : '' %>"><%= _isPrem ? '★ Premium' : t('profile.free') %></span>
123 <% if (_bioText) { %><p class="pf-summary-bio"><%= _bioText %></p><% } %>
124 <% if (_profileLinks.length) { %>
125 <ul class="pf-summary-links">
126 <% _profileLinks.forEach(function (l) { var meta = _platforms[l.platform]; if (!meta) return; var href = _linkHref(l.platform, l.url); var ext = (l.platform !== 'email' && l.platform !== 'phone'); %>
127 <li>
128 <a href="<%= href %>" <% if (ext) { %>target="_blank" rel="noopener noreferrer"<% } %> style="--brand: <%= meta.brand %>">
129 <span class="pf-summary-ico" aria-hidden="true"><%- meta.svg %></span>
130 <span class="pf-summary-rowtext"><span class="pf-summary-lbl"><%= meta.label %></span><span class="pf-summary-val"><%= _linkVal(l.url) %></span></span>
131 </a>
132 </li>
133 <% }); %>
134 </ul>
135 <% } %>
136 <% if (_showFollow) { %>
137 <button type="button" class="pf-summary-follow profile-fedi-link" data-fedi-actor-slug="<%= site.slug %>" aria-label="<%= t('fedi.profile_follow') %>">
138 <svg class="pf-summary-follow-ico" viewBox="151 31 530 530" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><g transform="translate(6.6789703,-32.495842)"><path d="M257.1,266.8c-4.9,9.4-12.6,17.1-22.1,22l121.3,121.8l29.2-14.8L257.1,266.8z M417.1,427.4l-29.2,14.8l61.5,61.7c4.9-9.4,12.6-17.1,22.1-22L417.1,427.4z"/><path d="M557.5,315l-68.7,34.8l5.1,32.4l77.7-39.4C564.1,335.2,559.2,325.5,557.5,315z M448.9,370l-162.4,82.3c7.5,7.6,12.4,17.3,14.1,27.8L454,402.4L448.9,370z"/><path d="M396.7,167.3l-78.4,153l23.1,23.2l83-162C414,179.7,404.3,174.7,396.7,167.3z M298,360l-39.7,77.5c10.5,1.8,20.2,6.7,27.7,14.2l35.1-68.5L298,360z"/><path d="M234.3,289.1c-8,4-16.9,5.9-25.8,5.4c-1.7-0.1-3.3-0.3-5-0.5l23.2,148.2c8-4,16.9-5.9,25.8-5.4c1.7,0.1,3.3,0.3,5,0.5L234.3,289.1z"/><path d="M300.8,480.8c0.5,3.4,0.7,6.9,0.5,10.4c-0.4,7.1-2.3,14-5.5,20.4l148.2,23.8c-0.5-3.4-0.7-6.9-0.5-10.4c0.4-7.1,2.3-14,5.5-20.4L300.8,480.8z"/><path d="M572.1,343.3l-68.4,133.6c10.5,1.8,20.2,6.7,27.7,14.2l68.4-133.6C589.4,355.8,579.7,350.8,572.1,343.3z"/><path d="M478.8,154.4c-4.9,9.4-12.6,17.1-22.1,22l105.9,106.4c4.9-9.4,12.6-17.1,22.1-22L478.8,154.4z"/><path d="M382.1,138.9l-133.9,67.9c7.5,7.6,12.4,17.3,14.1,27.8l133.9-67.9C388.7,159.1,383.8,149.4,382.1,138.9z"/><path d="M456.5,176.6c-8.1,4.1-17.1,6.1-26.2,5.6c-1.5-0.1-3-0.3-4.5-0.5l11.9,76l32.4,5.2L456.5,176.6z M444.5,301.8l28.1,179.6c7.9-3.9,16.7-5.7,25.4-5.2c1.8,0.1,3.6,0.3,5.4,0.6L476.8,307L444.5,301.8z"/><path d="M262.4,235.2c0.6,3.5,0.7,7,0.6,10.6c-0.4,7-2.2,13.9-5.4,20.2l76,12.2l14.9-29.2L262.4,235.2z M392.7,256.1l-14.9,29.2l179.6,28.9c-0.5-3.4-0.7-6.9-0.5-10.3c0.4-7.1,2.3-14.1,5.5-20.5L392.7,256.1z"/><circle cx="433" cy="130.6" r="47"/><circle cx="608.4" cy="306.6" r="47"/><circle cx="495.1" cy="527.8" r="47"/><circle cx="249.7" cy="488.4" r="47"/><circle cx="211.3" cy="242.9" r="47"/></g></svg>
139 <span><%= t('fedi.profile_follow') %></span>
140 </button>
141 <% } %>
142 <% if (_sinceStr) { %><p class="pf-summary-since"><%= t('profile.since') %> <%= _sinceStr %></p><% } %>
143 </div>
144</div>
145<% } %>
146<script>
147(function () {
148 if (window.__pcmsFediFollowWired) return;
149 window.__pcmsFediFollowWired = true;
150 document.addEventListener('click', function (e) {
151 var b = e.target.closest && e.target.closest('.profile-fedi-link');
152 if (!b) return;
153 var raw = window.prompt(<%- JSON.stringify(t('fedi.remote_prompt')) %>, '');
154 if (!raw) return;
155 // Strip a full @user@host handle (and any scheme/path) down to the server host.
156 var server = raw.trim().replace(/^@?[^@\s]*@/, '').replace(/^https?:\/\//i, '').replace(/\/.*$/, '').trim();
157 if (!server) return;
158 var actor = location.origin + '/ap/users/' + encodeURIComponent(b.getAttribute('data-fedi-actor-slug') || '');
159 location.href = 'https://' + server + '/authorize_interaction?uri=' + encodeURIComponent(actor);
160 });
161})();
162
163/* Profile summary: click the avatar to open a modal with photo + details. */
164(function () {
165 if (window.__pcmsLightboxWired) return; window.__pcmsLightboxWired = true;
166 function close() { var m = document.querySelector('.pf-summary.is-open'); if (m) m.classList.remove('is-open'); }
167 document.addEventListener('click', function (e) {
168 if (e.target.closest && e.target.closest('.pf-summary-close')) { e.preventDefault(); close(); return; }
169 var open = document.querySelector('.pf-summary.is-open');
170 if (open && e.target === open) { close(); return; } /* click on backdrop */
171 var t = e.target.closest && e.target.closest('.profile-photo[data-pf-summary]');
172 if (!t) return;
173 e.preventDefault();
174 var root = (t.closest && t.closest('#pcms-chrome')) || document;
175 var modal = root.querySelector('.pf-summary') || document.querySelector('.pf-summary');
176 if (modal) modal.classList.add('is-open');
177 });
178 document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
179})();
180</script>
181<% } %>
182
183<style>
184/* Profile header (v9 collapse pattern) */
185.profile-header {
186 border-bottom: 1px solid var(--rule);
187 background: var(--paper);
188 padding: 1.5rem 0;
189 transition: padding 250ms cubic-bezier(.4,0,.2,1);
190}
191.profile-header-inner {
192 max-width: 800px;
193 margin: 0 auto;
194 padding: 0 1rem;
195 display: flex;
196 align-items: center;
197 gap: 1.25rem;
198 transition: gap 250ms;
199}
200.profile-photo {
201 flex-shrink: 0;
202 display: block;
203 width: 80px;
204 height: 80px;
205 padding: 0;
206 border-radius: 50%;
207 overflow: hidden;
208 background: var(--paper-2);
209 border: 2px solid var(--rule);
210 transition: width 250ms, height 250ms;
211 cursor: pointer;
212 font: inherit;
213 -webkit-appearance: none;
214 appearance: none;
215}
216.profile-photo[data-lightbox] { cursor: zoom-in; }
217.profile-photo:hover {
218 border-color: var(--accent);
219}
220.profile-photo img {
221 width: 100%;
222 height: 100%;
223 object-fit: cover;
224 pointer-events: none;
225}
226.profile-photo-fallback {
227 display: flex;
228 align-items: center;
229 justify-content: center;
230 width: 100%;
231 height: 100%;
232 font-family: var(--font-display, serif);
233 font-size: 2rem;
234 font-weight: 700;
235 color: var(--ink-soft);
236 background: var(--paper-2);
237 pointer-events: none;
238}
239.profile-photo-fallback--music {
240 color: var(--accent);
241}
242.profile-photo-fallback--music svg {
243 width: 50%;
244 height: 50%;
245}
246.profile-info {
247 flex: 1;
248 min-width: 0;
249}
250.profile-name {
251 font-family: var(--font-display, serif);
252 font-size: 1.75rem;
253 margin: 0 0 0.25rem;
254 line-height: 1.2;
255}
256.profile-name a {
257 color: var(--ink);
258 text-decoration: none;
259}
260.profile-bio {
261 margin: 0;
262 color: var(--ink-soft);
263 font-size: 0.95rem;
264 line-height: 1.4;
265}
266
267/* Compact mode on post / special pages */
268.on-post .profile-header,
269.on-special .profile-header,
270.on-search .profile-header,
271.on-archive .profile-header {
272 padding: 0.75rem 0;
273}
274.on-post .profile-photo,
275.on-special .profile-photo,
276.on-search .profile-photo,
277.on-archive .profile-photo {
278 width: 40px;
279 height: 40px;
280 border-width: 1px;
281}
282.on-post .profile-photo-fallback,
283.on-special .profile-photo-fallback,
284.on-search .profile-photo-fallback,
285.on-archive .profile-photo-fallback {
286 font-size: 1rem;
287}
288.on-post .profile-name,
289.on-special .profile-name,
290.on-search .profile-name,
291.on-archive .profile-name {
292 font-size: 1.1rem;
293 margin: 0;
294}
295.on-post .profile-bio,
296.on-special .profile-bio,
297.on-search .profile-bio,
298.on-archive .profile-bio {
299 display: none;
300}
301
302/* Hide on admin pages */
303.on-admin .profile-header { display: none; }
304
305/* Mobile tweaks */
306@media (max-width: 600px) {
307 .profile-photo { width: 64px; height: 64px; }
308 .profile-photo-fallback { font-size: 1.5rem; }
309 .profile-name { font-size: 1.4rem; }
310}
311
312/* Social / streaming icon row */
313.profile-links {
314 list-style: none;
315 margin: 0.5rem 0 0;
316 padding: 0;
317 display: flex;
318 gap: 0.5rem;
319 flex-wrap: wrap;
320}
321.profile-link {
322 display: inline-flex;
323 align-items: center;
324 justify-content: center;
325 width: 36px;
326 height: 36px;
327 border-radius: 50%;
328 background: var(--paper-2);
329 color: var(--ink-soft);
330 text-decoration: none;
331 transition: background 120ms, color 120ms, transform 100ms ease;
332}
333.profile-link:hover {
334 background: var(--brand, var(--accent));
335 color: white;
336 transform: translateY(-1px);
337}
338.profile-link svg { width: 18px; height: 18px; display: block; }
339
340/* Compact mode collapses social links too (post pages) */
341.on-post .profile-links,
342.on-special .profile-links,
343.on-archive .profile-links { display: none; }
344
345/* Follow-via-fediverse: compact icon button, sits in the links row */
346.profile-fedi-link { border: 0; padding: 0; background: var(--paper-2); cursor: pointer; -webkit-appearance: none; appearance: none; }
347/* The fediverse logo is an open line-network, so it reads smaller than a solid
348 glyph at 18px — render it larger INSIDE the same 36px circle (circle unchanged). */
349.profile-fedi-link svg { width: 22px; height: 22px; }
350
351/* Profile-summary modal (click the avatar) */
352.profile-photo[data-pf-summary] { cursor: zoom-in; }
353.pf-summary { position: fixed; inset: 0; z-index: 2147483600; display: none;
354 align-items: center; justify-content: center; padding: 4vmin;
355 background: rgba(0,0,0,.7); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
356.pf-summary.is-open { display: flex; }
357.pf-summary-card { position: relative; width: 100%; max-width: 380px; max-height: 90vh; overflow-y: auto;
358 background: var(--paper); color: var(--ink); border: 1px solid var(--rule); border-radius: 20px;
359 padding: 1.75rem 1.5rem; box-shadow: 0 20px 60px rgba(0,0,0,.4); text-align: center; }
360.pf-summary-close { position: absolute; top: .6rem; right: .7rem; width: 36px; height: 36px; border: 0;
361 border-radius: 50%; background: var(--paper-2); color: var(--ink-soft); font-size: 1.5rem; line-height: 1;
362 cursor: pointer; display: flex; align-items: center; justify-content: center; }
363.pf-summary-close:hover { color: var(--ink); }
364.pf-summary-photo { width: 110px; height: 110px; border-radius: 50%; object-fit: cover; margin: 0 auto .9rem;
365 display: block; border: 3px solid var(--paper-2); background: #fff; }
366.pf-summary-name { font-family: var(--font-display, serif); font-size: 1.4rem; margin: 0 0 .35rem; }
367.pf-summary-prem { display: inline-block; margin: 0 0 .7rem; padding: .15rem .6rem; border-radius: 999px;
368 font-size: .75rem; font-weight: 600; background: var(--paper-2); color: var(--ink-soft); }
369.pf-summary-prem.is-prem { background: color-mix(in srgb, #e8b04b 22%, transparent); color: #b8860b; }
370.pf-summary-bio { color: var(--ink-soft); font-size: .92rem; line-height: 1.5; margin: 0 0 1rem; }
371.pf-summary-links { list-style: none; padding: 0; margin: .25rem 0 1rem; display: flex; flex-direction: column; gap: .4rem; text-align: left; }
372.pf-summary-links a { display: flex; align-items: center; gap: .7rem; padding: .5rem .7rem; border-radius: 12px;
373 text-decoration: none; color: var(--ink); background: var(--paper-2); transition: background .12s; }
374.pf-summary-links a:hover { background: color-mix(in srgb, var(--brand, var(--accent)) 16%, var(--paper-2)); }
375.pf-summary-ico { flex: 0 0 22px; width: 22px; height: 22px; color: var(--brand, var(--ink-soft)); display: inline-flex; }
376.pf-summary-ico svg { width: 22px; height: 22px; }
377.pf-summary-rowtext { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
378.pf-summary-lbl { font-size: .72rem; font-weight: 600; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .03em; }
379.pf-summary-val { font-size: .9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
380.pf-summary-since { color: var(--ink-soft); font-size: .8rem; margin: 0; }
381.pf-summary-follow { display: inline-flex; align-items: center; gap: .5rem; margin: .2rem auto 1rem; padding: .5rem 1.15rem;
382 border: 1.5px solid var(--accent); border-radius: 999px; background: transparent; color: var(--accent);
383 font: inherit; font-weight: 600; font-size: .88rem; cursor: pointer; transition: background .15s, color .15s; }
384.pf-summary-follow:hover { background: var(--accent); color: var(--paper); }
385.pf-summary-follow-ico { width: 18px; height: 18px; flex: 0 0 auto; }
386</style>
Note: See TracBrowser for help on using the repository browser.