/* ============================================================ main.css — single stylesheet for clove.is-a.dev Merged from style.css + discord-styles.css Sections: 1. Base & reset (all pages) 2. Shared layout & header (all pages) 3. Link hub (index page) 4. Now-playing widget (shared, top-left) 5. Page nav (shared, bottom-left) 6. System badges (shared, bottom-right) 7. Theme switcher (shared, top-right) 8. dev-info page 9. Changelog page 10. Secret cat modes (toast + picker modal) 11. Discord bots page 12. Responsive overrides 13. Friends Page ============================================================ */ @import url(/css/fonts.css); @import url(/css/themes/frappe.css); @import url(/css/themes/latte.css); @import url(/css/themes/mocha.css); @import url(/css/themes/macchiato.css); @import url(/api/api.css); /* ============================================================ 1. BASE & RESET ============================================================ */ * { box-sizing: border-box; } /* Smooth cross-fade between pages */ @view-transition { navigation: auto; } ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.35s; animation-timing-function: ease; } @media (prefers-reduced-motion: reduce) { ::view-transition-old(root), ::view-transition-new(root) { animation: none; } } html, body { height: 100%; overflow: hidden; } html { background: linear-gradient(135deg, var(--base) 0%, var(--mantle) 60%, var(--crust) 100%); } body { font-family: 'Comic Code', sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; height: 100dvh; margin: 0; padding: 1.5rem 1rem; background: linear-gradient(135deg, var(--base) 0%, var(--mantle) 60%, var(--crust) 100%); color: var(--text); } /* Estrogen watermark blended into the background */ body::before { content: ""; position: fixed; inset: 0; background: url(/assets/theme/estrogen.svg) center / cover no-repeat; filter: invert(86%) sepia(8%) saturate(900%) hue-rotate(190deg) brightness(105%); opacity: 0.05; pointer-events: none; z-index: 0; } /* ============================================================ 2. SHARED LAYOUT & HEADER (all pages) ============================================================ */ .hub { position: relative; z-index: 1; width: 100%; max-width: 460px; } .pfp { width: 96px; height: 96px; border-radius: 50%; object-fit: cover; border: 3px solid var(--yellow); box-shadow: 0 4px 18px rgba(245, 194, 231, 0.25); margin-bottom: 0.75rem; } .hub-header { text-align: center; margin-bottom: 2.25rem; } .hub-header h1 { margin: 0; font-size: 2rem; font-weight: 700; color: rgb(var(--accent-rgb)); transition: color 0.6s ease; } .tagline { margin: 0.35rem 0 0; color: var(--subtext-0); font-size: 0.95rem; letter-spacing: 0.04em; text-transform: uppercase; } .pronouns { margin: 0.35rem 0 0; color: var(--mauve); font-size: 0.95rem; letter-spacing: 0.04em; text-transform: lowercase; } /* ============================================================ 3. LINK HUB (index page) ============================================================ */ .links { display: grid; grid-template-columns: repeat(auto-fit, 72px); gap: 0.9rem; justify-content: center; } .link-card { position: relative; display: flex; align-items: center; justify-content: center; width: 72px; height: 72px; border-radius: 16px; background: var(--surface-0); border: 1px solid var(--surface-1); color: var(--text); text-decoration: none; transition: transform 0.15s ease, border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease; } .link-card:hover { transform: translateY(-3px); background: var(--surface-1); border-color: rgb(var(--accent-rgb)); box-shadow: 0 6px 20px rgba(var(--accent-rgb), 0.22); } .icon { width: 30px; height: 30px; flex-shrink: 0; filter: brightness(0) invert(1); transition: filter 0.15s ease; } .link-card:hover .icon { filter: none; } /* Tooltip revealed on hover */ .link-text { position: absolute; bottom: calc(100% + 10px); left: 50%; transform: translateX(-50%) translateY(4px); display: flex; flex-direction: column; align-items: center; gap: 0.1rem; padding: 0.5rem 0.75rem; border-radius: 10px; background: var(--crust); border: 1px solid rgb(var(--accent-rgb)); box-shadow: 0 6px 18px rgba(17, 17, 27, 0.55); white-space: nowrap; line-height: 1.3; opacity: 0; pointer-events: none; transition: opacity 0.15s ease, transform 0.15s ease; z-index: 10; } .link-text::after { content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border: 6px solid transparent; border-top-color: rgb(var(--accent-rgb)); } .link-card:hover .link-text, .link-card:focus-visible .link-text { opacity: 1; transform: translateX(-50%) translateY(0); } .link-title { font-weight: 500; font-size: 0.95rem; color: var(--text); } .link-sub { font-size: 0.78rem; color: var(--subtext-0); } /* ============================================================ 4. NOW-PLAYING WIDGET (shared, pinned top-left) Discord presence + Spotify via Lanyard. The album-art accent colour is exposed as --np-accent (r, g, b) while .has-accent set. ============================================================ */ .now-playing { --np-accent: 245, 194, 231; /* fallback ~ Catppuccin pink */ position: fixed; top: 1rem; left: 1rem; z-index: 6; display: flex; align-items: center; gap: 0.55rem; max-width: 260px; padding: 0.4rem 0.7rem 0.4rem 0.4rem; border-radius: 999px; background: var(--surface-0); border: 1px solid var(--surface-1); color: var(--text); text-decoration: none; transition: transform 0.15s ease, border-color 0.2s ease, border-radius 0.25s ease, box-shadow 0.2s ease; } .now-playing[hidden] { display: none; } .now-playing:hover { transform: translateY(2px); border-color: var(--pink); } /* While a track is live the pill grows and squares off for the progress bar, picking up a faint album-art glow. */ .now-playing.is-live { align-items: stretch; border-radius: 16px; } .now-playing.is-live.has-accent { border-color: rgba(var(--np-accent), 0.55); box-shadow: 0 6px 22px -10px rgba(var(--np-accent), 0.6); } .now-playing.is-live:hover.has-accent { border-color: rgba(var(--np-accent), 0.85); } /* Head row: status dot + status word, always visible */ .np-head { display: flex; align-items: center; gap: 0.35rem; } .np-status { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--overlay-0); } .now-playing[data-status="online"] .np-status { background: var(--green); } .now-playing[data-status="idle"] .np-status { background: var(--yellow); } .now-playing[data-status="dnd"] .np-status { background: var(--red); } .now-playing[data-status="offline"] .np-status { background: var(--overlay-0); } .np-status-label { font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--subtext-0); white-space: nowrap; } .np-art { width: 34px; height: 34px; border-radius: 50%; object-fit: cover; flex-shrink: 0; align-self: center; display: none; } .now-playing.is-live .np-art { display: block; border-radius: 8px; } /* Equalizer bars (only animate while live) */ .np-bars { display: none; align-items: flex-end; gap: 2px; height: 16px; flex-shrink: 0; } .now-playing.is-live .np-bars { display: flex; } .np-bars i { width: 3px; height: 100%; border-radius: 2px; background: var(--pink); transform-origin: bottom; animation: np-eq 0.9s ease-in-out infinite; } .now-playing.has-accent .np-bars i { background: rgb(var(--np-accent)); } .np-bars i:nth-child(2) { animation-delay: 0.15s; } .np-bars i:nth-child(3) { animation-delay: 0.3s; } .np-bars i:nth-child(4) { animation-delay: 0.45s; } @keyframes np-eq { 0%, 100% { transform: scaleY(0.3); } 50% { transform: scaleY(1); } } @media (prefers-reduced-motion: reduce) { .np-bars i { animation: none; transform: scaleY(0.6); } } .np-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; } /* "Now playing" tag — only while a track is live, pushed right */ .np-label { display: none; font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--pink); } .now-playing.is-live .np-label { display: inline; margin-left: auto; padding-left: 0.5rem; } .now-playing.is-live.has-accent .np-label { color: rgb(var(--np-accent)); } .np-track { font-size: 0.8rem; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .np-track:empty { display: none; } .np-artist { font-size: 0.72rem; color: var(--subtext-0); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .np-artist:empty { display: none; } /* Spotify progress bar — only shown while a track has timestamps */ .np-progress { display: none; flex-direction: column; gap: 3px; margin-top: 4px; } .now-playing.is-live.has-progress .np-progress { display: flex; } .np-bar { height: 3px; width: 100%; border-radius: 999px; background: var(--surface-2); overflow: hidden; } .np-fill { display: block; height: 100%; width: 0%; border-radius: 999px; background: var(--pink); transition: width 0.3s linear; } .now-playing.has-accent .np-fill { background: rgb(var(--np-accent)); box-shadow: 0 0 8px 1px rgba(var(--np-accent), 0.55); } .np-times { display: flex; justify-content: space-between; font-size: 0.58rem; font-variant-numeric: tabular-nums; color: var(--subtext-0); } /* ============================================================ 5. PAGE NAV (shared, pinned bottom-left) ============================================================ */ .nav { position: fixed; left: 1rem; bottom: 1rem; z-index: 6; } .nav-links { display: flex; flex-direction: column; align-items: flex-start; gap: 0.4rem; } .nav-link { position: relative; display: inline-flex; align-items: center; padding: 0.3rem 0.7rem; border-radius: 999px; background: var(--surface-0); border: 1px solid var(--surface-1); color: var(--subtext-1); font-size: 0.8rem; text-decoration: none; transition: transform 0.15s ease, border-color 0.15s ease, background 0.15s ease, color 0.15s ease; } .nav-link:hover { border-color: rgb(var(--accent-rgb)); color: var(--text); transform: translateX(2px); } .nav-link.selected { background: rgb(var(--accent-rgb)); border-color: rgb(var(--accent-rgb)); color: var(--crust); font-weight: 700; margin-left: 14px; } .nav-link.is-a-dev { background: var(--surface-1); border-color: var(--surface-2); color: var(--text); } .nav-link.is-a-dev:hover { border-color: var(--saphire); transform: translateX(2px); } /* Triangle pointing at the selected item */ .nav-link.selected::before { content: ""; position: absolute; left: -14px; top: 50%; transform: translateY(-50%); border: 6px solid transparent; border-left-color: rgb(var(--accent-rgb)); } /* ============================================================ 6. SYSTEM BADGES (shared, pinned bottom-right) ============================================================ */ .badges { position: fixed; right: 1rem; bottom: 1rem; display: flex; flex-direction: column; align-items: flex-end; gap: 0.4rem; pointer-events: none; z-index: 5; } .badge { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.3rem 0.6rem; border-radius: 999px; background: var(--surface-0); border: 1px solid rgba(var(--accent-rgb), 0.45); color: var(--subtext-1); font-size: 0.75rem; white-space: nowrap; transition: border-color 0.6s ease, box-shadow 0.6s ease; } .badge:hover { border-color: rgb(var(--accent-rgb)); box-shadow: 0 4px 14px -6px rgba(var(--accent-rgb), 0.5); } .badge-icon { width: 15px; height: 15px; filter: invert(78%) sepia(36%) saturate(640%) hue-rotate(280deg) brightness(105%); } /* ============================================================ 7. THEME SWITCHER (shared, icon button top-right) ============================================================ */ .beta-bar { position: fixed; top: 1rem; right: 1rem; z-index: 7; display: flex; align-items: center; gap: 0.5rem; } /* cat-collection button icon: the classic oneko idle frame, scaled down from the 256x128 sprite sheet (idle frame lives at -96px,-96px) */ .beta-cat-icon { width: 22px; height: 22px; display: block; background-image: url('/assets/oneko/classics/classic.png'); background-repeat: no-repeat; background-size: 176px 88px; background-position: -66px -66px; image-rendering: pixelated; } .beta-btn { display: inline-flex; align-items: center; justify-content: center; padding: 0.35rem; border-radius: 999px; background: var(--surface-0); border: 1px solid var(--surface-1); cursor: pointer; transition: border-color 0.15s ease, transform 0.15s ease; } .beta-btn:hover { border-color: var(--pink); transform: translateY(2px); } .beta-icon { width: 22px; height: 22px; display: block; } /* ============================================================ 8. dev-info PAGE ============================================================ */ /* Let only the dev-info page scroll; link hub stays locked */ html:has(.dev-info), body:has(.dev-info) { height: auto; min-height: 100dvh; overflow-y: auto; } body:has(.dev-info) { align-items: flex-start; } body:has(.dev-info) .hub { max-width: 860px; } .dev-info { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem; margin: 0 auto; padding-bottom: 4.5rem; } /* Simple Icons rendered via CSS mask so colour is theme-driven. Markup: */ .tech-icon { position: relative; width: 30px; height: 30px; display: inline-block; transition: transform 0.15s ease, filter 0.15s ease; } /* The icon shape — masked so the label (::after) stays visible */ .tech-icon::before { content: ""; position: absolute; inset: 0; background-color: currentColor; -webkit-mask: var(--si) center / contain no-repeat; mask: var(--si) center / contain no-repeat; } .tech-icon:hover { transform: translateY(-2px) scale(1.12); filter: drop-shadow(0 4px 8px currentColor); } /* Hover label — pulls text from aria-label, tinted to match the icon */ .tech-icon::after { content: attr(aria-label); position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%) translateY(4px); padding: 0.25rem 0.5rem; border-radius: 6px; background: var(--crust); border: 1px solid currentColor; color: var(--text); font-size: 0.72rem; line-height: 1; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 0.15s ease, transform 0.15s ease; z-index: 10; } .tech-icon:hover::after { opacity: 1; transform: translateX(-50%) translateY(0); } /* Catppuccin accent classes — pull from the active flavour's vars */ .tech-icon.rosewater { color: var(--rosewater); } .tech-icon.pink { color: var(--pink); } .tech-icon.mauve { color: var(--mauve); } .tech-icon.red { color: var(--red); } .tech-icon.maroon { color: var(--maroon); } .tech-icon.peach { color: var(--peach); } .tech-icon.yellow { color: var(--yellow); } .tech-icon.green { color: var(--green); } .tech-icon.teal { color: var(--teal); } .tech-icon.sky { color: var(--sky); } .tech-icon.sapphire { color: var(--saphire); } .tech-icon.blue { color: var(--blue); } .tech-icon.lavender { color: var(--lavender); } /* ============================================================ 9. CHANGELOG PAGE ============================================================ */ html:has(.changelog), body:has(.changelog) { height: auto; min-height: 100dvh; overflow-y: auto; } body:has(.changelog) { align-items: flex-start; } body:has(.changelog) .hub { max-width: 540px; } .changelog { display: flex; flex-direction: column; gap: 1rem; padding-bottom: 4.5rem; } .release { background: var(--surface-0); border: 1px solid var(--surface-1); border-radius: 14px; padding: 1rem 1.15rem; } .release-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.6rem; } .release-version { font-weight: 700; font-size: 1.05rem; color: var(--pink); } .release-date { font-size: 0.78rem; color: var(--subtext-0); } .release-notes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.45rem; } .release-notes li { font-size: 0.88rem; line-height: 1.4; color: var(--text); } .tag { display: inline-block; margin-right: 0.4rem; padding: 0.05rem 0.45rem; border-radius: 6px; font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; vertical-align: 1px; } .tag-add { background: rgba(166, 227, 161, 0.18); color: var(--green); } .tag-change { background: rgba(137, 180, 250, 0.18); color: var(--blue); } /* ============================================================ 10. SECRET CAT MODES (toast + picker modal) ============================================================ */ .cat-toast { position: fixed; left: 50%; bottom: 4.5rem; transform: translateX(-50%) translateY(8px); z-index: 2147483647; padding: 0.4rem 0.9rem; border-radius: 999px; background: var(--crust); border: 1px solid var(--pink); color: var(--text); font-size: 0.8rem; white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity 0.2s ease, transform 0.2s ease; } .cat-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); } .cat-picker { position: fixed; inset: 0; z-index: 2147483646; display: flex; align-items: center; justify-content: center; padding: 1rem; background: rgba(17, 17, 27, 0.65); backdrop-filter: blur(2px); } .cat-picker[hidden] { display: none; } .cat-picker-panel { width: min(94vw, 430px); max-height: 82vh; overflow-y: auto; background: var(--base); border: 1px solid var(--surface-1); border-radius: 16px; padding: 1rem; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.55); } .cat-picker-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.85rem; font-weight: 700; color: var(--pink); } .cat-picker-close { background: none; border: none; color: var(--subtext-0); font-size: 1.35rem; line-height: 1; cursor: pointer; padding: 0 0.25rem; } .cat-picker-close:hover { color: var(--text); } .cat-grid { display: flex; flex-direction: column; gap: 1rem; } .cat-section-title { margin: 0 0 0.55rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--mauve); border-bottom: 1px solid var(--surface-1); padding-bottom: 0.3rem; } .cat-section-items { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.6rem; } .cat-option { display: flex; flex-direction: column; align-items: center; gap: 0.3rem; padding: 0.75rem 0.4rem 0.6rem; border-radius: 12px; background: var(--surface-0); border: 1px solid var(--surface-1); color: var(--text); font-family: inherit; font-size: 0.74rem; text-align: center; cursor: pointer; transition: transform 0.15s ease, border-color 0.15s ease; } .cat-option:hover:not(.locked) { transform: translateY(-2px); border-color: var(--pink); } .cat-option.current { border-color: var(--pink); box-shadow: inset 0 0 0 1px var(--pink); } .cat-option.locked { cursor: default; opacity: 0.75; } .cat-preview { /* 30px window + the -97px,-97px position = the idle frame inset 1px on every side, so no preview can catch pixels from neighbouring frames */ width: 30px; height: 30px; margin: 7px 1px 11px; background-repeat: no-repeat; image-rendering: pixelated; transform: scale(1.7); transform-origin: center; } .cat-name { font-weight: 500; } .cat-hint { margin: 0.85rem 0 0; font-size: 0.68rem; color: var(--subtext-0); text-align: center; } /* ============================================================ 11. DISCORD BOTS PAGE ============================================================ */ /* On the bots page the header sits closer to the sections */ body:has(.bot-grid) .hub-header { position: relative; z-index: 1; margin-bottom: 0.25rem; } /* FIX: bot-grid and friend-grid pages need scrolling — was missing */ html:has(.bot-grid), html:has(.friend-grid) { height: auto; min-height: 100dvh; overflow-y: auto; overflow-x: hidden; } body:has(.bot-grid), body:has(.friend-grid) { height: auto; min-height: 100dvh; align-items: flex-start; overflow-x: hidden; overflow-y: visible; } .section { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 1.5rem; width: 100%; } .section-title { margin: 0; font-size: 1.1rem; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--mauve); } .section-subtitle { margin: -1.1rem 0 0; font-size: 1.1rem; font-weight: 500; letter-spacing: 0.08em; text-transform: lowercase; color: var(--surface-2); } .bot-grid { margin-bottom: 1.5rem; display: grid; grid-template-columns: repeat(auto-fit, 96px); justify-content: center; gap: 2rem 1.5rem; max-width: 560px; } .bot { position: relative; display: flex; align-items: center; justify-content: center; width: 96px; height: 96px; color: var(--text); text-decoration: none; transition: transform 0.15s ease, border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease; } .bot-pfp { width: 96px; height: 96px; border-radius: 50%; object-fit: cover; border: 3px solid var(--yellow); box-shadow: 0 4px 18px rgba(var(--accent-rgb), 0.25); } .bot:hover { transform: translateY(-3px); } .bot:hover .bot-pfp { filter: none; } /* Bot tooltip revealed on hover */ .bot-link-text { position: absolute; bottom: calc(100% + 10px); left: 50%; transform: translateX(-50%) translateY(4px); display: flex; flex-direction: column; align-items: center; gap: 0.1rem; padding: 0.5rem 0.75rem; border-radius: 10px; background: var(--crust); border: 1px solid rgb(var(--accent-rgb)); box-shadow: 0 6px 18px rgba(17, 17, 27, 0.55); white-space: nowrap; line-height: 1.3; opacity: 0; pointer-events: none; transition: opacity 0.15s ease, transform 0.15s ease; z-index: 10; } .bot-link-text::after { content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border: 6px solid transparent; border-top-color: rgb(var(--accent-rgb)); } .bot:hover .bot-link-text, .bot:focus-visible .bot-link-text { opacity: 1; transform: translateX(-50%) translateY(0); } .bot-link-title { font-weight: 500; font-size: 0.95rem; color: var(--text); } .bot-link-sub { font-size: 0.78rem; color: var(--subtext-0); } .bot-link-sub.closed { color: var(--red); } /* ============================================================ 12. RESPONSIVE OVERRIDES ============================================================ */ /* Shrink to fit narrow / short screens so the hub never scrolls */ @media (max-width: 420px), (max-height: 640px) { .hub-header { margin-bottom: 1.25rem; } .hub-header h1 { font-size: 1.6rem; } .pfp { width: 72px; height: 72px; margin-bottom: 0.5rem; } .links { grid-template-columns: repeat(auto-fit, 60px); gap: 0.6rem; } .link-card { width: 60px; height: 60px; border-radius: 13px; } .icon { width: 26px; height: 26px; } } /* Cat picker: 2 columns on very narrow screens */ @media (max-width: 420px) { .cat-grid { grid-template-columns: repeat(2, 1fr); } } /* Mobile layout — single vertical scroll, stacked widgets */ @media (max-width: 640px) { html { height: auto; /* Single vertical scroll root on mobile; clip horizontal overflow so the absolutely-positioned link tooltips can't pan the page. */ overflow-x: hidden; overflow-y: auto; } body, body:has(.dev-info), body:has(.changelog), body:has(.bot-grid), body:has(.friend-grid) { flex-direction: column; justify-content: flex-start; align-items: center; gap: 1rem; height: auto; min-height: 100dvh; overflow-x: hidden; overflow-y: visible; padding: 1.25rem 1rem 2rem; } /* 1 — Top bar: the two single-item widgets, side by side */ .topbar { order: 1; display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.6rem; width: 100%; } /* FIX: the presence card injected by now-playing.js replaces #now-playing with .presence-card (position:fixed by default in api.css). Inside .topbar on mobile it must flow normally. */ .topbar .presence-card, .topbar .now-playing, .topbar .beta-bar { position: static; inset: auto; } /* FIX: presence-card max-width so it doesn't overflow narrow screens */ .topbar .presence-card { max-width: min(100%, 320px); width: 100%; } .now-playing { max-width: 100%; } /* 2 — Main content */ .hub, body:has(.dev-info) .hub, body:has(.changelog) .hub, body:has(.bot-grid) .hub, body:has(.friend-grid) .hub { order: 2; width: 100%; max-width: 100%; } /* 3 — Page nav as a centered group */ .nav { order: 3; position: static; inset: auto; width: 100%; } .nav-links { flex-direction: row; flex-wrap: wrap; justify-content: center; gap: 0.5rem; } /* The selected-item pointer triangle / offset only makes sense in the vertical desktop nav — drop it on mobile */ .nav-link.selected { margin-left: 0; } .nav-link.selected::before { display: none; } /* 4 — System badges, centered and wrapping */ .badges { order: 4; position: static; inset: auto; width: 100%; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: center; /* FIX: restore pointer-events on mobile so pokéball and badges are tappable */ pointer-events: auto; } /* FIX: hide tooltips on touch (they'd stick on tap) */ .link-card:hover .link-text, .bot:hover .bot-link-text { opacity: 0; pointer-events: none; } .hub-header { margin-bottom: 1.5rem; } /* Keep the dev-info / changelog / bots / friends content from butting up against the nav below it */ .dev-info, .changelog, .bot-grid, .friend-grid { padding-bottom: 1rem; } /* FIX: bot sections need a bit of breathing room */ .section+.section { margin-top: 1.5rem; } /* FIX: narrow waka bar label column so bars aren't crushed */ .waka-bar-row { grid-template-columns: 5rem 1fr auto; } /* FIX: terminal height — respect short landscape viewports */ .terminal { width: 94vw; max-height: clamp(300px, 65dvh, 70vh); } /* FIX: button-wall — static in mobile flow, centered */ .button-wall { order: 5; position: static; transform: none; margin: 0 auto; max-width: 100%; } /* FIX: override the term-chrome-in transform that wins by source order over the plain .button-wall rule above (same specificity, later in sheet) */ body.term-booting .button-wall, body.term-chrome-in .button-wall { transform: none; } } /* Very narrow phones — squeeze waka bar name column further */ @media (max-width: 380px) { .waka-bar-row { grid-template-columns: 4rem 1fr auto; gap: 0.4rem; } .waka-bar-val { font-size: 0.66rem; } .bot-grid, .friend-grid { gap: 1.5rem 1rem; } /* Shrink avatar grids slightly on very small screens */ .bot-pfp, .friend-pfp { width: 80px; height: 80px; } .bot, .friend { width: 80px; height: 80px; } } /* ============================================================ 12. HIDDEN POKÉBALL (unlocks the Pokémon cats once clicked) ============================================================ */ /* Small, low-contrast and tucked among the badges so it has to be hunted for. Still clickable — that's the whole point of finding it. */ #pokeball-secret { width: 14px; height: 14px; opacity: 0.18; align-self: center; cursor: default; pointer-events: auto; /* parent .badges sets none — re-enable here */ image-rendering: auto; transition: opacity 0.2s ease, transform 0.2s ease; -webkit-user-drag: none; user-select: none; } #pokeball-secret:hover { opacity: 0.85; transform: scale(1.15); } #pokeball-secret.found { opacity: 1; cursor: default; filter: drop-shadow(0 0 4px var(--red)); } /* ============================================================ 12. dev-info / CODING STATS PAGE ============================================================ */ /* Let the coding-stats page scroll; link hub stays locked */ html:has(.waka), body:has(.waka) { height: auto; min-height: 100dvh; overflow-y: auto; } body:has(.waka) { align-items: flex-start; } .waka { position: relative; z-index: 1; width: 100%; max-width: 640px; margin: 0 auto; padding-bottom: 4.5rem; } .waka .hub-header { margin-bottom: 1.5rem; } .waka-meta { margin: 0.5rem 0 0; font-size: 0.72rem; letter-spacing: 0.03em; color: var(--subtext-0); } .waka-section { background: var(--surface-0); border: 1px solid var(--surface-1); border-radius: 16px; padding: 1.15rem 1.25rem 1.35rem; margin-bottom: 1.1rem; } .waka-section .section-title { text-align: left; font-size: 0.82rem; margin-bottom: 1rem; } /* ---- headline total + weekly chart ---- */ .waka-total { text-align: center; } .waka-total-num { font-size: 2.1rem; font-weight: 700; color: rgb(var(--accent-rgb)); line-height: 1.1; } .waka-total-sub { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--subtext-0); margin-bottom: 1.1rem; } .waka-week { display: flex; align-items: flex-end; justify-content: space-between; gap: 0.5rem; height: 120px; } .waka-day { flex: 1 1 0; display: flex; flex-direction: column; align-items: center; gap: 0.4rem; height: 100%; } .waka-day-track { flex: 1; width: 100%; max-width: 34px; display: flex; align-items: flex-end; background: var(--surface-1); border-radius: 7px; overflow: hidden; } .waka-day-fill { width: 100%; min-height: 3px; background: rgb(var(--accent-rgb)); border-radius: 7px 7px 0 0; transition: height 0.5s ease; } .waka-day-label { font-size: 0.66rem; color: var(--subtext-0); } /* ---- ranked horizontal bars (languages / projects / editors / os) ---- */ .waka-bars { display: flex; flex-direction: column; gap: 0.6rem; } .waka-bar-row { display: grid; grid-template-columns: 7.5rem 1fr auto; align-items: center; gap: 0.7rem; } .waka-bar-name { font-size: 0.82rem; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .waka-bar-track { height: 9px; background: var(--surface-1); border-radius: 999px; overflow: hidden; } .waka-bar-fill { display: block; height: 100%; width: 0; background: rgb(var(--accent-rgb)); border-radius: 999px; transition: width 0.6s ease; } .waka-bar-val { font-size: 0.74rem; color: var(--subtext-0); white-space: nowrap; font-variant-numeric: tabular-nums; } /* ---- two-up grid for editors + OS on wider screens ---- */ .waka-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; } .waka-grid2 .waka-section { margin-bottom: 0; } @media (max-width: 560px) { .waka-grid2 { grid-template-columns: 1fr; gap: 0; } .waka-grid2 .waka-section { margin-bottom: 1.1rem; } .waka-bar-row { grid-template-columns: 5.5rem 1fr auto; } } /* ---- empty / setup state ---- */ .waka-empty { font-size: 0.85rem; color: var(--subtext-0); line-height: 1.5; margin: 0; } .waka-setup { background: var(--surface-0); border: 1px solid var(--surface-1); border-radius: 16px; padding: 1.25rem 1.4rem 1.5rem; text-align: left; } .waka-steps { margin: 0.9rem 0 1.2rem; padding-left: 1.2rem; display: flex; flex-direction: column; gap: 0.5rem; font-size: 0.85rem; line-height: 1.45; color: var(--text); } .waka-steps code { background: var(--surface-1); padding: 0.05rem 0.35rem; border-radius: 6px; font-size: 0.8rem; } .waka-steps a, .waka-empty a, .waka-credit a { color: rgb(var(--accent-rgb)); text-decoration: none; } .waka-steps a:hover, .waka-empty a:hover, .waka-credit a:hover { text-decoration: underline; } .waka-setup-btn { display: inline-block; padding: 0.45rem 1rem; border-radius: 999px; background: rgb(var(--accent-rgb)); color: var(--crust); font-size: 0.82rem; font-weight: 600; text-decoration: none; transition: transform 0.15s ease, filter 0.15s ease; } .waka-setup-btn:hover { transform: translateY(-1px); filter: brightness(1.05); } .waka-credit { text-align: center; font-size: 0.72rem; color: var(--subtext-0); margin: 1.4rem 0 0; } /* ============================================================ 14. TERMINAL HOMEPAGE (+ 88x31 button wall) ============================================================ */ .terminal { position: relative; z-index: 1; width: min(92vw, 760px); max-height: 76vh; display: flex; flex-direction: column; padding: 1rem 1.15rem 1.15rem; background: var(--mantle); border: 1px solid var(--surface-1); border-radius: 14px; box-shadow: 0 18px 50px -20px rgba(0, 0, 0, 0.7); font-family: 'Comic Code', ui-monospace, 'JetBrains Mono', Menlo, monospace; font-size: 0.86rem; line-height: 1.5; color: var(--text); overflow: hidden; } body:has(.terminal) .hub { max-width: min(92vw, 760px); width: 100%; } body:has(.terminal) .hub .terminal { width: 100%; margin: 0 auto; } /* ---- boot log ---- */ .t-boot { margin: 0; white-space: pre-wrap; word-break: break-word; font-size: 0.78rem; color: var(--subtext-0); max-height: 72vh; overflow: hidden; } .t-boot[hidden] { display: none; } .b-line { display: block; } .b-time { color: var(--overlay-0); } .b-info { color: var(--blue); font-weight: 700; } .b-ok { color: var(--green); font-weight: 700; } /* ---- main terminal ---- */ .t-main { display: flex; flex-direction: column; min-height: 0; } .t-main[hidden] { display: none; } .t-banner { margin: 0 0 0.5rem; color: rgb(var(--accent-rgb)); font-size: clamp(0.4rem, 1.45vw, 0.78rem); line-height: 1.04; white-space: pre; overflow-x: auto; text-shadow: 0 0 14px rgba(var(--accent-rgb), 0.35); } .t-greet { margin-bottom: 0.7rem; color: var(--subtext-1); } .t-greet b { color: rgb(var(--accent-rgb)); } .t-dim { color: var(--subtext-0); } .t-accent { color: rgb(var(--accent-rgb)); } .t-inputline { display: flex; align-items: center; gap: 0.5rem; padding-bottom: 0.55rem; border-bottom: 1px solid var(--surface-0); } .t-prompt { color: var(--green); white-space: nowrap; font-weight: 700; } .t-path { color: var(--blue); font-weight: 700; } .t-input { flex: 1; min-width: 0; background: transparent; border: none; outline: none; color: var(--text); font: inherit; caret-color: rgb(var(--accent-rgb)); } .t-output { margin-top: 0.6rem; min-height: 0; flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 0.6rem; } .t-echo { color: var(--subtext-0); } .t-result { white-space: pre-wrap; word-break: break-word; margin-top: 0.15rem; } .t-entry.is-error .t-result { color: var(--red); } /* hyfetch trans-flag block */ .hf-c1 { color: #5bcefa; } .hf-c2 { color: #f5a9b8; } .hf-c3 { color: #ffffff; } .hf-pad { color: transparent; } /* ---- 88x31 button wall (always visible) ---- */ .button-wall { position: fixed; bottom: 1rem; left: 50%; transform: translateX(-50%); z-index: 5; display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem; max-width: min(90vw, 480px); } .button-wall a { display: block; line-height: 0; } .button-wall img { width: 88px; height: 31px; image-rendering: pixelated; border: 1px solid var(--surface-1); border-radius: 2px; transition: transform 0.12s ease, border-color 0.12s ease; } .button-wall a:hover img { transform: translateY(-2px); border-color: rgb(var(--accent-rgb)); } /* ---- boot reveal of side chrome ---- */ .nav, .badges, .button-wall { transition: opacity 0.6s ease, transform 0.6s ease; } body.term-booting .nav, body.term-booting .badges, body.term-booting .button-wall { opacity: 0; transform: translateY(8px); } body.term-booting .button-wall { transform: translate(-50%, 8px); } body.term-chrome-in .nav, body.term-chrome-in .badges, body.term-chrome-in .button-wall { opacity: 1; transform: none; } body.term-chrome-in .button-wall { transform: translateX(-50%); } @media (max-width: 640px) { .terminal { width: 94vw; max-height: clamp(300px, 65dvh, 70vh); } /* FIX: button-wall mobile — override both the base fixed position AND the term-chrome-in rule (which is later in source order and wins by cascade) */ .button-wall, body.term-booting .button-wall, body.term-chrome-in .button-wall { position: static; transform: none; margin: 0 auto; max-width: 100%; } } /* ---- terminal: socials list (svg icon + clickable link) ---- */ .t-socials-hint { margin-bottom: 0.4rem; } .t-socials { display: flex; flex-direction: column; gap: 0.1rem; } .t-social { display: grid; grid-template-columns: 18px 6.5rem 6rem 1fr; align-items: center; gap: 0.55rem; padding: 0.22rem 0.4rem; border-radius: 6px; text-decoration: none; color: var(--text); border: 1px solid transparent; } .t-social:hover { background: var(--surface-0); border-color: rgba(var(--accent-rgb), 0.4); } .t-social-ic { width: 16px; height: 16px; object-fit: contain; } .t-social-key { color: rgb(var(--accent-rgb)); } .t-social-label { color: var(--text); } .t-social-sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* the "Opening …" confirmation line */ .t-social-open { display: inline-flex; align-items: center; gap: 0.4rem; grid-template-columns: none; padding: 0; border: none; } .t-social-open:hover { background: transparent; } /* ---- terminal: ls-style socials list + social card ---- */ .t-ls { display: grid; grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr)); gap: 0.1rem 1.2rem; } .t-ls-item { color: rgb(var(--accent-rgb)); } .t-ls-foot { margin-top: 0.6rem; } .t-ls-foot b { color: var(--text); } .t-social-card { display: flex; flex-direction: column; gap: 0.35rem; } .t-sc-head { display: flex; align-items: center; gap: 0.45rem; } .t-sc-head .t-social-ic { width: 18px; height: 18px; } .t-sc-url { color: var(--blue); text-decoration: none; word-break: break-all; } .t-sc-url:hover { text-decoration: underline; } .t-sc-ask { margin-top: 0.2rem; } .t-sc-ask b { color: var(--text); } .t-social-open { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--text); text-decoration: none; } .t-social-open .t-social-ic { width: 16px; height: 16px; } /* ---- hyfetch: arch logo + info, side by side ---- */ .hf { display: flex; gap: 1.1rem; align-items: flex-start; flex-wrap: wrap; } .hf-logo { margin: 0; white-space: pre; line-height: 1.02; font-size: 0.62rem; } .hf-info { margin: 0; white-space: pre; } /* ============================================================ 13. Friends Page ============================================================ */ body:has(.friend-grid) .hub-header { position: relative; z-index: 1; margin-bottom: 2rem; } .friend-grid { display: grid; grid-template-columns: repeat(auto-fit, 96px); justify-content: center; margin-bottom: 1.5rem; gap: 3rem 1.5rem; max-width: 560px; } .friend { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; width: 96px; height: auto; color: var(--text); text-decoration: none; transition: transform 0.15s ease, border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease; } .friend-name { margin-top: 0.5rem; font-size: 0.8rem; color: var(--subtext-0); text-align: center; } .friend-name::before { content: "🩵 "; } .friend-name.wife::before { content: "🖤 "; } .friend-name.close::before { content: "🤍 "; } .friend-pfp { width: 96px; height: 96px; border-radius: 50%; object-fit: cover; border: 3px solid var(--yellow); box-shadow: 0 4px 18px rgba(var(--accent-rgb), 0.25); } .friend-pfp.wife { border: 3px solid var(--lavender); } .friend-pfp.close { border: 3px solid var(--red); } .friend:hover { transform: translateY(-3px); } .friend:hover .friend-pfp { filter: none; }