aboutsummaryrefslogtreecommitdiffstats
path: root/startpage/startpage.css
diff options
context:
space:
mode:
Diffstat (limited to 'startpage/startpage.css')
-rw-r--r--startpage/startpage.css1892
1 files changed, 1892 insertions, 0 deletions
diff --git a/startpage/startpage.css b/startpage/startpage.css
new file mode 100644
index 0000000..307e9cc
--- /dev/null
+++ b/startpage/startpage.css
@@ -0,0 +1,1892 @@
+:root {
+ --bg: #000000;
+ --text: #8b0000;
+ --accent: #ff0000;
+ --gold: #8b0000;
+ --border: #2a1515;
+ --neon-green: #39ff14;
+ --neon-cyan: #ff1a1a;
+ --accent-cyan: #8b0000;
+ --accent-pink: #a00000;
+ --accent-magenta: #8b0000;
+ --font-mono: "JetBrains Mono", "IBM Plex Mono", "Fira Code", "Source Code Pro", ui-monospace, SFMono-Regular, "Cascadia Code", Menlo, Consolas, monospace;
+ --lh-body: 1.55;
+ --lh-comfort: 1.85;
+ --link-glow: 255, 0, 0;
+ --btn-glow: 139, 0, 0;
+ --radius: 4px;
+ /* Sharper edges for a retro feel */
+ --logo-size: clamp(80px, 10vw, 100px);
+ --fs-base: clamp(14px, 1.1vw, 17px);
+}
+
+* {
+ box-sizing: border-box;
+}
+
+/* site.css sets html,body{height:100%}, which clamps the page to one viewport
+ and makes the overflowing body scroll inside that box — a second scrollbar
+ next to the browser's. Let the page grow naturally; min-height keeps the
+ footer pinned to the bottom. */
+html,
+body {
+ height: auto;
+ min-height: 100vh;
+ min-height: 100dvh; /* dynamic vh: excludes mobile address bar so content isn't cut off */
+}
+
+body {
+ margin: 0;
+ background: var(--bg);
+ color: var(--text);
+ font: 400 var(--fs-base) var(--font-mono);
+ line-height: var(--lh-body);
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+ min-height: 100dvh;
+ position: relative;
+ /* Cyber grid + retro wallpaper */
+ background-image:
+ linear-gradient(rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0.72)),
+ linear-gradient(rgba(255, 0, 0, 0.03) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(255, 0, 0, 0.03) 1px, transparent 1px),
+ url('wallpaper.jpg');
+ background-size: cover, 28px 28px, 28px 28px, cover;
+ background-position: center, center, center, center;
+ background-attachment: fixed, fixed, fixed, fixed;
+ background-blend-mode: normal;
+}
+
+.crt-overlay {
+ pointer-events: none;
+ position: fixed;
+ inset: 0;
+ z-index: 9998;
+ background:
+ repeating-linear-gradient(
+ 0deg,
+ rgba(0, 0, 0, 0.12) 0px,
+ rgba(0, 0, 0, 0.12) 1px,
+ transparent 1px,
+ transparent 3px
+ );
+ opacity: 0.35;
+ mix-blend-mode: multiply;
+}
+
+body::after {
+ content: '';
+ pointer-events: none;
+ position: fixed;
+ inset: 0;
+ z-index: 9997;
+ background: radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, 0.45) 100%);
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .crt-overlay { display: none; }
+ body.startpage-booting .boot-overlay { display: none !important; }
+ body.startpage-ready { animation: none; }
+ .boot-log .boot-cursor { animation: none; }
+}
+
+/* No scrollbars at any resolution: the overlay never scrolls, and the page
+ behind it is locked while booting. .boot-log is scaled down by JS
+ (fitBootLog) whenever it would exceed the viewport, so nothing is clipped. */
+html:has(> body.startpage-booting),
+body.startpage-booting {
+ overflow: hidden;
+}
+
+.boot-overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 10000;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ overscroll-behavior: none;
+ background: #000;
+ padding: 2rem;
+ transition: opacity 0.35s ease;
+ /* Failsafe: if JS errors, don't trap users on a black screen */
+ animation: boot-dismiss-failsafe 0s 3s forwards;
+}
+
+/* Short/narrow viewports: give the log the padding back as usable room so the
+ auto-fit scale stays readable instead of shrinking to fit 2rem gutters. */
+@media (max-height: 600px), (max-width: 600px) {
+ .boot-overlay { padding: 0.75rem; }
+}
+
+.boot-overlay.boot-fade {
+ opacity: 0;
+ pointer-events: none;
+}
+
+.boot-overlay[hidden] {
+ display: none !important;
+ animation: none;
+}
+
+@keyframes boot-dismiss-failsafe {
+ to {
+ opacity: 0;
+ visibility: hidden;
+ pointer-events: none;
+ }
+}
+
+.boot-log {
+ margin: auto;
+ max-width: 42rem;
+ width: 100%;
+ color: #f2ca30;
+ font: inherit;
+ line-height: 1.6;
+ /* Scale set by JS. Origin is the top edge: an over-tall flex item with
+ margin:auto is start-aligned, so scaling from the centre would leave the
+ shrunk box hanging past the bottom. Below scale 1 the log is centered by
+ flex anyway, so the origin only matters while shrinking. */
+ transform-origin: center top;
+}
+
+.boot-title {
+ color: #f2ca30;
+ margin-bottom: 0.9rem;
+}
+
+.boot-line {
+ white-space: pre-wrap;
+}
+
+.boot-login {
+ margin-top: 0.9rem;
+}
+
+.boot-log .boot-cursor {
+ color: #f2ca30;
+ animation: cursor-blink 0.9s step-end infinite;
+}
+
+body.startpage-ready {
+ animation: boot-reveal 0.45s ease;
+}
+
+@keyframes boot-reveal {
+ from { opacity: 0.55; }
+}
+
+body.startpage-ready .search-section h2 {
+ animation: cursor-blink 1.1s step-end infinite;
+}
+
+@keyframes cursor-blink {
+ 50% { opacity: 0.55; }
+}
+
+a {
+ color: var(--accent);
+ text-decoration: none;
+ transition: 0.1s;
+}
+
+a:hover {
+ background: var(--accent);
+ color: #000 !important;
+}
+
+/* Layout Overrides for Unified Header */
+.header-inner {
+ max-width: none !important;
+ margin: 0 !important;
+ padding-left: 20px !important;
+ padding-right: 20px !important;
+}
+
+main,
+footer {
+ max-width: none !important;
+ margin: 0 !important;
+ padding-left: 20px;
+ padding-right: 20px;
+}
+
+/* Search Section: Left Aligned */
+.search-section {
+ padding: 10px 0 40px;
+ text-align: center;
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+
+.top-left-links {
+ position: absolute;
+ top: 10px;
+ left: 20px;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 5px;
+ text-align: left;
+ z-index: 1;
+ width: max-content;
+}
+
+/* Windows-style cascading right-click menu for the Sports links */
+.ctx-menu,
+.ctx-menu ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+.ctx-parent {
+ position: relative;
+}
+
+.ctx-trigger {
+ cursor: pointer;
+ user-select: none;
+}
+
+/* Flyout panels: hidden until parent opened */
+.ctx-flyout {
+ min-width: 170px;
+ display: none;
+ flex-direction: column;
+ padding: 4px;
+ background: #0a0a0a;
+ border: 1px solid var(--accent);
+ border-radius: 4px;
+ box-shadow: 0 0 12px rgba(255, 0, 0, 0.4);
+ z-index: 60;
+ max-height: 80vh;
+ overflow-y: auto;
+ /* scroll works, scrollbar hidden */
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+}
+
+.ctx-flyout::-webkit-scrollbar {
+ display: none;
+}
+
+/* Root dropdown (the category list under "Sports") drops straight down */
+.ctx-root > .ctx-parent > .ctx-flyout {
+ position: absolute;
+ top: calc(100% + 4px);
+ left: 0;
+}
+
+/* Top-left dropdown (Sports) flies out to the RIGHT of the trigger */
+.top-left-links .ctx-root > .ctx-parent > .ctx-flyout {
+ top: 0;
+ left: calc(100% + 6px);
+}
+
+/* Top-right dropdown (Links) flies out to the LEFT of the trigger. */
+.top-right-links .ctx-root > .ctx-parent > .ctx-flyout {
+ top: 0;
+ left: auto;
+ right: calc(100% + 6px);
+}
+
+/* Category link lists float free (fixed) so the scrolling root menu can't clip them;
+ exact left/top set by JS so they cascade to the right and flip near screen edges */
+.ctx-root .ctx-flyout .ctx-flyout {
+ position: fixed;
+ top: 0;
+ left: 0;
+}
+
+.ctx-parent.open > .ctx-flyout {
+ display: flex;
+}
+
+/* Individual menu rows */
+.ctx-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 14px;
+ padding: 4px 10px;
+ font-size: 0.95rem;
+ font-weight: bold;
+ white-space: nowrap;
+ color: var(--accent);
+ text-decoration: none;
+ border-radius: 2px;
+ cursor: pointer;
+}
+
+.ctx-item:hover,
+.ctx-parent.open > .ctx-item {
+ background: var(--accent);
+ color: #000 !important;
+}
+
+/* Submenu arrow indicator */
+.ctx-has-sub::after {
+ content: '▶';
+ font-size: 0.8em;
+ opacity: 0.7;
+ display: inline-block;
+ transition: transform 0.2s ease;
+}
+
+/* Open submenu: right-pointing arrow rotates 90deg to point down */
+.ctx-parent.open > .ctx-has-sub::after {
+ transform: rotate(90deg);
+}
+
+/* Both menus use a crisp CSS border triangle instead of the ◀ / ▶ glyphs
+ (the fallback font renders those diagonally). Rotates 90deg down on open. */
+.top-left-links .ctx-arrow,
+.top-left-links .ctx-has-sub::after,
+.top-right-links .ctx-arrow,
+.top-right-links .ctx-has-sub::after {
+ content: '';
+ display: inline-block;
+ width: 0;
+ height: 0;
+ border-top: 8px solid transparent;
+ border-bottom: 8px solid transparent;
+ opacity: 0.85;
+ transform: none;
+ transition: transform 0.2s ease;
+ vertical-align: middle;
+}
+
+/* Top-right triangles point left */
+.top-right-links .ctx-arrow,
+.top-right-links .ctx-has-sub::after {
+ border-right: 11px solid currentColor;
+ border-left: 0;
+}
+
+/* Top-left triangles point right */
+.top-left-links .ctx-arrow,
+.top-left-links .ctx-has-sub::after {
+ border-left: 11px solid currentColor;
+ border-right: 0;
+}
+
+/* Trigger arrows (Sports / Google Services / Radio's) — bigger, matching the old glyph */
+.top-left-links .ctx-arrow,
+.top-right-links .ctx-arrow {
+ border-top-width: 9px;
+ border-bottom-width: 9px;
+}
+.top-right-links .ctx-arrow { margin-right: 0.4em; border-right-width: 12px; }
+.top-left-links .ctx-arrow { margin-left: 0.4em; border-left-width: 12px; }
+.top-left-links .ctx-has-sub::after { margin-left: 0.4em; }
+
+/* Top-right submenus cascade LEFT, so their arrow sits to the LEFT of the
+ label (before it), with the whole row packed to the left edge. */
+.top-right-links .ctx-has-sub {
+ flex-direction: row-reverse;
+ justify-content: flex-end;
+}
+.top-right-links .ctx-has-sub::after {
+ margin-left: 0;
+ margin-right: 0.4em;
+}
+
+/* On open the left-pointing (top-right) triangle rotates down to the bottom */
+.top-right-links .ctx-parent.open > .ctx-has-sub::after {
+ transform: rotate(-90deg);
+}
+
+/* Trigger arrows rotate to point down on open; direction depends on which way they point */
+.ctx-arrow {
+ display: inline-block;
+ transition: transform 0.2s ease;
+}
+
+/* Top-left trigger arrow points right (▶), rotates +90 -> down on open */
+.top-left-links .ctx-parent.open > .ctx-trigger .ctx-arrow {
+ transform: rotate(90deg);
+}
+
+/* Top-right trigger arrow rotates 90deg down (left -> bottom) on open */
+.top-right-links .ctx-parent.open > .ctx-trigger .ctx-arrow {
+ transform: rotate(-90deg);
+}
+
+.search-link {
+ font-size: 1.1rem;
+ font-weight: bold;
+ text-decoration: none;
+ transition: 0.1s;
+ color: var(--accent);
+}
+
+.top-right-links {
+ position: absolute;
+ top: 10px;
+ right: 20px;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 5px;
+ z-index: 1;
+ width: max-content;
+}
+
+.search-link:hover {
+ background: var(--accent);
+ color: #000 !important;
+}
+
+body a:hover,
+body a:focus-visible {
+ color: #ffd0d0;
+}
+
+.search-section h2 {
+ color: var(--accent);
+ margin-bottom: 15px;
+ font-size: 1.2rem;
+ font-weight: bold;
+}
+
+.search-section h2 a {
+ color: inherit;
+ text-decoration: none;
+ transition: color 0.1s;
+}
+
+.search-section h2 a:hover,
+.search-section h2 a:focus-visible {
+ color: var(--accent) !important;
+ background: transparent !important;
+ text-shadow:
+ 0 0 4px rgba(255, 0, 0, .95),
+ 0 0 12px rgba(139, 0, 0, .75),
+ 0 0 24px rgba(139, 0, 0, .45);
+ box-shadow:
+ 0 0 0 1px rgba(139, 0, 0, .55),
+ 0 0 10px rgba(255, 0, 0, .45),
+ 0 0 24px -4px rgba(139, 0, 0, .4);
+}
+
+/* Plain destination links stacked above the engine title; same look as it. */
+.search-section h2.quick-search-title {
+ margin-bottom: 6px;
+}
+
+/* First quick link sits on the section's top line; the rest stack under it. */
+.search-section h2.quick-search-title:first-of-type {
+ margin-top: 0;
+}
+
+.search-box {
+ width: 100%;
+ max-width: 584px;
+ background: #000;
+ border: 1px solid var(--accent);
+ padding: 12px;
+ color: var(--accent);
+ font-family: inherit;
+ outline: none;
+ border-radius: var(--radius);
+ transition: box-shadow 0.2s;
+ margin: 0 auto;
+ display: block;
+}
+
+.search-box:focus {
+ box-shadow: 0 0 10px var(--accent);
+}
+
+/* Skeleton sets input[type=...]{font-size:var(--fs-base)} (specificity 0,1,1) and
+ loads after this file, so it wins over plain .search-box. On mobile --fs-base
+ clamps to 14px, which makes iOS Safari auto-zoom (and reflow) on focus. Force
+ >=16px on the search inputs to stop that. !important needed to beat Skeleton. */
+input.search-box { font-size: 16px !important; }
+
+/* Unified search with engine toggle */
+.unified-search {
+ display: flex;
+ align-items: stretch;
+ width: 100%;
+ max-width: 584px;
+ margin: 0 auto;
+ border: 1px solid var(--accent);
+ border-radius: var(--radius);
+ background: #000;
+ position: relative;
+}
+
+.unified-search:focus-within {
+ box-shadow: 0 0 10px var(--accent);
+}
+
+.search-engine-picker {
+ position: relative;
+ display: flex;
+}
+
+.search-engine-toggle {
+ background: #000;
+ color: var(--accent);
+ border: none;
+ border-right: 1px solid var(--accent);
+ font-family: inherit;
+ font-weight: bold;
+ font-size: 1rem;
+ padding: 0 14px;
+ cursor: pointer;
+ min-width: 64px;
+ transition: 0.15s;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+}
+
+.search-engine-toggle:hover {
+ background: var(--accent);
+ color: #000;
+}
+
+.search-engine-caret {
+ font-size: 0.7rem;
+ opacity: 0.8;
+}
+
+.search-engine-menu {
+ position: absolute;
+ top: calc(100% + 2px);
+ left: 0;
+ min-width: 180px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ background: #000;
+ border: 1px solid var(--accent);
+ border-radius: var(--radius);
+ z-index: 50;
+ text-align: left;
+ box-shadow: 0 0 10px rgba(255, 0, 0, 0.4);
+}
+
+.search-engine-menu[hidden] {
+ display: none;
+}
+
+.search-engine-menu li {
+ padding: 8px 12px;
+ color: var(--accent);
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 0.9rem;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ border-bottom: 1px solid var(--border);
+}
+
+.search-engine-menu li:last-child {
+ border-bottom: none;
+}
+
+.search-engine-menu li:hover,
+.search-engine-menu li[aria-selected="true"] {
+ background: var(--accent);
+ color: #000;
+}
+
+.search-engine-menu .engine-icon {
+ font-weight: bold;
+ min-width: 28px;
+ text-align: center;
+}
+
+.unified-search .unified-search-input {
+ border: none;
+ border-radius: 0;
+ max-width: none;
+ flex: 1;
+ width: auto;
+ margin: 0;
+ text-align: center;
+}
+
+.unified-search .unified-search-input:focus {
+ box-shadow: none;
+}
+
+/* kill ugly native search clear (webkit) + edge clear, use custom .search-clear */
+.unified-search .unified-search-input::-webkit-search-cancel-button,
+.unified-search .unified-search-input::-webkit-search-decoration {
+ -webkit-appearance: none;
+ appearance: none;
+ display: none;
+}
+.unified-search .unified-search-input::-ms-clear,
+.unified-search .unified-search-input::-ms-reveal {
+ display: none;
+ width: 0;
+ height: 0;
+}
+
+.search-engine-spacer {
+ min-width: 64px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.search-clear {
+ background: #8b0000;
+ border: 1px solid #8b0000;
+ cursor: pointer;
+ padding: 0;
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ opacity: 1;
+ transition: background 0.15s, border-color 0.15s, transform 0.15s;
+}
+
+.search-clear svg {
+ display: block;
+ stroke: #ff5555 !important;
+}
+
+.search-clear svg line {
+ stroke: #ff5555 !important;
+}
+
+.search-clear:hover {
+ background: #ff0000;
+ border-color: #ff0000;
+ transform: scale(1.05);
+}
+
+.search-clear:hover svg,
+.search-clear:hover svg line {
+ stroke: #8b0000 !important;
+}
+
+.search-clear:active {
+ transform: scale(0.92);
+}
+
+.search-clear:focus-visible {
+ outline: 1px solid var(--accent);
+ outline-offset: 1px;
+ opacity: 1;
+}
+
+.search-clear[hidden] {
+ display: none;
+}
+
+.clock-container {
+ margin-top: 15px;
+ color: var(--text);
+ font-size: 0.9rem;
+ opacity: 0.8;
+ text-align: center;
+}
+
+.clock-time {
+ color: var(--accent);
+ letter-spacing: 1px;
+}
+
+/* Grid Layout: Left Aligned */
+.grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
+ gap: 24px;
+ padding: 0;
+}
+
+.card {
+ border: 1px solid var(--border);
+ background: #050505;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ transition: transform .2s ease, border-color .2s ease, box-shadow .25s ease;
+ min-width: 0;
+ overflow: hidden;
+ border-radius: var(--radius);
+ box-shadow:
+ 0 0 0 1px rgba(255, 0, 0, 0.08),
+ 0 4px 18px rgba(0, 0, 0, 0.45);
+}
+
+.card:hover {
+ border-color: var(--accent);
+ transform: translateY(-2px) scale(1.01);
+ box-shadow:
+ 0 0 0 1px rgba(255, 0, 0, 0.45),
+ 0 0 14px rgba(255, 0, 0, 0.25),
+ 0 8px 24px rgba(0, 0, 0, 0.55);
+}
+
+.card-titlebar {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 8px 12px;
+ background: linear-gradient(180deg, #1a0000, #0a0000);
+ border-bottom: 1px solid var(--border);
+ font-weight: 700;
+ font-size: 0.85rem;
+ letter-spacing: 0.3px;
+ text-transform: uppercase;
+}
+
+.card-dots {
+ display: inline-flex;
+ gap: 5px;
+}
+
+.card-dots span {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: #333;
+ border: 1px solid #555;
+}
+
+.card-dots span:nth-child(1) { background: #ff5f57; border-color: #cc4a44; }
+.card-dots span:nth-child(2) { background: #febc2e; border-color: #c99524; }
+.card-dots span:nth-child(3) { background: #28c840; border-color: #1f9a32; }
+
+.card-title {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ color: var(--accent);
+ text-shadow: 0 0 6px rgba(255, 0, 0, 0.35);
+}
+
+.card-body {
+ padding: 15px 15px 20px;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+}
+
+.card.hidden {
+ display: none !important;
+}
+
+.card-filter-wrap {
+ width: 100%;
+ max-width: 584px;
+ margin: 10px auto 0;
+ position: relative;
+}
+
+.card-filter {
+ margin: 0;
+ text-align: center;
+ font-size: 0.95rem;
+ padding: 10px 12px;
+ padding-right: 55px;
+ border-radius: var(--radius);
+ /* always-on active glow, matches focused search look even when not focused */
+ box-shadow: 0 0 10px var(--accent);
+}
+
+/* kill native search clear for the card filter too */
+.card-filter::-webkit-search-cancel-button,
+.card-filter::-webkit-search-decoration {
+ -webkit-appearance: none;
+ appearance: none;
+ display: none;
+}
+.card-filter::-ms-clear {
+ display: none;
+}
+
+.filter-count {
+ position: absolute;
+ right: 12px;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 0.75rem;
+ color: #666;
+ white-space: nowrap;
+ pointer-events: none;
+ opacity: 0.7;
+}
+
+body.light-mode .filter-count {
+ color: #8b0000;
+}
+
+.card .thumb {
+ width: 100%;
+ height: 70px;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ margin-bottom: 15px;
+ opacity: 0.85;
+ transition: opacity .2s ease, transform .2s ease;
+}
+
+.card:hover .thumb {
+ opacity: 1;
+ transform: scale(1.03);
+}
+
+.card img {
+ max-width: 80px;
+ max-height: 100%;
+ object-fit: contain;
+}
+
+.card-links {
+ font-size: 0.95rem;
+ line-height: 1.6;
+ border-top: 1px solid var(--border);
+ width: 100%;
+ padding-top: 16px;
+ text-align: left;
+ display: grid;
+ grid-template-columns: 1fr;
+ align-items: flex-start;
+ gap: 12px;
+}
+
+.card-links a {
+ display: inline-block;
+ width: auto;
+ max-width: 100%;
+ /* Dotted labels ("wiki.realmofespionage") are one unbreakable token: their
+ min-content width sets the grid track and pushes the whole link column
+ past the card's right edge on narrow columns. Let them wrap. */
+ min-width: 0;
+ overflow-wrap: anywhere;
+ padding: 2px 6px 4px;
+ line-height: 1.45;
+ border-radius: 2px;
+ background: #0a0a0a;
+ text-shadow:
+ 0 0 4px rgba(255, 0, 0, .9),
+ 0 0 10px rgba(255, 0, 0, .5);
+ box-shadow:
+ 0 0 0 1px rgba(255, 0, 0, .9),
+ 0 0 6px rgba(255, 0, 0, .35);
+ transition: transform .2s ease, box-shadow .25s ease, background .2s ease;
+}
+
+.card-links a:hover,
+.card-links a:focus-visible {
+ transform: translateY(-1px) scale(1.02);
+ background: color-mix(in srgb, var(--accent) 12%, #0a0a0a);
+ color: #ffd0d0;
+ box-shadow:
+ 0 0 0 1px rgba(var(--link-glow), .65),
+ 0 0 12px rgba(var(--link-glow), .4);
+}
+
+footer {
+ border-top: 1px solid var(--border);
+ margin-top: auto;
+ color: #555;
+}
+
+/* Last.fm now-playing bar */
+.lastfm-widget {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 8px 20px;
+ margin-top: 12px;
+ border-bottom: 1px solid var(--border);
+ background: #050505;
+ font-size: 0.8rem;
+ color: #888;
+ flex-wrap: wrap;
+}
+
+
+.lastfm-label {
+ color: #d51007;
+}
+
+#lastfm-status {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.lastfm-profile {
+ color: #d51007;
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+.lastfm-profile:hover {
+ background: #d51007;
+ color: #000 !important;
+}
+
+/* Phones / touch devices: bigger text, easier tap target, stacked layout */
+@media (max-width: 600px), (hover: none) and (pointer: coarse) and (max-width: 820px) {
+
+ .lastfm-widget {
+ flex-direction: column;
+ align-items: stretch;
+ gap: 8px;
+ padding: 12px 16px;
+ font-size: 0.95rem;
+ text-align: center;
+ }
+
+ .lastfm-label {
+ font-size: 1.2rem;
+ }
+
+ #lastfm-status {
+ white-space: normal;
+ overflow: visible;
+ text-overflow: clip;
+ flex: none;
+ line-height: 1.4;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 2px;
+ word-break: break-word;
+ overflow-wrap: anywhere;
+ }
+
+ #lastfm-status .lastfm-prefix,
+ #lastfm-status .lastfm-track-name,
+ #lastfm-status .lastfm-track-artist {
+ display: block;
+ max-width: 100%;
+ }
+
+ #lastfm-status .lastfm-track-name {
+ font-weight: bold;
+ }
+
+ #lastfm-status .lastfm-sep {
+ display: none;
+ }
+
+ #lastfm-status .lastfm-track-artist::before {
+ content: '— ';
+ opacity: 0.6;
+ }
+
+ .lastfm-profile {
+ align-self: center;
+ padding: 10px 18px;
+ min-height: 44px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid #d51007;
+ border-radius: 4px;
+ font-weight: bold;
+ }
+}
+
+
+
+/* Persistent red glow halo on the link groups (visible on desktop and touch) */
+.top-left-links .search-link,
+.top-right-links .search-link {
+ display: inline-block;
+ padding: 1px 4px;
+ border-radius: 2px;
+ text-shadow:
+ 0 0 4px rgba(255, 0, 0, .9),
+ 0 0 12px rgba(139, 0, 0, .6),
+ 0 0 24px rgba(139, 0, 0, .35);
+ box-shadow:
+ 0 0 0 1px rgba(255, 0, 0, .5),
+ 0 0 10px rgba(139, 0, 0, .55),
+ 0 0 24px -4px rgba(139, 0, 0, .4);
+}
+
+/* Phone-only: stack the link groups vertically so they don't overlap the search */
+@media (max-width: 600px), (hover: none) and (pointer: coarse) and (max-width: 820px) {
+ .search-section {
+ padding-top: 20px;
+ }
+
+ .top-left-links,
+ .top-right-links {
+ position: static;
+ flex-direction: column;
+ align-items: center;
+ gap: 6px;
+ padding: 0 10px;
+ margin-bottom: 20px;
+ text-align: center;
+ z-index: auto;
+ width: 100%;
+ }
+
+ .top-left-links .search-link,
+ .top-right-links .search-link {
+ font-size: 0.95rem;
+ }
+}
+
+@media (max-width: 850px) {
+
+ header,
+ main,
+ footer {
+ padding: 20px;
+ }
+
+ header {
+ flex-direction: column;
+ }
+
+ .nav-columns {
+ width: 100%;
+ }
+
+ .age-modal-content {
+ margin: 20px;
+ padding: 20px;
+ }
+
+ .search-section {
+ padding: 20px 0 20px 0;
+ }
+
+ .search-box {
+ padding: 8px 10px;
+ font-size: 16px; /* >=16px: prevent iOS Safari auto-zoom on focus */
+ }
+
+ .unified-search {
+ max-width: 100%;
+ }
+
+ .card-filter-wrap {
+ max-width: 100%;
+ }
+
+ .search-engine-toggle {
+ min-width: 48px;
+ padding: 0 8px;
+ font-size: 0.9rem;
+ }
+
+ .unified-search .unified-search-input {
+ min-width: 0;
+ }
+}
+
+
+
+/* Light mode: snow/ice startpage theme */
+body.light-mode {
+ --bg: #fff8f1;
+ --surface: #fffdf9;
+ --text: #1a2a33;
+ --ink: #1a2a33;
+ --muted: #5c6b73;
+ --accent: #8b0000;
+ --gold: #8b0000;
+ --border: #d9c9b8;
+ --shadow: rgba(92, 72, 52, .12);
+ --link-glow: 139, 0, 0;
+ background: #fff8f1 !important;
+ background-image: none !important;
+ color: var(--text);
+}
+
+body.light-mode main,
+body.light-mode footer,
+body.light-mode .search-section,
+body.light-mode .grid {
+ background: #fff8f1;
+}
+
+body.light-mode .card,
+body.light-mode .lastfm-widget,
+body.light-mode .ctx-flyout,
+body.light-mode .unified-search,
+body.light-mode .search-box,
+body.light-mode .search-engine-toggle,
+body.light-mode .search-engine-menu,
+body.light-mode .unified-search .unified-search-input,
+body.light-mode .age-modal-content,
+body.light-mode .age-modal-btn,
+body.light-mode .modal-search-input,
+body.light-mode .modal-search-button {
+ background: #ffffff !important;
+ color: var(--text) !important;
+ border-color: var(--border) !important;
+}
+
+body.light-mode .card-links,
+body.light-mode .search-engine-toggle,
+body.light-mode .ctx-flyout,
+body.light-mode .search-engine-menu li,
+body.light-mode footer,
+body.light-mode .lastfm-widget,
+body.light-mode .modal-search {
+ border-color: var(--border) !important;
+}
+
+body.light-mode .top-left-links .search-link,
+body.light-mode .top-right-links .search-link {
+ color: var(--accent);
+ text-shadow: none;
+ box-shadow: none;
+}
+
+body.light-mode .card {
+ box-shadow:
+ 0 0 0 1px rgba(255, 255, 255, .95),
+ 0 0 16px rgba(139, 0, 0, .18),
+ 0 0 34px rgba(255, 255, 255, .88);
+}
+
+body.light-mode .card-links a {
+ background: #fff4f4;
+ color: var(--accent);
+ text-shadow:
+ 0 0 3px rgba(255, 255, 255, 1),
+ 0 0 10px rgba(255, 255, 255, .9),
+ 0 0 18px rgba(139, 0, 0, .28);
+ box-shadow:
+ 0 0 0 1px rgba(255, 255, 255, .95),
+ 0 0 10px rgba(255, 255, 255, .9),
+ 0 0 20px -4px rgba(139, 0, 0, .36);
+}
+
+body.light-mode .ctx-flyout,
+body.light-mode .search-engine-menu {
+ box-shadow: 0 8px 22px var(--shadow);
+}
+
+body.light-mode .ctx-item,
+body.light-mode .search-engine-menu li {
+ color: var(--text);
+ text-shadow: none;
+}
+
+body.light-mode .ctx-parent.open > .ctx-item {
+ background: var(--accent);
+ color: #ffffff !important;
+}
+
+body.light-mode .search-section h2,
+body.light-mode .search-section h2 a,
+body.light-mode .clock-time,
+body.light-mode .lastfm-label,
+body.light-mode .lastfm-profile,
+body.light-mode .age-modal-content h2 {
+ color: var(--accent);
+}
+
+body.light-mode .clock-container,
+body.light-mode .lastfm-widget,
+body.light-mode footer {
+ color: var(--muted);
+}
+
+body.light-mode .card:hover,
+body.light-mode .unified-search:focus-within,
+body.light-mode .search-box:focus {
+ border-color: var(--accent);
+}
+
+body.light-mode .card:hover {
+ box-shadow:
+ 0 0 0 1px rgba(255, 255, 255, 1),
+ 0 0 18px rgba(139, 0, 0, .32),
+ 0 0 42px rgba(255, 255, 255, .95);
+}
+
+body.light-mode .search-engine-menu {
+ box-shadow: 0 8px 22px var(--shadow);
+}
+
+body.light-mode button.search-clear {
+ background: #f8e8e8 !important;
+ border-color: var(--border) !important;
+}
+
+body.light-mode .search-clear svg,
+body.light-mode .search-clear svg line {
+ stroke: var(--accent) !important;
+}
+
+body.light-mode button.search-clear:hover {
+ background: var(--accent) !important;
+ border-color: var(--accent) !important;
+}
+
+body.light-mode .search-clear:hover svg,
+body.light-mode .search-clear:hover svg line {
+ stroke: #ffffff !important;
+}
+
+body.light-mode a:hover,
+body.light-mode .search-link:hover,
+body.light-mode .ctx-item:hover,
+body.light-mode .search-engine-toggle:hover,
+body.light-mode .search-engine-menu li:hover,
+body.light-mode .search-engine-menu li[aria-selected="true"],
+body.light-mode .lastfm-profile:hover,
+body.light-mode .card-links a:hover,
+body.light-mode .age-modal-btn:hover,
+body.light-mode .age-modal-content form button:hover {
+ background: var(--accent) !important;
+ color: #ffffff !important;
+ border-color: var(--accent) !important;
+ text-shadow: none;
+}
+
+body.light-mode .age-modal {
+ background: rgba(255, 248, 241, 0.92);
+}
+
+body.light-mode .age-modal-btn.deny:hover {
+ background: #555 !important;
+ border-color: #555 !important;
+ color: #ffffff !important;
+}
+
+body .site-header .brand-text strong,
+body .site-header .brand-text span,
+body .site-header .header-button,
+body .site-header #menu-toggle,
+body .site-header nav.site-nav a,
+body .site-header .lang-menu a {
+ color: var(--accent);
+}
+
+/* ---------------------------------------------------------------------------
+ Mobile / touch: the desktop context menus cascade as absolute/fixed flyouts
+ that run off the right edge and below the viewport. On small / touch screens
+ render every flyout in-flow instead: full-width, stacked under its trigger,
+ nested levels indented (accordion). Kills all overflow. !important is needed
+ to override the inline left/top the JS (positionFlyout) sets and the fixed
+ positioning from the base rules.
+ --------------------------------------------------------------------------- */
+@media (max-width: 600px), (hover: none) and (pointer: coarse) and (max-width: 820px) {
+ .ctx-menu .ctx-flyout {
+ position: static !important;
+ inset: auto !important;
+ left: auto !important;
+ top: auto !important;
+ right: auto !important;
+ width: 100% !important;
+ min-width: 0 !important;
+ max-width: 100% !important;
+ max-height: none !important;
+ box-sizing: border-box;
+ margin: 4px 0;
+ box-shadow: none;
+ overflow: visible !important;
+ }
+
+ /* indent + accent rule on nested submenus so the hierarchy reads clearly */
+ .ctx-menu .ctx-flyout .ctx-flyout {
+ margin: 4px 0 4px 14px;
+ border-left: 2px solid var(--accent);
+ }
+
+ /* left-align rows and give finger-friendly tap targets */
+ .ctx-menu .ctx-item {
+ justify-content: flex-start;
+ padding: 10px 12px;
+ }
+
+ /* Mobile uses a distinct chevron (❯) that rotates down on open, instead of
+ the desktop filled triangles. Applies to both submenu arrows and the
+ top-level trigger arrows (Sports / Google Services / Radio's). */
+ .ctx-menu .ctx-has-sub::after {
+ content: '❯';
+ transform: rotate(0deg);
+ transition: transform 0.2s ease;
+ }
+ .ctx-menu .ctx-parent.open > .ctx-has-sub::after {
+ transform: rotate(90deg);
+ }
+
+ /* Trigger arrows: hide the desktop glyph (◀ / ▶) and show the same chevron,
+ rotating down on open. */
+ .ctx-menu .ctx-arrow { font-size: 0; }
+ .ctx-menu .ctx-arrow::after {
+ content: '❯';
+ font-size: 1rem;
+ display: inline-block;
+ transition: transform 0.2s ease;
+ }
+ .ctx-menu .ctx-parent.open > .ctx-trigger .ctx-arrow {
+ transform: none;
+ }
+ .ctx-menu .ctx-parent.open > .ctx-trigger .ctx-arrow::after {
+ transform: rotate(90deg);
+ }
+
+ /* Drop the desktop triangles on mobile; the chevron (❯) is used instead */
+ .top-left-links .ctx-arrow,
+ .top-left-links .ctx-has-sub::after,
+ .top-right-links .ctx-arrow,
+ .top-right-links .ctx-has-sub::after {
+ border: 0;
+ width: auto;
+ height: auto;
+ margin: 0;
+ }
+ .top-left-links .ctx-has-sub::after,
+ .top-right-links .ctx-has-sub::after { content: '❯'; }
+ /* Mobile accordion: keep chevron on the right (undo desktop left-flip) */
+ .top-right-links .ctx-has-sub {
+ flex-direction: row;
+ justify-content: space-between;
+ }
+}
+
+/* Comfortable line spacing toggle for long link lists */
+.comfort-toggle {
+ margin-top: 12px;
+ padding: 6px 12px;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ background: #111;
+ color: var(--accent);
+ font: inherit;
+ font-size: 0.82rem;
+ cursor: pointer;
+ transition: background .15s, color .15s, border-color .15s, box-shadow .2s;
+}
+
+.comfort-toggle:hover,
+.comfort-toggle:focus-visible {
+ background: var(--accent);
+ color: #000;
+ outline: none;
+}
+
+.comfort-toggle[aria-pressed="true"] {
+ border-color: var(--neon-green);
+ color: var(--neon-green);
+ box-shadow: 0 0 10px rgba(57, 255, 20, .25);
+}
+
+body.startpage-comfort,
+body.comfort-spacing {
+ line-height: var(--lh-comfort);
+}
+
+body.startpage-comfort .card-body,
+body.startpage-comfort .clock-container,
+body.startpage-comfort .lastfm-widget {
+ line-height: var(--lh-comfort);
+}
+
+body.startpage-comfort .card-links {
+ line-height: var(--lh-comfort);
+ gap: 22px;
+}
+
+body.startpage-comfort .card-links a {
+ line-height: 1.7;
+ padding: 4px 8px 6px;
+}
+
+.search-section h2 {
+ font-weight: 800;
+ position: relative;
+}
+
+.search-section h2::after {
+ content: '';
+ display: block;
+ width: 2.5rem;
+ height: 2px;
+ margin: 6px auto 0;
+ border-radius: 2px;
+ background: linear-gradient(90deg, #8b0000, var(--accent));
+ box-shadow: 0 0 8px color-mix(in srgb, var(--accent) 45%, transparent);
+ animation: sp-neon-pulse 3.5s ease-in-out infinite;
+}
+
+@keyframes sp-neon-pulse {
+ 50% {
+ box-shadow:
+ 0 0 10px color-mix(in srgb, var(--accent) 50%, transparent),
+ 0 0 18px color-mix(in srgb, #8b0000 25%, transparent);
+ }
+}
+
+body.light-mode .comfort-toggle {
+ background: #fff8f1;
+ color: #8b0000;
+ border-color: #e8c8c8;
+}
+
+body.light-mode .comfort-toggle:hover {
+ background: #8b0000;
+ color: #fff;
+}
+
+body.light-mode .comfort-toggle[aria-pressed="true"] {
+ color: #5a0000;
+ border-color: #8b0000;
+ box-shadow: 0 0 10px rgba(139, 0, 0, .2);
+}
+
+/* Konaste / BEMANI PC maintenance status card (under the Last.fm widget) */
+.konaste-status {
+ margin: 12px 20px 0;
+ padding: 12px 16px;
+ border: 1px solid var(--border);
+ border-radius: 4px;
+ background: #050505;
+ font-size: 0.8rem;
+ color: #888;
+}
+
+.konaste-head {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 10px;
+ flex-wrap: wrap;
+ margin-bottom: 8px;
+ border-bottom: 1px solid var(--border);
+ padding-bottom: 6px;
+}
+
+.konaste-title {
+ margin: 0;
+ font-size: 0.85rem;
+ color: var(--accent);
+ letter-spacing: 0.03em;
+}
+
+.konaste-updated { color: #666; }
+
+.konaste-clock { color: #666; }
+
+.konaste-clock-time {
+ color: var(--neon-cyan);
+ font-variant-numeric: tabular-nums;
+ letter-spacing: 0.02em;
+}
+
+.konaste-clock-colon { opacity: 0.6; margin: 0 1px; }
+
+.konaste-clock-ap { color: var(--neon-cyan); font-size: 0.9em; }
+
+.konaste-clock-tz { color: #666; margin-left: 4px; }
+
+.konaste-names {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ flex-wrap: wrap;
+}
+
+.konaste-name-sep { color: #555; flex-shrink: 0; }
+
+.konaste-game {
+ display: grid;
+ grid-template-columns: 12px auto minmax(0, 1fr);
+ align-items: start;
+ column-gap: 10px;
+ row-gap: 5px;
+ padding: 5px 0;
+}
+
+.konaste-dot { grid-column: 1; grid-row: 1; margin-top: 3px; }
+
+.konaste-names { grid-column: 2; grid-row: 1; }
+
+.konaste-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ flex-shrink: 0;
+ background: #555;
+ box-shadow: 0 0 6px rgba(255, 255, 255, 0.15);
+}
+
+.konaste-dot.is-online {
+ background: var(--neon-green);
+ box-shadow: 0 0 8px var(--neon-green);
+}
+
+.konaste-dot.is-maintenance {
+ background: #febc2e;
+ box-shadow: 0 0 8px #febc2e;
+}
+
+.konaste-name {
+ color: #d51007;
+ white-space: nowrap;
+ flex-shrink: 0;
+ font-weight: 600;
+}
+
+.konaste-name:hover {
+ background: #d51007;
+ color: #000 !important;
+}
+
+.konaste-text {
+ grid-column: 3;
+ grid-row: 1;
+ color: #aaa;
+ line-height: 1.55;
+ text-align: right;
+ white-space: pre-line;
+}
+
+.konaste-countdown {
+ grid-column: 3;
+ text-align: right;
+ color: var(--neon-cyan);
+ font-variant-numeric: tabular-nums;
+}
+
+.konaste-note {
+ display: block;
+ margin-top: 8px;
+ padding-top: 6px;
+ border-top: 1px solid var(--border);
+ color: #666;
+ line-height: 1.4;
+}
+
+.konaste-note a { color: #8b0000; }
+
+@media (max-width: 600px), (hover: none) and (pointer: coarse) and (max-width: 820px) {
+ .konaste-status { font-size: 0.9rem; }
+ .konaste-game { padding: 7px 0; }
+ .konaste-dot { width: 12px; height: 12px; }
+}
+
+/* ---------------------------------------------------------------------------
+ Mid-size viewports (portrait monitors, half-screen windows, small laptops):
+ the absolutely-positioned link columns overlap the centered search box
+ between the phone breakpoint (600px) and ~1100px. Pull them into the flow
+ as centered wrapping rows above the search instead. Root dropdowns drop
+ straight down under their trigger; nested flyouts keep the JS fixed
+ positioning, which already clamps to the viewport.
+ On touch screens <=820px the accordion rules above still win (!important).
+ --------------------------------------------------------------------------- */
+@media (min-width: 601px) and (max-width: 1100px) {
+ .search-section {
+ padding-top: 16px;
+ }
+
+ .top-left-links,
+ .top-right-links {
+ position: static;
+ width: 100%;
+ flex-direction: row;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: center;
+ gap: 8px 16px;
+ margin-bottom: 12px;
+ text-align: center;
+ z-index: auto;
+ }
+
+ /* Root dropdowns open downward under the trigger instead of sideways */
+ .top-left-links .ctx-root > .ctx-parent > .ctx-flyout,
+ .top-right-links .ctx-root > .ctx-parent > .ctx-flyout {
+ top: calc(100% + 4px);
+ left: 0;
+ right: auto;
+ max-width: 92vw;
+ }
+}
+
+/* Narrow viewports: the 3-column konaste row (dot | names | right-aligned text)
+ squeezes the status text into a sliver. Stack text/countdown under the names. */
+@media (max-width: 850px) {
+ .konaste-game {
+ grid-template-columns: 12px minmax(0, 1fr);
+ }
+
+ .konaste-text {
+ grid-column: 2;
+ grid-row: 2;
+ text-align: left;
+ }
+
+ .konaste-countdown {
+ grid-column: 2;
+ text-align: left;
+ }
+
+ .grid {
+ gap: 16px;
+ }
+}
+
+/* Light mode */
+body.light-mode .konaste-status {
+ background: #f4f4f4;
+ border-color: #d9c2c2;
+ color: #555;
+}
+body.light-mode .konaste-title { color: #b00020; }
+body.light-mode .konaste-text { color: #444; }
+body.light-mode .konaste-updated,
+body.light-mode .konaste-note { color: #888; }
+body.light-mode .konaste-countdown { color: #8b0000; }
+body.light-mode .konaste-name,
+body.light-mode .konaste-note a { color: #b00020; }
+
+/* ===== OpenBSD-style boot screen additions ===== */
+.boot-log {
+ text-align: center;
+}
+/* Whole boot log is centered (ASCII blocks keep their own left-aligned
+ internal alignment via .boot-ascii-wrap's column flex). */
+.boot-log .boot-line,
+.boot-log .boot-login,
+.boot-log .boot-title {
+ text-align: center;
+}
+.boot-avatar {
+ width: clamp(72px, 10vw, 96px);
+ height: clamp(72px, 10vw, 96px);
+ border-radius: 50%;
+ object-fit: cover;
+ border: 3px solid #f2ca30;
+ box-shadow: 0 0 14px rgba(242, 202, 48, 0.55);
+ display: block;
+ margin: 0 auto 10px;
+}
+/* Lain hero card pinned above Puffy's bubble column. The wrap reserves the
+ avatar's height as padding so the absolute placement never clips the ASCII
+ or the lines above it. */
+.boot-puffy-wrap {
+ position: relative;
+ display: inline-block;
+ padding-top: calc(clamp(72px, 10vw, 96px) + 10px);
+ /* Right padding just under half an avatar: lands the avatar centre on the
+ top bubble without escaping the wrap, which .boot-ascii-wrap clips
+ horizontally. Scales with the avatar so the alignment holds at every
+ clamped ASCII size. */
+ padding-right: calc(clamp(72px, 10vw, 96px) * 0.385);
+}
+.boot-puffy-wrap .boot-avatar {
+ position: absolute;
+ top: 0;
+ right: 0;
+ margin: 0;
+}
+/* Puffy stacked over the OpenBSD wordmark. */
+.boot-ascii-wrap {
+ /* overflow-x:hidden alone forces overflow-y to auto, which put a real
+ scrollbar inside the boot screen. `clip` has no such side effect: the
+ wide ASCII is still clipped horizontally, y stays visible, nothing
+ scrolls. `overflow: hidden` is the fallback for pre-Chrome-90 UAs. */
+ overflow: hidden;
+ overflow-x: clip;
+ overflow-y: visible;
+ margin-bottom: 12px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 10px;
+}
+.boot-openbsd-wordmark {
+ display: inline-block;
+ margin: 0;
+ color: #f2ca30;
+ text-shadow:
+ 0 0 8px rgba(242, 202, 48, 0.65),
+ 0 0 18px rgba(242, 202, 48, 0.3);
+ font-family: var(--font-mono);
+ font-size: clamp(4px, min(0.85vw, 0.95vh), 10px);
+ line-height: 1.15;
+ text-align: left;
+ white-space: pre;
+}
+/* Puffy is 23 lines tall (Gentoo's g was 9) — smaller type keeps the whole
+ boot log on screen at 1080p and under. */
+.boot-puffy-ascii {
+ display: inline-block;
+ margin: 0;
+ color: #f2ca30;
+ text-shadow: 0 0 6px rgba(242, 202, 48, 0.4);
+ font-family: var(--font-mono);
+ font-size: clamp(4px, min(0.9vw, 1.0vh), 11px);
+ line-height: 1.15;
+ text-align: left;
+ white-space: pre;
+}
+.boot-log .boot-dim { color: #f2ca30; }
+.boot-log .boot-user {
+ color: #f2ca30;
+ font-weight: 600;
+ text-shadow: 0 0 6px rgba(242, 202, 48, 0.55);
+}
+.boot-log .boot-path { color: #f2ca30; font-weight: 600; }
+.boot-log .boot-line,
+.boot-log .boot-svc,
+.boot-log .boot-login {
+ color: #f2ca30;
+}
+
+/* ---------------------------------------------------------------------------
+ Responsive pass: portrait / vertical monitors + denser desktop grid.
+ The hero used to eat ~440px of height on 1080p, pushing every card below
+ the fold; portrait viewports over 1100px kept the absolute side link
+ columns and squeezed the search box into the middle third.
+ --------------------------------------------------------------------------- */
+
+/* Tighter quick-link stack (same type, less air between the rules). */
+.search-section h2.quick-search-title {
+ line-height: 1.25;
+ margin-bottom: 2px;
+}
+
+.search-section h2.quick-search-title::after {
+ margin-top: 4px;
+}
+
+/* Desktop hero compaction: cards start above the fold on 1080p. */
+@media (min-width: 851px) {
+ .search-section {
+ padding: 10px 0 22px;
+ }
+
+ .clock-container {
+ margin-top: 10px;
+ }
+
+ /* More cards per row: 200px tracks + tighter gutters. */
+ .grid {
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+ gap: 18px;
+ }
+}
+
+/* Wide screens have spare horizontal room: let the search inputs use it. */
+@media (min-width: 1400px) {
+ .unified-search,
+ .card-filter-wrap,
+ .search-box {
+ max-width: 680px;
+ }
+}
+
+@media (min-width: 1600px) {
+ .grid {
+ grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
+ gap: 20px;
+ }
+}
+
+/* Portrait / vertical monitors and tablets: drop the absolute side columns so
+ the search block gets the full width instead of the middle third. */
+@media (orientation: portrait) and (min-width: 601px) and (max-width: 1500px) {
+ .search-section {
+ padding-top: 12px;
+ }
+
+ .top-left-links,
+ .top-right-links {
+ position: static;
+ width: 100%;
+ flex-direction: row;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: center;
+ gap: 8px 16px;
+ margin-bottom: 10px;
+ text-align: center;
+ z-index: auto;
+ }
+
+ /* Root dropdowns open downward under the trigger instead of sideways */
+ .top-left-links .ctx-root > .ctx-parent > .ctx-flyout,
+ .top-right-links .ctx-root > .ctx-parent > .ctx-flyout {
+ top: calc(100% + 4px);
+ left: 0;
+ right: auto;
+ max-width: 92vw;
+ }
+}
+
+/* Tall-and-narrow portrait (vertical 1080p panel): keep card text legible but
+ pack more columns than the default 220px track would allow. */
+@media (orientation: portrait) and (min-width: 900px) {
+ .grid {
+ grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
+ gap: 16px;
+ }
+}
+
+/* The search form is a flex item, so it shrink-wrapped to ~384px and the
+ 584/680px max-width on .unified-search never applied. Let it fill the row. */
+#unified-search-form {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+}
+
+/* Short desktop viewports (720p, laptop panels): shave the hero further so the
+ first card row clears the fold. */
+@media (min-width: 851px) and (max-height: 820px) {
+ .search-section {
+ padding: 6px 0 14px;
+ }
+
+ .search-section h2.quick-search-title {
+ margin-bottom: 0;
+ }
+
+ .clock-container {
+ margin-top: 6px;
+ }
+}
+
+/* Red/dark-red terminal cursor on startpage controls (overrides cursor:pointer). */
+@media (hover: hover) and (pointer: fine) {
+ a,
+ button,
+ summary,
+ .search-link,
+ .ctx-item,
+ .ctx-trigger,
+ .comfort-toggle,
+ .search-engine-menu li,
+ .card,
+ label[for],
+ input[type="checkbox"],
+ input[type="radio"],
+ select {
+ cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='20' viewBox='0 0 16 20'%3E%3Crect x='6' y='0' width='4' height='14' fill='%23ff1a1a'/%3E%3Crect x='4' y='14' width='8' height='4' fill='%238b0000'/%3E%3C/svg%3E") 8 10, pointer;
+ }
+}