405 lines
32 KiB
Svelte
405 lines
32 KiB
Svelte
<script lang="ts">
|
|
import AgentIdentityLink from '$lib/components/AgentIdentityLink.svelte';
|
|
import AccountControl from '$lib/components/AccountControl.svelte';
|
|
import CommentComposer from '$lib/components/CommentComposer.svelte';
|
|
import ContentReport from '$lib/components/ContentReport.svelte';
|
|
import InfoPopover from '$lib/components/InfoPopover.svelte';
|
|
import MarkdownContent from '$lib/components/MarkdownContent.svelte';
|
|
import MarkdownEditor from '$lib/components/MarkdownEditor.svelte';
|
|
import ModerationDisclosure from '$lib/components/ModerationDisclosure.svelte';
|
|
import OverflowMenu from '$lib/components/OverflowMenu.svelte';
|
|
import PageBreadcrumb from '$lib/components/PageBreadcrumb.svelte';
|
|
import PendingForm from '$lib/components/PendingForm.svelte';
|
|
import { tick } from 'svelte';
|
|
|
|
type PublicAgent = {
|
|
id: string;
|
|
displayName: string;
|
|
publicSlug: string;
|
|
avatarUrl: string;
|
|
bioHtml: string;
|
|
bioMarkdown: string;
|
|
isPublic: boolean;
|
|
bioHidden: boolean;
|
|
bioModerationReason: string | null;
|
|
bioReviewPending: boolean;
|
|
bioReviewReason: string | null;
|
|
roles: string[];
|
|
};
|
|
type PublicContent = {
|
|
id: string;
|
|
slug: string;
|
|
title: string;
|
|
updatedAt: string;
|
|
};
|
|
type AuthoredComment = {
|
|
id: string;
|
|
createdAt: string;
|
|
targetType: string;
|
|
targetTitle: string;
|
|
targetHref: string;
|
|
};
|
|
type ProfileComment = {
|
|
id: string;
|
|
parentId: string | null;
|
|
status: 'visible' | 'removed';
|
|
bodyHtml: string;
|
|
removalReason: string | null;
|
|
createdAt: string;
|
|
author: { id: string; displayName: string; publicSlug: string | null; avatarUrl: string; roles: string[] };
|
|
canDelete: boolean;
|
|
canReport: boolean;
|
|
depth: number;
|
|
hasReplies: boolean;
|
|
rootId: string;
|
|
isFollowing: boolean;
|
|
isPinned: boolean;
|
|
};
|
|
type PageData = {
|
|
agent: PublicAgent;
|
|
counts: { builds: number; guides: number; authoredComments: number; profileComments: number };
|
|
builds: PublicContent[];
|
|
guides: PublicContent[];
|
|
authoredComments: AuthoredComment[];
|
|
profileComments: ProfileComment[];
|
|
viewer: { id: string | null; canComment: boolean; canReportProfile: boolean; isSelf: boolean };
|
|
accountControl: any | null;
|
|
};
|
|
|
|
let { data, form }: { data: PageData; form?: Record<string, any> | null } = $props();
|
|
let profileCommentDraft = $state('');
|
|
let activeComposerId = $state<string | null>(null);
|
|
let deletingCommentId = $state('');
|
|
let activeCommentMenuId = $state('');
|
|
let bioEditorOpen = $state(false);
|
|
let bioDraft = $state('');
|
|
let bioDraftInitialized = $state(false);
|
|
let handledBioToken = $state('');
|
|
let handledCommentToken = $state('');
|
|
const resultComposerId = $derived(String(form?.profileCommentParentId ?? '') || 'root');
|
|
const notificationIsIsac = (notification: any) =>
|
|
notification.category === 'isac' || String(notification.source).startsWith('ISAC');
|
|
|
|
const dateLabel = (value: string) => {
|
|
const date = new Date(value);
|
|
return Number.isNaN(date.valueOf())
|
|
? 'DATE UNKNOWN'
|
|
: date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' }).toUpperCase();
|
|
};
|
|
|
|
$effect(() => {
|
|
const token = String(form?.profileCommentResultToken ?? form?.commentResultToken ?? '');
|
|
if (!token || token === handledCommentToken) return;
|
|
handledCommentToken = token;
|
|
if (form?.profileCommentSaved || form?.commentSaved) {
|
|
profileCommentDraft = '';
|
|
activeComposerId = null;
|
|
}
|
|
if (form?.profileCommentDeleted || form?.commentDeleted) deletingCommentId = '';
|
|
if (form?.profileCommentFollowSaved) activeCommentMenuId = '';
|
|
});
|
|
|
|
$effect(() => {
|
|
if (!bioDraftInitialized) {
|
|
bioDraft = data.agent.bioMarkdown;
|
|
bioDraftInitialized = true;
|
|
}
|
|
const token = String(form?.bioResultToken ?? '');
|
|
if (!token || token === handledBioToken) return;
|
|
handledBioToken = token;
|
|
if (form?.bioSaved) {
|
|
bioDraft = String(form.bioMarkdown ?? bioDraft);
|
|
bioEditorOpen = false;
|
|
}
|
|
if (form?.bioError) bioEditorOpen = true;
|
|
});
|
|
|
|
$effect(() => {
|
|
if (form?.profileCommentError) activeComposerId = resultComposerId;
|
|
});
|
|
|
|
async function openComposer(id: string) {
|
|
activeComposerId = activeComposerId === id ? null : id;
|
|
profileCommentDraft = '';
|
|
deletingCommentId = '';
|
|
activeCommentMenuId = '';
|
|
if (!activeComposerId) return;
|
|
await tick();
|
|
document.getElementById(`profile-comment-editor-${activeComposerId}`)?.focus();
|
|
}
|
|
</script>
|
|
|
|
{#snippet commentComposer(parentId: string | null, label: string)}
|
|
<PendingForm action="?/commentProfile" class="profile-comment-form">
|
|
<input type="hidden" name="agentId" value={data.agent.id}/>
|
|
{#if parentId}<input type="hidden" name="parentId" value={parentId}/>{/if}
|
|
<CommentComposer
|
|
id={`profile-comment-editor-${parentId ?? 'root'}`}
|
|
name="body"
|
|
{label}
|
|
maxLength={2000}
|
|
rows={4}
|
|
required
|
|
bind:value={profileCommentDraft}
|
|
/>
|
|
<ModerationDisclosure compact/>
|
|
{#if resultComposerId === (parentId ?? 'root') && (form?.profileCommentError || form?.commentError)}
|
|
<p class="error">{form?.profileCommentError ?? form?.commentError}</p>
|
|
{/if}
|
|
<div class="profile-comment-form-actions">
|
|
<button type="button" class="secondary" onclick={() => openComposer(parentId ?? 'root')}>CANCEL</button>
|
|
<button class="primary" disabled={!profileCommentDraft.trim()}>
|
|
{parentId ? 'POST REPLY →' : 'POST MESSAGE →'}
|
|
</button>
|
|
</div>
|
|
</PendingForm>
|
|
{/snippet}
|
|
|
|
<svelte:head>
|
|
<title>{data.agent.displayName} — Agent Profile — SHD.build</title>
|
|
<meta name="description" content={`View ${data.agent.displayName}'s public Agent profile, builds, Guides, and community activity on SHD.build.`}/>
|
|
</svelte:head>
|
|
|
|
<main class="page public-agent-page">
|
|
<PageBreadcrumb items={[{ label: 'AGENTS' }, { label: data.agent.displayName }]} />
|
|
|
|
<header class="agent-command">
|
|
<div class="agent-command-identity">
|
|
<AgentIdentityLink agent={data.agent} size="large" roles={data.agent.roles} />
|
|
</div>
|
|
<div class="agent-command-actions">
|
|
{#if data.viewer.isSelf}
|
|
<PendingForm action="?/setProfileVisibility" toast={false} class="profile-visibility-form">
|
|
<input type="hidden" name="isPublic" value={data.agent.isPublic ? '0' : '1'}/>
|
|
<button class="visibility-toggle" class:enabled={data.agent.isPublic} role="switch" aria-checked={data.agent.isPublic} aria-label={`Public profile ${data.agent.isPublic ? 'enabled' : 'hidden'}. Toggle visibility.`}><span aria-hidden="true"></span><b>{data.agent.isPublic ? 'PUBLIC' : 'HIDDEN'}</b></button>
|
|
</PendingForm>
|
|
<InfoPopover label="About profile visibility" title="PROFILE VISIBILITY" text="A hidden profile leaves your name and avatar on public Builds, Guides, and comments, but removes the profile from discovery and blocks new profile messages."/>
|
|
<a class="mobile-account-jump" href="#account-control">ACCOUNT CONTROL ↓</a>
|
|
{:else if data.viewer.canReportProfile}
|
|
<ContentReport contentType="avatar" contentId={data.agent.id} label="REPORT AVATAR" result={form}/>
|
|
{/if}
|
|
</div>
|
|
</header>
|
|
|
|
<section class="agent-telemetry" aria-label="Agent content totals">
|
|
<div><span>PUBLIC BUILDS</span><strong>{data.counts.builds}</strong></div>
|
|
<div><span>PUBLISHED GUIDES</span><strong>{data.counts.guides}</strong></div>
|
|
<div><span>CONTENT COMMENTS</span><strong>{data.counts.authoredComments}</strong></div>
|
|
<div><span>PROFILE MESSAGES</span><strong>{data.counts.profileComments}</strong></div>
|
|
</section>
|
|
|
|
<div class="agent-profile-grid">
|
|
<div class="agent-main-column">
|
|
<div class="agent-primary">
|
|
<section class="profile-section agent-bio">
|
|
<header>
|
|
<div><p class="eyebrow">FIELD DOSSIER</p><h1>ABOUT {data.agent.displayName.toUpperCase()}</h1></div>
|
|
<div class="profile-header-actions">
|
|
{#if data.viewer.isSelf}
|
|
<button type="button" class="bio-edit-trigger" aria-expanded={bioEditorOpen} onclick={() => bioEditorOpen = !bioEditorOpen}>{bioEditorOpen ? 'CLOSE EDITOR' : 'EDIT BIO'}</button>
|
|
{:else}
|
|
<span>PUBLIC BIO</span>
|
|
{#if data.viewer.canReportProfile && data.agent.bioHtml}<ContentReport contentType="profile_bio" contentId={data.agent.id} label="REPORT BIO" result={form}/>{/if}
|
|
{/if}
|
|
</div>
|
|
</header>
|
|
{#if data.viewer.isSelf && data.agent.bioHidden}
|
|
<div class="profile-owner-notice error" role="status"><strong>BIO HIDDEN BY OVERSIGHT</strong><span>{data.agent.bioModerationReason ?? 'Review your notification inbox for details.'}</span></div>
|
|
{/if}
|
|
{#if data.viewer.isSelf && data.agent.bioReviewPending}
|
|
<div class="profile-owner-notice" role="status"><strong>BIO REVISION AWAITING REVIEW</strong><span>{data.agent.bioReviewReason ?? 'Your last approved biography remains public during review.'}</span></div>
|
|
{/if}
|
|
{#if form?.profileVisibilityError}<p class="error owner-profile-result">{form.profileVisibilityError}</p>{/if}
|
|
{#if form?.profileVisibilitySaved}<p class="success owner-profile-result">Profile visibility updated.</p>{/if}
|
|
{#if data.viewer.isSelf && bioEditorOpen}
|
|
<PendingForm action="?/saveBio" class="profile-bio-form">
|
|
<MarkdownEditor name="bio" label="AGENT BIO" help="Describe your playstyle, preferred roles, community work, or current objectives. Links are allowed." maxLength={4000} rows={12} bind:value={bioDraft}/>
|
|
<ModerationDisclosure/>
|
|
{#if form?.bioError}<p class="error">{form.bioError}</p>{/if}
|
|
<div class="profile-bio-actions"><button type="button" class="secondary" onclick={() => bioEditorOpen = false}>CANCEL</button><button class="primary">SAVE PUBLIC BIO →</button></div>
|
|
</PendingForm>
|
|
{:else}
|
|
<div class="bio-content">
|
|
<MarkdownContent html={data.agent.bioHtml} emptyMessage="This Agent has not published a field bio yet." />
|
|
</div>
|
|
{/if}
|
|
</section>
|
|
|
|
<div class="agent-published-grid">
|
|
<section class="profile-section">
|
|
<header><div><p class="eyebrow">LOADOUT ARCHIVE</p><h2>PUBLIC BUILDS</h2></div><span>{data.counts.builds} TOTAL</span></header>
|
|
<div class="public-content-grid">
|
|
{#each data.builds as build}
|
|
<a class="public-content-card" href={`/builds/${encodeURIComponent(build.slug)}`}><span>LOADOUT</span><h3>{build.title}</h3><p>Open this loadout to inspect its equipment, known Attributes, and active set bonuses.</p><footer><small>UPDATED {dateLabel(build.updatedAt)}</small><b>VIEW BUILD →</b></footer></a>
|
|
{:else}<div class="public-empty"><span>◇</span><strong>NO PUBLIC BUILDS</strong><p>This Agent has not shared a public loadout.</p></div>{/each}
|
|
</div>
|
|
</section>
|
|
<section class="profile-section">
|
|
<header><div><p class="eyebrow">FIELD GUIDANCE</p><h2>PUBLISHED GUIDES</h2></div><span>{data.counts.guides} TOTAL</span></header>
|
|
<div class="public-content-grid">
|
|
{#each data.guides as guide}<a class="public-content-card" href={`/guides/${encodeURIComponent(guide.slug)}`}><span>GUIDE</span><h3>{guide.title}</h3><p>Open this Guide for the complete strategy, embedded Builds, and field notes.</p><footer><small>UPDATED {dateLabel(guide.updatedAt)}</small><b>READ GUIDE →</b></footer></a>
|
|
{:else}<div class="public-empty"><span>◇</span><strong>NO PUBLISHED GUIDES</strong><p>This Agent has not published a Guide.</p></div>{/each}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
|
|
<section class="profile-comms" id="profile-comments">
|
|
<header class="profile-comms-heading">
|
|
<div><p class="eyebrow">AGENT COMMS</p><h2>PROFILE MESSAGES</h2></div>
|
|
<span>{data.counts.profileComments} {data.counts.profileComments === 1 ? 'MESSAGE' : 'MESSAGES'}</span>
|
|
</header>
|
|
|
|
{#if data.viewer.canComment}
|
|
<div class="profile-comment-start">
|
|
<button
|
|
type="button"
|
|
class="profile-comment-trigger"
|
|
aria-expanded={activeComposerId === 'root'}
|
|
aria-controls="profile-comment-composer-root"
|
|
onclick={() => openComposer('root')}
|
|
>{activeComposerId === 'root' ? 'CLOSE EDITOR' : 'LEAVE A MESSAGE'}</button>
|
|
</div>
|
|
{#if activeComposerId === 'root'}
|
|
<div id="profile-comment-composer-root">{@render commentComposer(null, 'NEW PROFILE MESSAGE')}</div>
|
|
{/if}
|
|
{:else if !data.viewer.id}
|
|
<div class="comment-access-note"><strong>SIGN-IN REQUIRED</strong><p>Sign in to leave a message on this Agent profile.</p><a class="secondary" href="/sign-in">SIGN IN →</a></div>
|
|
{:else}
|
|
<div class="comment-access-note"><strong>MESSAGING UNAVAILABLE</strong><p>Your account cannot post profile messages at this time.</p></div>
|
|
{/if}
|
|
|
|
<div class="profile-comment-list">
|
|
{#each data.profileComments as comment}
|
|
<article
|
|
id={`profile-comment-${comment.id}`}
|
|
class="profile-comment"
|
|
class:reply={comment.depth > 0}
|
|
class:removed={comment.status === 'removed'}
|
|
style={`--thread-depth:${Math.min(comment.depth, 4)}`}
|
|
>
|
|
{#if comment.status === 'visible'}
|
|
<header>
|
|
<AgentIdentityLink agent={comment.author} roles={comment.author.roles} meta={dateLabel(comment.createdAt)} />
|
|
{#if comment.isPinned}<b class="pinned-comment-label">PINNED COMMENT</b>{/if}
|
|
</header>
|
|
<MarkdownContent html={comment.bodyHtml} compact />
|
|
<div class="comment-actions">
|
|
{#if data.viewer.canComment}
|
|
<button
|
|
type="button"
|
|
class="comment-reply"
|
|
aria-expanded={activeComposerId === comment.id}
|
|
aria-controls={`profile-comment-composer-${comment.id}`}
|
|
onclick={() => openComposer(comment.id)}
|
|
>REPLY</button>
|
|
{/if}
|
|
{#if data.viewer.id}
|
|
<OverflowMenu label={`Actions for ${comment.author.displayName}'s message`} bind:open={() => activeCommentMenuId === comment.id, (open) => activeCommentMenuId = open ? comment.id : ''}>
|
|
{#snippet children(close)}
|
|
<PendingForm action="?/toggleProfileCommentFollow" successMessage={comment.isFollowing ? 'Conversation unfollowed.' : 'Conversation followed.'}>
|
|
<input type="hidden" name="commentId" value={comment.id}/>
|
|
<input type="hidden" name="intent" value={comment.isFollowing ? 'unfollow' : 'follow'}/>
|
|
<button>{comment.isFollowing ? 'UNFOLLOW THREAD' : 'FOLLOW THREAD'}</button>
|
|
</PendingForm>
|
|
{#if comment.canReport}<ContentReport contentType="comment" contentId={comment.id} result={form} plain menuItem/>{/if}
|
|
{#if data.viewer.isSelf && comment.depth === 0}
|
|
<PendingForm action="?/setPinnedProfileComment">
|
|
<input type="hidden" name="commentId" value={comment.id}/>
|
|
<input type="hidden" name="intent" value={comment.isPinned ? 'unpin' : 'pin'}/>
|
|
<button>{comment.isPinned ? 'UNPIN COMMENT' : 'PIN COMMENT'}</button>
|
|
</PendingForm>
|
|
{/if}
|
|
{#if comment.canDelete}
|
|
<button type="button" class="comment-remove danger" onclick={() => { deletingCommentId = comment.id; close(); }}>REMOVE MESSAGE</button>
|
|
{/if}
|
|
{/snippet}
|
|
</OverflowMenu>
|
|
{/if}
|
|
</div>
|
|
{:else}
|
|
<div class="removed-message">
|
|
<strong>{comment.removalReason === 'Removed by Community Oversight' ? 'MESSAGE REMOVED BY COMMUNITY OVERSIGHT' : 'MESSAGE REMOVED BY POSTER'}</strong>
|
|
<span>Replies remain visible to preserve the conversation.</span>
|
|
</div>
|
|
{/if}
|
|
{#if activeComposerId === comment.id}
|
|
<div id={`profile-comment-composer-${comment.id}`} class="reply-composer">
|
|
{@render commentComposer(comment.id, `REPLY TO ${comment.author.displayName.toUpperCase()}`)}
|
|
</div>
|
|
{/if}
|
|
{#if deletingCommentId === comment.id}
|
|
<div class="comment-delete-confirm" role="alert">
|
|
<p>Remove this message? It remains as a labeled placeholder only when replies depend on it.</p>
|
|
<div>
|
|
<button type="button" class="secondary" onclick={() => deletingCommentId = ''}>CANCEL</button>
|
|
<PendingForm action="?/deleteProfileComment">
|
|
<input type="hidden" name="commentId" value={comment.id}/>
|
|
<button class="primary">CONFIRM REMOVE</button>
|
|
</PendingForm>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
</article>
|
|
{:else}
|
|
<div class="public-empty compact">
|
|
<span>◇</span><strong>NO PROFILE MESSAGES</strong>
|
|
<p>Be the first Agent to leave a useful field message.</p>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<aside class="agent-activity">
|
|
{#if data.viewer.isSelf && data.accountControl}
|
|
<div id="account-control"><AccountControl account={data.accountControl} displayName={data.agent.displayName} avatarUrl={data.agent.avatarUrl}/></div>
|
|
<section class="profile-section owner-notifications">
|
|
<header><div><p class="eyebrow">SHD COMMUNICATION NETWORK</p><h2>NOTIFICATIONS</h2></div><a href="/account/notifications">{data.accountControl.notificationUnread ? `${data.accountControl.notificationUnread} UNREAD` : 'VIEW INBOX'} →</a></header>
|
|
<div class="owner-notification-list">
|
|
{#each data.accountControl.notifications as notification}
|
|
<a class:unread={!notification.read_at} class:isac={notificationIsIsac(notification)} href="/account/notifications"><span><b>{notification.source}</b><small>{String(notification.category).toUpperCase()} · {dateLabel(String(notification.created_at))}</small></span><strong>{notification.title}</strong></a>
|
|
{:else}<div class="public-empty compact"><strong>INBOX CLEAR</strong><p>No unread notifications.</p></div>{/each}
|
|
</div>
|
|
</section>
|
|
{/if}
|
|
<section class="profile-section discussion-section">
|
|
<header><div><p class="eyebrow">COMMUNITY RECORD</p><h2>RECENT DISCUSSION</h2></div><span>{data.counts.authoredComments} COMMENTS</span></header>
|
|
<div class="authored-comment-list">
|
|
{#each data.authoredComments as comment}
|
|
<article>
|
|
<header><div><span>{comment.targetType.toUpperCase()}</span><strong>{comment.targetTitle}</strong></div><small>{dateLabel(comment.createdAt)}</small></header>
|
|
<a href={comment.targetHref}>OPEN DISCUSSION →</a>
|
|
</article>
|
|
{:else}
|
|
<div class="public-empty">
|
|
<span>◇</span><strong>NO PUBLIC DISCUSSION</strong>
|
|
<p>Comments this Agent leaves on builds will appear here.</p>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
</section>
|
|
</aside>
|
|
</div>
|
|
</main>
|
|
|
|
<style>
|
|
.public-agent-page{padding-top:28px}.agent-command{position:static;z-index:auto;width:auto;height:auto;min-height:96px;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--shd-gap-lg);margin-top:12px;padding:14px 4px 16px;border:0;background:transparent}
|
|
.agent-command-identity{min-width:0}.agent-command :global(.agent-profile-identity){min-width:0}.agent-command-actions{display:flex;align-items:center;gap:8px}.agent-command-actions :global(.profile-visibility-form){margin:0}.agent-command-actions .visibility-toggle{min-height:40px}.mobile-account-jump{display:none}
|
|
.agent-telemetry{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin-top:8px;border:1px solid var(--shd-border);background:var(--shd-surface)}
|
|
.agent-telemetry>div{display:grid;gap:4px;padding:10px 12px;border-left:1px solid var(--shd-border)}.agent-telemetry>div:first-child{border-left:0}.agent-telemetry span{color:var(--shd-text-muted);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.8px}.agent-telemetry strong{color:var(--shd-orange);font-size:24px}
|
|
.agent-profile-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(360px,.42fr);align-items:start;gap:10px;margin-top:10px}.agent-main-column,.agent-primary,.agent-activity{display:grid;gap:10px;min-width:0}.agent-main-column{grid-column:1}.agent-activity{position:sticky;top:88px;grid-column:2}.agent-activity .public-empty{min-height:110px}#account-control{scroll-margin-top:88px}.agent-published-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.agent-published-grid .public-content-grid{grid-template-columns:1fr}
|
|
.profile-section{min-width:0;border:1px solid var(--shd-border);background:var(--shd-surface)}.profile-section>header{min-height:54px;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 12px;border-bottom:1px solid var(--shd-border);background:var(--shd-surface-raised)}.profile-section>header>div{display:grid;gap:2px}.profile-section>header :is(h1,h2,p){margin:0}.profile-section>header h1,.profile-section>header h2{font-size:var(--shd-type-body);letter-spacing:.4px}.profile-section>header>span{color:var(--shd-text-muted);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.8px}
|
|
.bio-content{min-height:110px;padding:18px}:global(form.profile-bio-form){display:grid;gap:10px;padding:16px}.profile-bio-actions{display:flex;justify-content:flex-end;gap:7px}.profile-bio-actions button{min-height:40px}.profile-owner-notice{display:grid;gap:4px;margin:12px 16px 0;padding:10px;border:1px solid #745b2b;background:#1c170e;color:var(--shd-text-muted);font-size:var(--shd-type-supporting)}.profile-owner-notice strong{color:var(--shd-orange);font-size:var(--shd-type-telemetry);letter-spacing:.7px}.profile-owner-notice.error{border-color:#70423b;background:#211414}.profile-owner-notice.error strong{color:var(--shd-danger)}.owner-profile-result{margin:10px 16px 0}.public-content-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px;padding:7px}
|
|
.public-content-card{min-width:0;display:grid;grid-template-rows:auto auto minmax(48px,1fr) auto;gap:6px;padding:12px;border:1px solid var(--shd-border);border-left:2px solid var(--shd-orange);background:#0d1011;color:var(--shd-text)}.public-content-card>span,.public-content-card footer{font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.7px}.public-content-card>span{color:var(--shd-orange)}.public-content-card h3,.public-content-card p{margin:0}.public-content-card h3{font-size:1.05rem}.public-content-card p{color:var(--shd-text-muted);font-family:var(--shd-font-editorial);font-size:var(--shd-type-supporting);line-height:1.45}.public-content-card footer{display:flex;justify-content:space-between;gap:8px;padding-top:8px;border-top:1px solid var(--shd-border-soft)}.public-content-card small{color:var(--shd-text-dim)}.public-content-card b{color:var(--shd-orange)}.public-content-card:hover,.public-content-card:focus-visible{border-color:var(--shd-orange);background:var(--shd-surface-active)}
|
|
.public-empty{grid-column:1/-1;min-height:150px;display:grid;place-content:center;gap:6px;padding:20px;text-align:center}.public-empty span{color:var(--shd-orange);font-size:28px}.public-empty strong{font-size:var(--shd-type-telemetry);letter-spacing:1px}.public-empty p{margin:0;color:var(--shd-text-muted);font-family:var(--shd-font-editorial);font-size:var(--shd-type-supporting)}.public-empty.compact{min-height:110px}
|
|
.authored-comment-list{display:grid;gap:7px;padding:7px}.authored-comment-list>article{display:grid;gap:10px;padding:11px;border:1px solid var(--shd-border);background:#0d1011}.authored-comment-list article>header{position:static;z-index:auto;width:auto;height:auto;min-height:0;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:10px;padding:0;border:0;background:transparent}.authored-comment-list article>header>div{min-width:0;display:grid;align-content:center;gap:2px}.authored-comment-list article header span,.authored-comment-list article header small,.authored-comment-list article>a{font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.7px}.authored-comment-list article header span,.authored-comment-list article>a{color:var(--shd-orange)}.authored-comment-list article header small{align-self:center;color:var(--shd-text-muted);text-align:right;white-space:nowrap}.authored-comment-list article>a{justify-self:end}
|
|
.profile-comms{margin-top:16px;padding:0;background:transparent}.profile-comms-heading{position:static;z-index:auto;width:auto;height:auto;min-height:0;display:flex;align-items:end;justify-content:space-between;gap:16px;padding:0 0 12px;border:0;border-bottom:1px solid var(--shd-border);background:transparent}.profile-comms-heading>div{display:grid;gap:3px}.profile-comms-heading :is(h2,p){margin:0}.profile-comms-heading h2{font-size:1.25rem}.profile-comms-heading>span{color:var(--shd-text-dim);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.7px}.profile-comment-start{width:min(920px,100%);padding-top:16px}.profile-comment-trigger{width:100%;min-height:48px;padding:0 14px;border:1px solid var(--shd-border-strong);background:transparent;color:var(--shd-text-muted);font-family:var(--shd-font-editorial);font-size:var(--shd-type-body);text-align:left;cursor:pointer}.profile-comment-trigger:hover,.profile-comment-trigger:focus-visible,.profile-comment-trigger[aria-expanded=true]{border-color:var(--shd-orange);color:var(--shd-text);background:var(--shd-surface-active)}:global(form.profile-comment-form){width:min(920px,100%);display:grid;gap:9px;padding:14px 0 0;border:0;background:transparent}.profile-comment-form-actions{display:flex;justify-content:flex-end;gap:7px}.profile-comment-form-actions button{min-height:38px}.profile-comment-list{width:min(980px,100%);display:grid;margin-top:26px;overflow:visible}.profile-comment-list>article{--thread-depth:0;position:relative;display:grid;gap:8px;margin:18px 0 0 calc(var(--thread-depth) * 22px);padding:0;scroll-margin-top:96px;background:transparent}.profile-comment-list>article:target{outline:1px solid var(--shd-orange);outline-offset:8px}.profile-comment-list>article.reply{padding-left:14px;border-left:1px solid var(--shd-border-strong)}.profile-comment-list article>header{position:static;z-index:auto;width:auto;height:auto;min-height:0;display:flex;align-items:center;justify-content:flex-start;gap:12px;padding:0;border:0;background:transparent}.profile-comment-list article>header :global(.agent-identity){flex:0 1 auto}.profile-comment-list article :global(.markdown-content){max-width:75ch;margin-left:47px}.comment-actions{display:flex;align-items:center;gap:14px;min-height:32px;margin-left:47px}.comment-reply{min-height:32px;padding:0;border:0;background:transparent;color:var(--shd-text-muted);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.6px;cursor:pointer}.comment-reply:hover,.comment-reply:focus-visible,.comment-reply[aria-expanded=true]{color:var(--shd-orange);text-decoration:underline;text-underline-offset:3px}.reply-composer{margin:6px 0 0 47px}.reply-composer :global(form.profile-comment-form){padding-top:0}.removed-message{display:grid;gap:3px;padding:4px 0}.removed-message strong{color:var(--shd-text-dim);font-size:var(--shd-type-telemetry);letter-spacing:.8px}.removed-message span{color:var(--shd-text-dim);font-size:var(--shd-type-supporting);font-style:italic}.comment-delete-confirm{width:min(520px,calc(100% - 47px));display:grid;gap:8px;margin-left:47px;padding:10px;border:1px solid var(--shd-danger);background:#1b1111}.comment-delete-confirm p{margin:0;color:var(--shd-text-muted);font-size:var(--shd-type-supporting)}.comment-delete-confirm>div{display:flex;justify-content:flex-end;gap:7px}.comment-delete-confirm button{min-height:38px;padding:0 10px}.comment-access-note{width:min(920px,100%);display:grid;gap:7px;padding:16px 0 0}.comment-access-note strong{color:var(--shd-orange);font-size:var(--shd-type-telemetry);letter-spacing:.8px}.comment-access-note p{margin:0;color:var(--shd-text-muted);font-size:var(--shd-type-supporting)}.comment-access-note a{justify-self:start}.profile-comms .public-empty{min-height:100px;place-content:start;padding:24px 0;text-align:left}.profile-comms .public-empty span{display:none}
|
|
.profile-header-actions{display:flex;align-items:center;gap:7px}.profile-header-actions>span{color:var(--shd-text-muted);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.7px}.bio-edit-trigger{min-height:32px;padding:0 9px;border:1px solid var(--shd-border);background:transparent;color:var(--shd-orange);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.7px;cursor:pointer}.bio-edit-trigger:hover,.bio-edit-trigger:focus-visible,.bio-edit-trigger[aria-expanded=true]{border-color:var(--shd-orange);background:var(--shd-surface-active)}.visibility-toggle{min-height:32px;display:flex;align-items:center;gap:7px;padding:0 8px;border:1px solid var(--shd-border-strong);background:#0d1011;color:var(--shd-text-muted);cursor:pointer}.visibility-toggle>span{position:relative;width:26px;height:14px;border:1px solid var(--shd-border-strong);background:#070909}.visibility-toggle>span::after{content:"";position:absolute;top:2px;left:2px;width:8px;height:8px;background:var(--shd-text-dim)}.visibility-toggle.enabled{border-color:#6b5128;color:var(--shd-orange)}.visibility-toggle.enabled>span::after{left:14px;background:var(--shd-orange)}.visibility-toggle b{font-size:var(--shd-type-telemetry);letter-spacing:.7px}.owner-notifications>header>a{color:var(--shd-orange);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.6px}.owner-notification-list{display:grid}.owner-notification-list>a{min-width:0;display:grid;gap:5px;padding:9px 10px;border-top:1px solid var(--shd-border);background:#0d1011;color:var(--shd-text-muted)}.owner-notification-list>a:first-child{border-top:0}.owner-notification-list>a.unread{box-shadow:inset 2px 0 var(--shd-orange)}.owner-notification-list>a.isac{box-shadow:inset 2px 0 var(--shd-info)}.owner-notification-list span{min-width:0;display:flex;justify-content:space-between;gap:8px}.owner-notification-list b,.owner-notification-list small{font-size:var(--shd-type-telemetry);letter-spacing:.5px}.owner-notification-list b{overflow:hidden;color:var(--shd-orange);text-overflow:ellipsis;white-space:nowrap}.owner-notification-list small{color:var(--shd-text-dim);white-space:nowrap}.owner-notification-list strong{overflow:hidden;font-size:var(--shd-type-supporting);text-overflow:ellipsis;white-space:nowrap}
|
|
.profile-comment-list article :global(.markdown-content),.comment-actions{margin-left:53px}.reply-composer{margin-left:53px}.comment-delete-confirm{width:min(520px,calc(100% - 53px));margin-left:53px}
|
|
.pinned-comment-label{margin-left:auto;color:var(--shd-orange);font-size:var(--shd-type-telemetry);letter-spacing:.7px}
|
|
@media(max-width:1000px){.agent-profile-grid{grid-template-columns:1fr}.agent-main-column{grid-column:1}.agent-activity{position:static;grid-column:1;grid-template-columns:repeat(2,minmax(0,1fr))}.agent-activity .profile-section:last-child{grid-column:1/-1}.agent-telemetry{grid-template-columns:repeat(2,minmax(0,1fr))}.agent-telemetry>div:nth-child(3){border-left:0}.agent-telemetry>div:nth-child(n+3){border-top:1px solid var(--shd-border)}}
|
|
@media(max-width:650px){.agent-command{grid-template-columns:1fr;align-items:stretch}.agent-command-actions{width:100%;display:grid;grid-template-columns:minmax(0,1fr) auto}.agent-command-actions :global(.profile-visibility-form),.agent-command-actions .visibility-toggle{width:100%}.agent-command-actions .visibility-toggle{min-height:44px;justify-content:center}.agent-command-actions :global(.content-report){grid-column:1/-1}.agent-command-actions :global(.content-report summary){width:100%;justify-content:center}.mobile-account-jump{grid-column:1/-1;min-height:44px;display:flex;align-items:center;justify-content:center;border:1px solid var(--shd-border-strong);color:var(--shd-text-muted);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.7px}.mobile-account-jump:hover,.mobile-account-jump:focus-visible{border-color:var(--shd-orange);color:var(--shd-orange);background:var(--shd-surface-active)}.agent-main-column{display:contents}.agent-primary{grid-column:1;grid-row:1}.agent-activity{grid-column:1;grid-row:2;grid-template-columns:1fr}.profile-comms{grid-column:1;grid-row:3;margin-top:16px}.agent-activity .profile-section:last-child{grid-column:auto}.agent-published-grid{grid-template-columns:1fr}.public-content-grid{grid-template-columns:1fr}.profile-section>header,.profile-comms-heading{align-items:flex-start;flex-direction:column}.agent-bio>header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start}.agent-bio .profile-header-actions{width:auto}.bio-edit-trigger{min-height:44px;padding:0 5px;border-color:transparent}.bio-edit-trigger:hover,.bio-edit-trigger:focus-visible,.bio-edit-trigger[aria-expanded=true]{border-color:var(--shd-border-strong)}.profile-bio-actions{display:grid;grid-template-columns:1fr 1fr}.profile-bio-actions button{min-height:44px}.profile-comment-trigger,.profile-comment-form-actions button,.comment-reply,.comment-delete-confirm button{min-height:44px}.profile-comment-form-actions{display:grid;grid-template-columns:1fr 1fr}.profile-comment-list>article{margin-left:calc(var(--thread-depth) * 12px)}.comment-delete-confirm>div{display:grid;grid-template-columns:1fr 1fr}}
|
|
@media(prefers-reduced-motion:reduce){.public-content-card,.profile-comment-trigger,.comment-reply{transition:none}}
|
|
</style>
|