523 lines
11 KiB
CSS
523 lines
11 KiB
CSS
/* ============================================================
|
|
cool-people.css — the /cool-people page. Friend cards are
|
|
built from the shared .presence-card (see shared/presence-
|
|
card.css) — this file only adds the .is-mini sizing + tier
|
|
heart variants used here.
|
|
============================================================ */
|
|
|
|
/* ============================================================
|
|
13. Friends Page
|
|
============================================================ */
|
|
|
|
body:has(.friend-grid) .hub-header {
|
|
position: relative;
|
|
z-index: 1;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.friend-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
/* flex-wrap centres EVERY row, including a partial last row (a lone card
|
|
sits centred rather than stuck to the left as it did with CSS grid) */
|
|
justify-content: center;
|
|
align-items: flex-start;
|
|
margin-bottom: 1.5rem;
|
|
gap: 1.1rem;
|
|
width: 100%;
|
|
}
|
|
|
|
/* allow the cool-people page to scroll even before friends.js injects the
|
|
.friend-grid elements that the :has() rule keys on */
|
|
html:has(.friends-wrap),
|
|
body:has(.friends-wrap) {
|
|
height: auto;
|
|
min-height: 100dvh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
body:has(.friends-wrap) {
|
|
align-items: flex-start;
|
|
}
|
|
|
|
body:has(.friends-wrap) .hub {
|
|
max-width: 960px;
|
|
}
|
|
|
|
#friends-root {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2rem;
|
|
padding-bottom: 4.5rem;
|
|
}
|
|
|
|
/* ---- Lanyard friend cards ---- */
|
|
.friend-card {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 210px;
|
|
border-radius: 14px;
|
|
background: var(--surface-0);
|
|
border: 1px solid var(--surface-1);
|
|
overflow: hidden;
|
|
transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
|
|
}
|
|
|
|
.friend-card:hover {
|
|
transform: translateY(-3px);
|
|
border-color: rgb(var(--accent-rgb));
|
|
box-shadow: 0 8px 22px -12px rgba(var(--accent-rgb), 0.5);
|
|
}
|
|
|
|
/* Nitro profile gradient — recolours the card body (mirrors the /discord card) */
|
|
.friend-card.has-profile-grad {
|
|
background: linear-gradient(180deg, rgb(var(--fc-grad-1-rgb)) 0%, rgb(var(--fc-grad-2-rgb)) 100%);
|
|
border-color: rgba(var(--fc-grad-1-rgb), 0.6);
|
|
}
|
|
|
|
/* Hovered card lifts above its neighbours and lets its text un-truncate so
|
|
long names / usernames / custom statuses expand in full instead of being
|
|
chopped off with an ellipsis. The body becomes an absolutely-positioned
|
|
overlay, so the card grows DOWNWARD without resizing its grid slot —
|
|
neighbouring cards stay exactly where they are. */
|
|
/* Expansion is gated on .is-hovering (added by JS) rather than :hover so the
|
|
card's flow height can be pinned BEFORE .fc-main is taken out of flow —
|
|
otherwise the card collapses, the page reflows, and hover ping-pongs
|
|
(the "vibrating page" bug). */
|
|
.friend-card.is-hovering {
|
|
overflow: visible;
|
|
z-index: 5;
|
|
}
|
|
|
|
.friend-card.is-hovering .fc-main {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
top: 54px;
|
|
/* sit directly under the banner strip */
|
|
background: inherit;
|
|
/* carry the card surface / Nitro gradient */
|
|
border-bottom-left-radius: 14px;
|
|
border-bottom-right-radius: 14px;
|
|
box-shadow: 0 10px 24px -14px rgba(17, 17, 27, 0.8);
|
|
}
|
|
|
|
.friend-card.is-hovering .fc-name,
|
|
.friend-card.is-hovering .fc-user,
|
|
.friend-card.is-hovering .fc-custom-text {
|
|
white-space: normal;
|
|
overflow: visible;
|
|
text-overflow: clip;
|
|
overflow-wrap: anywhere;
|
|
/* break long unbroken usernames / handles */
|
|
}
|
|
|
|
/* banner strip — Nitro banner image / accent colour / default wash */
|
|
.fc-banner {
|
|
height: 54px;
|
|
background:
|
|
linear-gradient(135deg, rgba(var(--accent-rgb), 0.45), rgba(var(--accent-rgb), 0.12));
|
|
background-size: cover;
|
|
background-position: center;
|
|
/* keep the banner corners rounded even on hover, when the card switches
|
|
to overflow:visible and no longer clips them to the card radius */
|
|
border-top-left-radius: 14px;
|
|
border-top-right-radius: 14px;
|
|
}
|
|
|
|
.friend-card.has-banner .fc-banner {
|
|
background-size: cover;
|
|
background-position: center;
|
|
}
|
|
|
|
.fc-main {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 0.7rem;
|
|
padding: 0.6rem 0.85rem 0.85rem;
|
|
}
|
|
|
|
.fc-avatar {
|
|
position: relative;
|
|
flex-shrink: 0;
|
|
width: 56px;
|
|
height: 56px;
|
|
margin-top: -30px;
|
|
}
|
|
|
|
.fc-pfp {
|
|
width: 56px;
|
|
height: 56px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
border: 3px solid var(--surface-0);
|
|
background: var(--surface-0);
|
|
display: block;
|
|
}
|
|
|
|
/* avatar decoration / frame overlay (Discord cosmetic) */
|
|
.fc-deco {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 76px;
|
|
height: 76px;
|
|
transform: translate(-50%, -50%);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.fc-deco[hidden] {
|
|
display: none;
|
|
}
|
|
|
|
/* status dot — colour driven by data-status on the card */
|
|
.fc-status {
|
|
position: absolute;
|
|
right: -1px;
|
|
bottom: -1px;
|
|
width: 15px;
|
|
height: 15px;
|
|
border-radius: 50%;
|
|
border: 3px solid var(--surface-0);
|
|
background: var(--blue);
|
|
}
|
|
|
|
.friend-card[data-status="online"] .fc-status {
|
|
background: var(--green);
|
|
}
|
|
|
|
.friend-card[data-status="idle"] .fc-status {
|
|
background: var(--yellow);
|
|
}
|
|
|
|
.friend-card[data-status="dnd"] .fc-status {
|
|
background: var(--red);
|
|
}
|
|
|
|
.friend-card[data-status="offline"] .fc-status {
|
|
background: var(--overlay-0);
|
|
}
|
|
|
|
.friend-card[data-status="unconnected"] .fc-status {
|
|
background: var(--blue);
|
|
}
|
|
|
|
.fc-id {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.15rem;
|
|
min-width: 0;
|
|
padding-top: 0.1rem;
|
|
}
|
|
|
|
.fc-name-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 0.15rem 0.3rem;
|
|
min-width: 0;
|
|
}
|
|
|
|
/* name claims the full first line (so a clan tag never truncates it); the
|
|
tag chip wraps onto its own line just beneath when there isn't room */
|
|
.fc-name-row .fc-name {
|
|
flex: 1 1 100%;
|
|
min-width: 0;
|
|
}
|
|
|
|
/* Discord server (clan) tag chip */
|
|
.fc-tag {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.15rem;
|
|
flex-shrink: 0;
|
|
padding: 0.05rem 0.3rem;
|
|
border-radius: 5px;
|
|
background: var(--surface-2);
|
|
font-size: 0.56rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.02em;
|
|
color: var(--text);
|
|
}
|
|
|
|
.fc-tag[hidden] {
|
|
display: none;
|
|
}
|
|
|
|
.fc-tag-badge {
|
|
width: 12px;
|
|
height: 12px;
|
|
display: block;
|
|
}
|
|
|
|
.fc-name {
|
|
font-size: 0.95rem;
|
|
font-weight: 700;
|
|
color: var(--text);
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
a.fc-name:hover {
|
|
color: rgb(var(--accent-rgb));
|
|
}
|
|
|
|
/* Nitro display-name gradient (clipped to the text). Keep the tier heart in
|
|
::before painted normally so it stays its solid colour. */
|
|
.fc-name.is-gradient {
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
color: transparent;
|
|
-webkit-text-fill-color: transparent;
|
|
}
|
|
|
|
.fc-name.is-gradient::before {
|
|
-webkit-text-fill-color: initial;
|
|
color: var(--text);
|
|
}
|
|
|
|
/* tier hearts (match the old friend-name prefixes) */
|
|
.fc-name::before {
|
|
content: "🩵 ";
|
|
}
|
|
|
|
.fc-name.known::before {
|
|
content: "💛 ";
|
|
}
|
|
|
|
.fc-name.wife::before {
|
|
content: "🖤 ";
|
|
}
|
|
|
|
.fc-name.close::before {
|
|
content: "🤍 ";
|
|
}
|
|
|
|
.fc-user {
|
|
font-size: 0.72rem;
|
|
color: var(--subtext-0);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.fc-user:empty {
|
|
display: none;
|
|
}
|
|
|
|
/* custom status (Discord activity type 4) */
|
|
.fc-custom {
|
|
position: relative;
|
|
align-self: flex-start;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.3rem;
|
|
max-width: 100%;
|
|
font-size: 0.72rem;
|
|
color: var(--subtext-1);
|
|
margin-top: 0.45rem;
|
|
min-width: 0;
|
|
padding: 0.3rem 0.5rem;
|
|
background: var(--surface-1);
|
|
border-radius: 11px;
|
|
border-top-left-radius: 4px;
|
|
}
|
|
|
|
/* Discord-style thought-bubble tail: two little circles rising to the name */
|
|
.fc-custom::before,
|
|
.fc-custom::after {
|
|
content: "";
|
|
position: absolute;
|
|
background: var(--surface-1);
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.fc-custom::before {
|
|
width: 7px;
|
|
height: 7px;
|
|
top: -4px;
|
|
left: 9px;
|
|
}
|
|
|
|
.fc-custom::after {
|
|
width: 4px;
|
|
height: 4px;
|
|
top: -8px;
|
|
left: 7px;
|
|
}
|
|
|
|
.fc-custom[hidden] {
|
|
display: none;
|
|
}
|
|
|
|
.fc-custom-emoji {
|
|
width: 14px;
|
|
height: 14px;
|
|
display: block;
|
|
flex: none;
|
|
}
|
|
|
|
.fc-custom-emoji-uni {
|
|
font-size: 0.8rem;
|
|
line-height: 1;
|
|
flex: none;
|
|
}
|
|
|
|
.fc-custom-text {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.fc-badges {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 0.2rem;
|
|
margin-top: 0.1rem;
|
|
}
|
|
|
|
.fc-badges:empty {
|
|
display: none;
|
|
}
|
|
|
|
.fc-badge {
|
|
width: 16px;
|
|
height: 16px;
|
|
display: block;
|
|
}
|
|
|
|
.fc-badge-link {
|
|
display: inline-flex;
|
|
line-height: 0;
|
|
}
|
|
|
|
/* ---- Alts (active + dead) ---- */
|
|
.fc-name.active-alt::before {
|
|
content: "🎭 ";
|
|
}
|
|
|
|
.fc-name.dead-alt::before {
|
|
content: "💀 ";
|
|
}
|
|
|
|
/* dead alts: banned accounts — greyed out, name struck through, no status */
|
|
.friend-card.tier-dead-alt .fc-pfp {
|
|
filter: grayscale(1) brightness(0.6);
|
|
}
|
|
|
|
.friend-card.tier-dead-alt .fc-name {
|
|
color: var(--overlay-1);
|
|
text-decoration: line-through;
|
|
}
|
|
|
|
.friend-card.tier-dead-alt .fc-status {
|
|
display: none;
|
|
}
|
|
|
|
/* the "struck off" diagonal slash across the avatar */
|
|
.friend-card.tier-dead-alt .fc-avatar::after {
|
|
content: "";
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
width: 132%;
|
|
height: 4px;
|
|
background: var(--red);
|
|
border-radius: 2px;
|
|
transform: translate(-50%, -50%) rotate(-45deg);
|
|
box-shadow: 0 0 0 2px var(--surface-0);
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* ============================================================
|
|
15. Cool-people friend cards — mini presence cards
|
|
Each friend is a full presence card (built by discord.js's
|
|
PresenceCard factory) but smaller than the big /discord one.
|
|
The BASE .presence-card is already compact (≈280px); we just
|
|
un-fix it from the corner so the cards tile in .friend-grid,
|
|
and re-add the tier hearts / dead-alt treatment on pc-* markup.
|
|
============================================================ */
|
|
.presence-card.is-mini {
|
|
position: static;
|
|
top: auto;
|
|
left: auto;
|
|
right: auto;
|
|
bottom: auto;
|
|
z-index: auto;
|
|
margin: 0;
|
|
width: 300px;
|
|
/* clearly smaller than the 680px /discord card */
|
|
max-width: 100%;
|
|
}
|
|
|
|
/* keep things tidy at the small size */
|
|
.presence-card.is-mini .pc-banner {
|
|
height: 84px;
|
|
}
|
|
|
|
.presence-card.is-mini .pc-bio {
|
|
max-height: 6.5em;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/* the friend name can open a personal site */
|
|
.presence-card.is-mini .pc-name--link {
|
|
text-decoration: none;
|
|
}
|
|
|
|
.presence-card.is-mini .pc-name--link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* ---- tier hearts (ported from the old .fc-name prefixes) ---- */
|
|
.presence-card.is-mini .pc-name::before {
|
|
content: "🩵 ";
|
|
}
|
|
|
|
.presence-card.is-mini.tier-known .pc-name::before {
|
|
content: "💛 ";
|
|
}
|
|
|
|
.presence-card.is-mini.tier-wife .pc-name::before {
|
|
content: "🖤 ";
|
|
}
|
|
|
|
.presence-card.is-mini.tier-close .pc-name::before {
|
|
content: "🤍 ";
|
|
}
|
|
|
|
.presence-card.is-mini.tier-active-alt .pc-name::before {
|
|
content: "🎭 ";
|
|
}
|
|
|
|
.presence-card.is-mini.tier-dead-alt .pc-name::before {
|
|
content: "💀 ";
|
|
}
|
|
|
|
/* gradient names clip text to transparent — keep the heart visible */
|
|
.presence-card.is-mini .pc-name.is-gradient::before {
|
|
-webkit-text-fill-color: initial;
|
|
color: var(--text);
|
|
}
|
|
|
|
/* ---- dead alts: greyed, struck through, no live status ---- */
|
|
.presence-card.is-mini.tier-dead-alt .pc-av-img {
|
|
filter: grayscale(1) brightness(0.6);
|
|
}
|
|
|
|
.presence-card.is-mini.tier-dead-alt .pc-name {
|
|
color: var(--overlay-1);
|
|
text-decoration: line-through;
|
|
}
|
|
|
|
.presence-card.is-mini.tier-dead-alt .pc-status {
|
|
display: none;
|
|
}
|
|
|
|
|