: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; } }