Files
saiti-wiki/src/components/WikiHeader.astro

863 lines
28 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
import config from 'virtual:starlight/user-config';
import LanguageSelect from 'virtual:starlight/components/LanguageSelect';
import Search from 'virtual:starlight/components/Search';
import SocialIcons from 'virtual:starlight/components/SocialIcons';
const shouldRenderSearch =
config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro';
const topLinks = [
{ label: 'Старт', href: '/getting-started/' },
{ label: 'Команды', href: '/commands/' },
{ label: 'Города', href: '/cities/' },
{ label: 'FAQ', href: '/faq/' },
{ label: 'Правила', href: '/rules/' }
];
---
<div class="wiki-header-shell">
<div class="header wiki-header">
<div class="title-wrapper sl-flex">
<a class="wiki-brand" href="/" aria-label="PARABOX PROJECT">
<span class="wiki-brand__icon" aria-hidden="true">
<img src="/brand-logo.png" alt="" loading="eager" decoding="async" />
</span>
<span class="wiki-brand__copy">
<span class="wiki-brand__title">PARABOX</span>
<span class="wiki-brand__subtitle">PROJECT</span>
</span>
</a>
<nav class="wiki-top-nav" aria-label="Быстрая навигация">
{
topLinks.map((link) => (
<a href={link.href} class="wiki-top-nav__link">
{link.label}
</a>
))
}
</nav>
</div>
<div class="sl-flex print:hidden header-tools">
{shouldRenderSearch && <Search />}
<button
class="theme-toggle-btn mobile-theme-toggle md:sl-hidden"
type="button"
aria-label="Переключить тему"
data-theme-toggle
>
<svg class="icon-sun" aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="4" />
<line x1="12" y1="2.5" x2="12" y2="5.5" />
<line x1="12" y1="18.5" x2="12" y2="21.5" />
<line x1="2.5" y1="12" x2="5.5" y2="12" />
<line x1="18.5" y1="12" x2="21.5" y2="12" />
<line x1="5" y1="5" x2="7.3" y2="7.3" />
<line x1="16.7" y1="16.7" x2="19" y2="19" />
<line x1="5" y1="19" x2="7.3" y2="16.7" />
<line x1="16.7" y1="7.3" x2="19" y2="5" />
</svg>
<svg class="icon-moon" aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none">
<path d="M15.3 3.8A8.9 8.9 0 1 0 20.2 16a7.4 7.4 0 1 1-4.9-12.2Z" />
<path d="m19.9 4.4.7 1.6 1.6.7-1.6.7-.7 1.6-.7-1.6-1.6-.7 1.6-.7.7-1.6Z" />
</svg>
</button>
</div>
<div class="sl-hidden md:sl-flex print:hidden right-group">
<div class="sl-flex social-icons">
<SocialIcons />
</div>
<button class="theme-toggle-btn" type="button" aria-label="Переключить тему" data-theme-toggle>
<svg class="icon-sun" aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="4" />
<line x1="12" y1="2.5" x2="12" y2="5.5" />
<line x1="12" y1="18.5" x2="12" y2="21.5" />
<line x1="2.5" y1="12" x2="5.5" y2="12" />
<line x1="18.5" y1="12" x2="21.5" y2="12" />
<line x1="5" y1="5" x2="7.3" y2="7.3" />
<line x1="16.7" y1="16.7" x2="19" y2="19" />
<line x1="5" y1="19" x2="7.3" y2="16.7" />
<line x1="16.7" y1="7.3" x2="19" y2="5" />
</svg>
<svg class="icon-moon" aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none">
<path d="M15.3 3.8A8.9 8.9 0 1 0 20.2 16a7.4 7.4 0 1 1-4.9-12.2Z" />
<path d="m19.9 4.4.7 1.6 1.6.7-1.6.7-.7 1.6-.7-1.6-1.6-.7 1.6-.7.7-1.6Z" />
</svg>
</button>
<LanguageSelect />
</div>
</div>
<div class="wiki-read-progress" aria-hidden="true">
<div class="wiki-read-progress__fill" data-read-progress></div>
</div>
</div>
<button class="wiki-back-to-top" type="button" aria-label="Прокрутить в начало" data-back-to-top>
<svg aria-hidden="true" class="wiki-back-to-top__icon" viewBox="0 0 24 24" fill="none">
<path d="M12 18V6" />
<path d="m6.8 11.2 5.2-5.2 5.2 5.2" />
</svg>
</button>
<script>
const emojiPattern = (() => {
try {
return new RegExp('[\\p{Extended_Pictographic}\\u2600-\\u27BF]', 'gu');
} catch {
return /[\u2600-\u27BF]/g;
}
})();
const stripDecorativeSymbols = (value) =>
value
.replace(emojiPattern, '')
.replace(/\s{2,}/g, ' ')
.trim();
const normalizeLabelKey = (value) => stripDecorativeSymbols(value).toLowerCase();
const minimalIconByHeading = new Map([
['настройки', '/icons/minimal-solid/gear.png'],
['личные сообщения', '/icons/minimal-solid/message.png'],
['игнор', '/icons/minimal-solid/safe.png'],
['развлечения', '/icons/minimal-solid/game-controller.png'],
['rp и взаимодействие', '/icons/minimal-solid/community.png'],
['статус игрока', '/icons/minimal-solid/user-profile.png'],
['информация', '/icons/minimal-solid/exclamation.png'],
['символы', '/icons/minimal-solid/keyboard.png']
]);
const sanitizeNavLabels = () => {
const navLinks = document.querySelectorAll('.sidebar-content a, starlight-toc a, mobile-starlight-toc a');
navLinks.forEach((linkNode) => {
if (!(linkNode instanceof HTMLElement)) return;
const sourceText = linkNode.textContent;
if (!sourceText) return;
const normalizedText = stripDecorativeSymbols(sourceText);
if (!normalizedText || normalizedText === sourceText.trim()) return;
linkNode.textContent = normalizedText;
});
};
const sanitizeDocHeadings = () => {
const headings = document.querySelectorAll('.sl-markdown-content :is(h1, h2, h3, h4, h5, h6)');
headings.forEach((headingNode) => {
if (!(headingNode instanceof HTMLElement)) return;
const sourceText = headingNode.textContent;
if (!sourceText) return;
const normalizedText = stripDecorativeSymbols(sourceText);
if (!normalizedText || normalizedText === sourceText.trim()) return;
headingNode.textContent = normalizedText;
});
};
const decorateSectionIcons = () => {
const headings = document.querySelectorAll('.sl-markdown-content h3');
headings.forEach((headingNode) => {
if (!(headingNode instanceof HTMLElement)) return;
const sourceText = headingNode.textContent;
if (!sourceText) return;
const normalizedText = normalizeLabelKey(sourceText);
const iconPath = minimalIconByHeading.get(normalizedText);
if (!iconPath) return;
if (headingNode.querySelector('.minimal-heading-icon')) return;
const iconNode = document.createElement('span');
iconNode.className = 'minimal-heading-icon';
iconNode.setAttribute('aria-hidden', 'true');
iconNode.style.setProperty('--icon-url', `url('${iconPath}')`);
headingNode.prepend(iconNode);
});
};
const trimDestination = (value, maxLength = 42) => {
if (value.length <= maxLength) return value;
return `${value.slice(0, Math.max(0, maxLength - 1))}…`;
};
const decodePath = (value) => {
try {
return decodeURIComponent(value);
} catch {
return value;
}
};
const annotateLinkDestinations = () => {
const links = document.querySelectorAll('a[href]');
links.forEach((linkNode) => {
if (!(linkNode instanceof HTMLAnchorElement)) return;
if (linkNode.dataset.linkAnnotated === 'true') return;
const rawHref = linkNode.getAttribute('href')?.trim();
if (!rawHref || rawHref.toLowerCase().startsWith('javascript:')) return;
let parsedUrl;
try {
parsedUrl = new URL(rawHref, window.location.href);
} catch {
return;
}
const isHashOnly = rawHref.startsWith('#');
const isHttp = parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
const isMail = parsedUrl.protocol === 'mailto:';
const isTel = parsedUrl.protocol === 'tel:';
const isExternal = isHttp && parsedUrl.origin !== window.location.origin;
const isSamePageAnchor =
!isExternal && !!parsedUrl.hash && parsedUrl.pathname === window.location.pathname;
const isContentLink = linkNode.closest('.sl-markdown-content') instanceof HTMLElement;
const shouldDecorate =
isContentLink &&
!isHashOnly &&
!linkNode.classList.contains('sl-anchor-link') &&
!linkNode.classList.contains('map-cta-button') &&
!linkNode.classList.contains('map-ghost-button') &&
!linkNode.classList.contains('sl-link-button');
if (shouldDecorate) {
let kind = 'internal';
if (isExternal) kind = 'external';
else if (isMail) kind = 'mail';
else if (isTel) kind = 'tel';
else if (isSamePageAnchor) kind = 'anchor';
linkNode.dataset.linkKind = kind;
let destination = '';
if (isExternal) destination = parsedUrl.hostname.replace(/^www\./, '');
else if (isMail) destination = rawHref.replace(/^mailto:/i, '');
else if (isTel) destination = rawHref.replace(/^tel:/i, '');
else destination = `${decodePath(parsedUrl.pathname)}${parsedUrl.hash || ''}`;
if (destination) {
linkNode.dataset.linkDestination = trimDestination(destination);
}
}
if (isExternal) {
const relValues = new Set((linkNode.rel || '').split(/\s+/).filter(Boolean));
relValues.add('noopener');
relValues.add('noreferrer');
linkNode.rel = Array.from(relValues).join(' ');
if (!linkNode.target) {
linkNode.target = '_blank';
}
}
if (!linkNode.title) {
if (isHashOnly || isSamePageAnchor) {
linkNode.title = `Переход к разделу: ${parsedUrl.hash || rawHref}`;
} else if (isExternal) {
linkNode.title = `Внешняя ссылка: ${parsedUrl.hostname.replace(/^www\./, '')}`;
} else if (isMail) {
linkNode.title = `Написать: ${rawHref.replace(/^mailto:/i, '')}`;
} else if (isTel) {
linkNode.title = `Позвонить: ${rawHref.replace(/^tel:/i, '')}`;
} else {
linkNode.title = `Перейти: ${decodePath(parsedUrl.pathname)}${parsedUrl.hash || ''}`;
}
}
linkNode.dataset.linkAnnotated = 'true';
});
};
const copyTextToClipboard = async (value) => {
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(value);
return;
}
const helperInput = document.createElement('textarea');
helperInput.value = value;
helperInput.setAttribute('readonly', '');
helperInput.style.position = 'fixed';
helperInput.style.opacity = '0';
document.body.appendChild(helperInput);
helperInput.select();
document.execCommand('copy');
helperInput.remove();
};
const bindCopyIpChips = () => {
const copyButtons = document.querySelectorAll('[data-copy-ip]');
copyButtons.forEach((buttonNode) => {
if (!(buttonNode instanceof HTMLButtonElement)) return;
if (buttonNode.dataset.copyBound === 'true') return;
buttonNode.dataset.copyBound = 'true';
buttonNode.classList.add('is-copy-ready');
if (!buttonNode.title) {
buttonNode.title = 'Нажмите, чтобы скопировать';
}
buttonNode.addEventListener('click', async () => {
const value = buttonNode.dataset.copyIp?.trim();
if (!value) return;
try {
await copyTextToClipboard(value);
buttonNode.classList.add('is-copied');
buttonNode.setAttribute('aria-label', `Скопировано: ${value}`);
window.setTimeout(() => {
buttonNode.classList.remove('is-copied');
buttonNode.setAttribute('aria-label', `Скопировать: ${value}`);
}, 1200);
} catch {
buttonNode.classList.add('is-copy-error');
buttonNode.setAttribute('aria-label', `Не удалось скопировать: ${value}`);
window.setTimeout(() => {
buttonNode.classList.remove('is-copy-error');
buttonNode.setAttribute('aria-label', `Скопировать: ${value}`);
}, 1400);
}
});
});
};
const normalizeCraftSearch = (value) =>
stripDecorativeSymbols(value)
.toLowerCase()
.replace(/ё/g, 'е')
.replace(/\s+/g, ' ')
.trim();
const bindCraftCatalogFilters = () => {
const catalogNodes = document.querySelectorAll('[data-craft-catalog]');
catalogNodes.forEach((catalogNode) => {
if (!(catalogNode instanceof HTMLElement)) return;
if (catalogNode.dataset.craftBound === 'true') return;
catalogNode.dataset.craftBound = 'true';
const searchInput = catalogNode.querySelector('[data-craft-search]');
const filterButtons = Array.from(catalogNode.querySelectorAll('[data-craft-filter]')).filter(
(node) => node instanceof HTMLButtonElement
);
const groupNodes = Array.from(catalogNode.querySelectorAll('[data-craft-group]')).filter(
(node) => node instanceof HTMLElement
);
const emptyState = catalogNode.querySelector('[data-craft-empty]');
let activeFilter = 'all';
const activeButton = filterButtons.find(
(buttonNode) =>
buttonNode.classList.contains('is-active') ||
buttonNode.getAttribute('aria-pressed') === 'true'
);
if (activeButton?.dataset.craftFilter) {
activeFilter = activeButton.dataset.craftFilter;
}
const applyFilters = () => {
const searchQuery =
searchInput instanceof HTMLInputElement ? normalizeCraftSearch(searchInput.value) : '';
filterButtons.forEach((buttonNode) => {
const isActive = (buttonNode.dataset.craftFilter || 'all') === activeFilter;
buttonNode.classList.toggle('is-active', isActive);
buttonNode.setAttribute('aria-pressed', String(isActive));
});
let visibleCount = 0;
groupNodes.forEach((groupNode) => {
const defaultCategory = groupNode.dataset.craftCategory || '';
const itemNodes = Array.from(groupNode.querySelectorAll('[data-craft-item]')).filter(
(node) => node instanceof HTMLElement
);
let groupVisibleCount = 0;
itemNodes.forEach((itemNode) => {
const itemCategory = itemNode.dataset.craftCategory || defaultCategory;
const itemName =
itemNode.dataset.craftName || itemNode.querySelector('h3')?.textContent || '';
const normalizedName = normalizeCraftSearch(itemName);
const matchesCategory = activeFilter === 'all' || itemCategory === activeFilter;
const matchesSearch = !searchQuery || normalizedName.includes(searchQuery);
const isVisible = matchesCategory && matchesSearch;
itemNode.hidden = !isVisible;
if (isVisible) groupVisibleCount += 1;
});
groupNode.hidden = groupVisibleCount === 0;
visibleCount += groupVisibleCount;
});
if (emptyState instanceof HTMLElement) {
emptyState.hidden = visibleCount > 0;
}
};
filterButtons.forEach((buttonNode) => {
buttonNode.addEventListener('click', () => {
const nextFilter = buttonNode.dataset.craftFilter || 'all';
if (nextFilter === activeFilter) return;
activeFilter = nextFilter;
applyFilters();
});
});
if (searchInput instanceof HTMLInputElement) {
searchInput.addEventListener('input', applyFilters);
searchInput.addEventListener('search', applyFilters);
}
applyFilters();
});
};
const enhanceSidebarGroupLinks = () => {
const targets = [];
if (targets.length === 0) return;
const labelNodes = document.querySelectorAll('.sidebar-content details > summary .group-label .large');
labelNodes.forEach((labelNode) => {
if (!(labelNode instanceof HTMLElement)) return;
const text = labelNode.textContent?.trim();
const target = targets.find((item) => item.label === text);
if (!target) return;
if (labelNode.querySelector('a[data-sidebar-group-link]')) return;
const link = document.createElement('a');
link.href = target.href;
link.className = 'sidebar-group-link';
link.dataset.sidebarGroupLink = 'true';
link.textContent = target.label;
link.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
window.location.href = target.href;
});
labelNode.replaceChildren(link);
});
};
const setReadProgress = () => {
const progressEl = document.querySelector('[data-read-progress]');
const backToTopBtn = document.querySelector('[data-back-to-top]');
if (!(progressEl instanceof HTMLElement)) return;
const doc = document.documentElement;
const scrollTop = window.scrollY || doc.scrollTop;
const scrollable = doc.scrollHeight - window.innerHeight;
const ratio = scrollable > 0 ? Math.min(1, Math.max(0, scrollTop / scrollable)) : 0;
progressEl.style.transform = `scaleX(${ratio})`;
if (backToTopBtn instanceof HTMLElement) {
backToTopBtn.classList.toggle('is-visible', scrollTop > 420);
}
};
const bindReadProgress = () => {
const backToTopBtn = document.querySelector('[data-back-to-top]');
const themeToggleBtns = document.querySelectorAll('[data-theme-toggle]');
if (backToTopBtn instanceof HTMLElement) {
if (backToTopBtn.parentElement !== document.body) {
document.body.appendChild(backToTopBtn);
}
backToTopBtn.addEventListener('click', () => {
window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
themeToggleBtns.forEach((btn) => {
if (!(btn instanceof HTMLButtonElement)) return;
btn.addEventListener('click', () => {
const root = document.documentElement;
const current = root.dataset.theme === 'light' ? 'light' : 'dark';
const next = current === 'dark' ? 'light' : 'dark';
root.dataset.theme = next;
localStorage.setItem('starlight-theme', next);
});
});
enhanceSidebarGroupLinks();
sanitizeNavLabels();
sanitizeDocHeadings();
decorateSectionIcons();
annotateLinkDestinations();
bindCopyIpChips();
bindCraftCatalogFilters();
setReadProgress();
window.addEventListener('scroll', setReadProgress, { passive: true });
window.addEventListener('resize', setReadProgress);
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bindReadProgress, { once: true });
} else {
bindReadProgress();
}
document.addEventListener('astro:page-load', () => {
enhanceSidebarGroupLinks();
sanitizeNavLabels();
sanitizeDocHeadings();
decorateSectionIcons();
annotateLinkDestinations();
bindCopyIpChips();
bindCraftCatalogFilters();
setReadProgress();
});
</script>
<style>
@layer starlight.core {
.wiki-header-shell {
position: relative;
width: 100%;
height: 100%;
}
.wiki-header {
display: flex;
gap: var(--sl-nav-gap);
justify-content: space-between;
align-items: center;
height: 100%;
padding-block: 0.34rem;
}
.title-wrapper {
overflow: clip;
padding: 0.25rem;
margin: -0.25rem;
min-width: 0;
gap: 1.1rem;
align-items: center;
}
.wiki-brand {
display: inline-flex;
align-items: center;
gap: 0.55rem;
text-decoration: none;
flex-shrink: 0;
border: 1px solid transparent;
border-radius: 0.3rem;
padding: 0.2rem 0.28rem 0.2rem 0.22rem;
transition: border-color 150ms ease, background 150ms ease;
}
.wiki-brand:hover {
border-color: color-mix(in srgb, var(--sl-color-accent) 32%, transparent);
background: color-mix(in srgb, var(--sl-color-accent-low) 64%, transparent);
}
.wiki-brand__icon {
width: 1.85rem;
height: 1.85rem;
display: inline-flex;
align-items: center;
justify-content: center;
border: 0;
background: transparent;
box-shadow: none;
}
.wiki-brand__icon img {
width: 100%;
height: 100%;
display: block;
border-radius: 0;
object-fit: contain;
}
.wiki-brand__copy {
display: inline-flex;
flex-direction: column;
align-items: flex-start;
line-height: 1;
}
.wiki-brand__title {
font-family: 'Sora', sans-serif;
font-size: 1.43rem;
font-weight: 700;
letter-spacing: 0.02em;
color: var(--sl-color-white);
}
.wiki-brand__subtitle {
margin-top: 0.14rem;
font-family: 'Sora', sans-serif;
font-size: 0.56rem;
font-weight: 700;
letter-spacing: 0.28em;
color: var(--sl-color-gray-3);
}
.wiki-top-nav {
display: none;
gap: 0.45rem;
align-items: center;
}
.wiki-top-nav__link {
border: 1px solid transparent;
border-radius: 0.18rem;
padding: 0.36rem 0.74rem;
text-decoration: none;
color: var(--sl-color-gray-2);
font-size: 0.82rem;
font-family: 'Sora', sans-serif;
font-weight: 600;
letter-spacing: 0.01em;
transition: border-color 150ms ease, background 150ms ease, color 150ms ease;
}
.wiki-top-nav__link:hover {
border-color: color-mix(in srgb, var(--sl-color-accent) 28%, transparent);
background: color-mix(in srgb, var(--sl-color-accent-low) 65%, transparent);
color: var(--sl-color-white);
}
.right-group,
.social-icons {
gap: 1rem;
align-items: center;
}
.header-tools {
align-items: center;
gap: 0.5rem;
}
.theme-toggle-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.25rem;
height: 2.25rem;
border: 1px solid color-mix(in srgb, var(--sl-color-hairline) 78%, transparent);
border-radius: 50%;
background: color-mix(in srgb, var(--sl-color-bg-nav) 88%, transparent);
color: #2a5f4d;
box-shadow: 0 0 0 1px color-mix(in srgb, var(--sl-color-hairline) 28%, transparent);
transition: color 160ms ease, transform 160ms ease, background 160ms ease, border-color 160ms ease,
box-shadow 160ms ease;
}
.theme-toggle-btn:hover {
transform: translateY(-1px) scale(1.02);
border-color: color-mix(in srgb, var(--sl-color-accent) 46%, transparent);
box-shadow:
0 0 0 1px color-mix(in srgb, var(--sl-color-accent) 24%, transparent),
0 6px 14px color-mix(in srgb, var(--sl-color-accent) 22%, transparent);
}
.theme-toggle-btn svg {
width: 1.15rem;
height: 1.15rem;
stroke: currentColor;
stroke-width: 1.9;
stroke-linecap: round;
stroke-linejoin: round;
}
.theme-toggle-btn .icon-sun,
.theme-toggle-btn .icon-moon {
display: none;
}
:global(:root[data-theme='dark']) .theme-toggle-btn .icon-moon {
display: block;
}
:global(:root[data-theme='light']) .theme-toggle-btn .icon-sun {
display: block;
}
:global(:root[data-theme='dark']) .theme-toggle-btn {
color: #66f5df;
background: color-mix(in srgb, #0f1b2a 86%, transparent);
border-color: color-mix(in srgb, #2b4c5a 65%, transparent);
}
:global(:root[data-theme='light']) .theme-toggle-btn {
color: #2e6b57;
background: color-mix(in srgb, #f2f7ff 92%, transparent);
border-color: color-mix(in srgb, #b4c5db 72%, transparent);
}
.wiki-read-progress {
position: fixed;
inset-inline: 0;
top: calc(var(--sl-nav-height) + var(--sl-mobile-toc-height));
height: 2px;
z-index: calc(var(--sl-z-index-navbar) - 1);
pointer-events: none;
background: color-mix(in srgb, var(--sl-color-hairline) 65%, transparent);
overflow: hidden;
}
.wiki-read-progress__fill {
height: 100%;
width: 100%;
transform-origin: left center;
transform: scaleX(0);
background: linear-gradient(
90deg,
color-mix(in srgb, var(--wiki-purple-2) 88%, #ffffff),
color-mix(in srgb, var(--wiki-blue-2) 90%, #ffffff)
);
transition: transform 90ms linear;
}
.wiki-back-to-top {
position: fixed;
top: auto;
right: max(1.35rem, calc(env(safe-area-inset-right) + 0.8rem));
bottom: max(1.45rem, calc(env(safe-area-inset-bottom) + 0.7rem));
z-index: 30;
border: 1px solid color-mix(in srgb, var(--sl-color-accent) 74%, transparent);
border-radius: 999px;
background: linear-gradient(
140deg,
color-mix(in srgb, var(--wiki-purple-2) 74%, #101522),
color-mix(in srgb, var(--wiki-blue-2) 84%, #101522)
);
color: #f6f9ff;
width: 3.1rem;
height: 3.1rem;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
box-shadow:
0 0 0 1px hsl(214 88% 70% / 0.24),
0 0 24px hsl(217 100% 68% / 0.38),
0 0 42px hsl(221 100% 65% / 0.22);
opacity: 0;
visibility: hidden;
transform: translateY(8px) scale(0.96);
pointer-events: none;
transition: opacity 180ms ease, transform 180ms ease, border-color 180ms ease, box-shadow 180ms ease;
}
.wiki-back-to-top__icon {
width: 1.5rem;
height: 1.5rem;
stroke: currentColor;
stroke-width: 2.15;
stroke-linecap: round;
stroke-linejoin: round;
}
.wiki-back-to-top.is-visible {
opacity: 1;
visibility: visible;
transform: translateY(0) scale(1);
pointer-events: auto;
}
.wiki-back-to-top:hover {
border-color: color-mix(in srgb, #9ec4ff 80%, transparent);
box-shadow:
0 0 0 1px hsl(214 88% 70% / 0.35),
0 0 28px hsl(219 97% 70% / 0.44),
0 0 50px hsl(221 98% 68% / 0.27);
}
.social-icons::after {
content: '';
height: 2rem;
border-inline-end: 1px solid var(--sl-color-gray-5);
}
@media (min-width: 64rem) {
.wiki-top-nav {
display: inline-flex;
}
}
@media (min-width: 50rem) {
:global(:root[data-has-sidebar]) {
--__sidebar-pad: calc(2 * var(--sl-nav-pad-x));
}
:global(:root:not([data-has-toc])) {
--__toc-width: 0rem;
}
.wiki-header {
--__sidebar-width: max(0rem, var(--sl-content-inline-start, 0rem) - var(--sl-nav-pad-x));
--__main-column-fr: calc(
(
100% + var(--__sidebar-pad, 0rem) - var(--__toc-width, var(--sl-sidebar-width)) -
(2 * var(--__toc-width, var(--sl-nav-pad-x))) - var(--sl-content-inline-start, 0rem) -
var(--sl-content-width)
) / 2
);
display: grid;
grid-template-columns: minmax(
calc(var(--__sidebar-width) + max(0rem, var(--__main-column-fr) - var(--sl-nav-gap))),
auto
)
1fr auto;
align-content: center;
}
}
@media (max-width: 50rem) {
.wiki-brand {
padding: 0.14rem 0.2rem;
gap: 0.42rem;
}
.wiki-brand__icon {
width: 1.55rem;
height: 1.55rem;
}
.wiki-brand__title {
font-size: 1.08rem;
}
.wiki-brand__subtitle {
font-size: 0.46rem;
letter-spacing: 0.24em;
}
.wiki-back-to-top {
top: auto;
right: max(1rem, calc(env(safe-area-inset-right) + 0.52rem));
bottom: max(1.18rem, calc(env(safe-area-inset-bottom) + 0.58rem));
width: 2.85rem;
height: 2.85rem;
}
.wiki-back-to-top__icon {
width: 1.34rem;
height: 1.34rem;
}
}
}
</style>