From ccd646f13bd72a07aef55d71013c99654ea207cb Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 12 Jun 2026 09:15:36 +0000 Subject: [PATCH] Autosave: 20260612-091548 --- ...tf-8\")\nprint(\"aligned source counts\")" | 0 ...l=>#sheep\")\ns=s.replace(\"source_count=" | 0 'Comparison | 0 "'Evolution')\ns=s.replace('name'=" | 0 "'Karma')\ns=s.replace('name'=" | 0 'Logecs | 0 'Principles | 0 'Spireason | 0 44,source_until= | 0 6,source_until= | 0 api/scan_links.php | 268 +++++++++ api/scan_structure.php | 316 ++++++++++ assets/css/custom.css | 510 ++++------------ assets/js/main.js | 566 ++++++++++++++++-- curated-links.php | 334 +++++++++++ healthz.php | 4 + includes/curated_data.php | 206 +++++++ index.php | 409 ++++++++----- 18 files changed, 2047 insertions(+), 566 deletions(-) create mode 100644 "#coffeeandcigarettes, source_count=>5,source_until=>#coffeeandcigarettes\")\np.write_text(s, encoding=\"utf-8\")\nprint(\"aligned source counts\")" create mode 100644 "#sheep, source_count=>42,source_until=>#sheep\")\ns=s.replace(\"source_count=" create mode 100644 'Comparison create mode 100644 "'Evolution')\ns=s.replace('name'=" create mode 100644 "'Karma')\ns=s.replace('name'=" create mode 100644 'Logecs create mode 100644 'Principles create mode 100644 'Spireason create mode 100644 44,source_until= create mode 100644 6,source_until= create mode 100644 api/scan_links.php create mode 100644 api/scan_structure.php create mode 100644 curated-links.php create mode 100644 healthz.php create mode 100644 includes/curated_data.php diff --git "a/#coffeeandcigarettes, source_count=>5,source_until=>#coffeeandcigarettes\")\np.write_text(s, encoding=\"utf-8\")\nprint(\"aligned source counts\")" "b/#coffeeandcigarettes, source_count=>5,source_until=>#coffeeandcigarettes\")\np.write_text(s, encoding=\"utf-8\")\nprint(\"aligned source counts\")" new file mode 100644 index 0000000..e69de29 diff --git "a/#sheep, source_count=>42,source_until=>#sheep\")\ns=s.replace(\"source_count=" "b/#sheep, source_count=>42,source_until=>#sheep\")\ns=s.replace(\"source_count=" new file mode 100644 index 0000000..e69de29 diff --git a/'Comparison b/'Comparison new file mode 100644 index 0000000..e69de29 diff --git "a/'Evolution')\ns=s.replace('name'=" "b/'Evolution')\ns=s.replace('name'=" new file mode 100644 index 0000000..e69de29 diff --git "a/'Karma')\ns=s.replace('name'=" "b/'Karma')\ns=s.replace('name'=" new file mode 100644 index 0000000..e69de29 diff --git a/'Logecs b/'Logecs new file mode 100644 index 0000000..e69de29 diff --git a/'Principles b/'Principles new file mode 100644 index 0000000..e69de29 diff --git a/'Spireason b/'Spireason new file mode 100644 index 0000000..e69de29 diff --git a/44,source_until= b/44,source_until= new file mode 100644 index 0000000..e69de29 diff --git a/6,source_until= b/6,source_until= new file mode 100644 index 0000000..e69de29 diff --git a/api/scan_links.php b/api/scan_links.php new file mode 100644 index 0000000..8251457 --- /dev/null +++ b/api/scan_links.php @@ -0,0 +1,268 @@ + [ + 'timeout' => 12, + 'header' => "User-Agent: Laegna-LandScaper-VisibleLinkScanner/1.1\r\n", + ], +]); +$html = @file_get_contents($source, false, $context); +if ($html === false || $html === '') { + http_response_code(502); + echo json_encode(['success' => false, 'error' => 'Could not fetch source page.']); + exit; +} + +$links = []; +$seen = []; +$ignoredCount = 0; +$suppressedCount = 0; + +if (preg_match_all('~]*)>(.*?)~is', $html, $matches, PREG_SET_ORDER)) { + foreach ($matches as $match) { + $attrs = $match[1] ?? ''; + $inner = $match[2] ?? ''; + + if (is_hidden_anchor($attrs)) { + $ignoredCount++; + continue; + } + if (!preg_match('~\bhref\s*=\s*(["\'])(.*?)\1~is', $attrs, $hrefMatch)) { + $ignoredCount++; + continue; + } + + $href = html_entity_decode(trim($hrefMatch[2]), ENT_QUOTES | ENT_HTML5, 'UTF-8'); + $label = visible_label($attrs, $inner); + if ($label === '') { + $ignoredCount++; + continue; + } + + $absolute = absolutize_url($href, $source); + $normalized = normalize_for_compare($absolute); + $skipReason = skip_reason($href, $absolute, $normalized, $deliberatelyRemoved); + if ($skipReason === 'suppressed') { + $suppressedCount++; + continue; + } + if ($skipReason !== '') { + $ignoredCount++; + continue; + } + + if (isset($seen[$normalized])) { + continue; + } + $seen[$normalized] = true; + + $category = categorize_link($absolute, $label); + $host = strtolower((string)(parse_url($absolute, PHP_URL_HOST) ?: '')); + $links[] = [ + 'text' => unicode_limit($label, 160), + 'href' => $absolute, + 'host' => $host, + 'category' => $category, + 'category_label' => category_label($category), + 'safety' => safety_class($host), + ]; + } +} + +echo json_encode([ + 'success' => true, + 'source' => $source, + 'count' => count($links), + 'ignored_count' => $ignoredCount, + 'suppressed_count' => $suppressedCount, + 'scanned_at' => gmdate('Y-m-d H:i:s') . ' UTC', + 'filters' => [ + 'visible_anchor_text_required' => true, + 'skips_schemes' => ['javascript', 'mailto', 'tel', 'data', 'blob'], + 'skips_asset_extensions' => ['js', 'mjs', 'css', 'map', 'png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'ico', 'woff', 'woff2', 'ttf', 'eot'], + 'unknown_external_hosts' => 'included but marked review', + ], + 'links' => $links, +], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + +function is_hidden_anchor(string $attrs): bool +{ + if (preg_match('~(?:^|\s)hidden(?:\s|=|$)~i', $attrs)) { + return true; + } + if (preg_match('~\baria-hidden\s*=\s*(["\'])true\1~i', $attrs)) { + return true; + } + if (preg_match('~\bstyle\s*=\s*(["\'])(.*?)\1~is', $attrs, $m)) { + $style = strtolower($m[2]); + return str_contains($style, 'display:none') + || str_contains($style, 'display: none') + || str_contains($style, 'visibility:hidden') + || str_contains($style, 'visibility: hidden') + || str_contains($style, 'opacity:0') + || str_contains($style, 'opacity: 0'); + } + return false; +} + +function visible_label(string $attrs, string $inner): string +{ + $cleanInner = preg_replace('~<(script|style)\b[^>]*>.*?~is', ' ', $inner) ?? $inner; + $text = html_entity_decode(strip_tags($cleanInner), ENT_QUOTES | ENT_HTML5, 'UTF-8'); + $text = trim(preg_replace('/\s+/u', ' ', $text) ?? ''); + if ($text !== '') { + return $text; + } + + foreach ([$attrs, $inner] as $source) { + if (preg_match_all('~\b(?:aria-label|title|alt)\s*=\s*(["\'])(.*?)\1~is', $source, $matches, PREG_SET_ORDER)) { + foreach ($matches as $match) { + $candidate = trim(preg_replace('/\s+/u', ' ', html_entity_decode($match[2], ENT_QUOTES | ENT_HTML5, 'UTF-8')) ?? ''); + if ($candidate !== '') { + return $candidate; + } + } + } + } + return ''; +} + +function skip_reason(string $href, string $absolute, string $normalized, array $deliberatelyRemoved): string +{ + $hrefLower = strtolower(trim($href)); + if ($hrefLower === '' || $hrefLower[0] === '#') { + return 'fragment'; + } + foreach (['javascript:', 'mailto:', 'tel:', 'data:', 'blob:'] as $scheme) { + if (str_starts_with($hrefLower, $scheme)) { + return 'scheme'; + } + } + if (!preg_match('~^https?://~i', $absolute)) { + return 'scheme'; + } + + $path = (string)(parse_url($absolute, PHP_URL_PATH) ?: ''); + if (preg_match('~\.(?:js|mjs|css|map|png|jpe?g|gif|svg|webp|ico|woff2?|ttf|eot)(?:$|[?#])~i', $path)) { + return 'asset'; + } + + foreach ($deliberatelyRemoved as $removed) { + if ($normalized === normalize_for_compare((string)$removed)) { + return 'suppressed'; + } + } + return ''; +} + +function categorize_link(string $url, string $label): string +{ + $host = strtolower((string)(parse_url($url, PHP_URL_HOST) ?: '')); + $path = strtolower((string)(parse_url($url, PHP_URL_PATH) ?: '')); + $haystack = strtolower($url . ' ' . $label); + if (str_ends_with($path, '.pdf')) return 'pdf'; + if (str_ends_with($path, '.zip')) return 'archive'; + if (str_ends_with($path, ".json") || str_contains($path, "numberdatabase")) return "dataset"; + if (str_ends_with($path, ".py") || str_contains($haystack, "script")) return "source"; + if (str_contains($haystack, 'frequency') || str_contains($haystack, 'frequential') || str_contains($haystack, 'octave') || str_contains($haystack, 'calculator') || str_contains($haystack, 'counter')) return 'tool'; + if (str_contains($haystack, 'bot') || str_contains($host, 'perplexity.ai')) return 'bot'; + if (str_contains($host, 'github')) return 'github'; + if (str_contains($path, 'apples') || str_contains($haystack, 'app')) return 'applet'; + if (str_contains($host, 'prezi')) return 'presentation'; + if (str_contains($host, 'youtube') || str_contains($host, 'notion')) return 'media'; + if ($host !== 'spireason.neocities.org') return 'external'; + return 'onsite'; +} + +function category_label(string $category): string +{ + return [ + 'pdf' => 'PDF text', + 'archive' => 'Archive', + "dataset" => "Dataset", + "source" => "Source file", + 'tool' => 'Tool', + 'bot' => 'External bot/system', + 'github' => 'Repository', + 'applet' => 'Applet', + 'presentation' => 'Presentation', + 'media' => 'Media', + 'external' => 'External system', + 'onsite' => 'On-site branch', + ][$category] ?? ucfirst(str_replace('-', ' ', $category)); +} + +function safety_class(string $host): string +{ + if ($host === 'spireason.neocities.org') { + return 'source'; + } + $knownHosts = [ + 'laegna.notaku.site', + 'prezi.com', + 'www.perplexity.ai', + 'huggingface.co', + 'assorted-canopy-961.notion.site', + 'www.youtube.com', + 'youtube.com', + 'github.com', + 'tambetvali.github.io', + ]; + foreach ($knownHosts as $knownHost) { + if ($host === $knownHost || str_ends_with($host, '.' . $knownHost)) { + return 'known-external'; + } + } + return 'review'; +} + +function unicode_limit(string $text, int $limit): string +{ + if (preg_match_all('/./us', $text, $chars) && count($chars[0]) > $limit) { + return implode('', array_slice($chars[0], 0, $limit - 1)) . 'โ€ฆ'; + } + return $text; +} + +function normalize_for_compare(string $url): string +{ + $url = trim($url); + $url = preg_replace('/#$/', '', $url) ?? $url; + return $url; +} + +function absolutize_url(string $href, string $base): string +{ + $href = trim($href); + if (preg_match('~^https?://~i', $href)) { + return encode_spaces($href); + } + $parts = parse_url($base); + $scheme = $parts['scheme'] ?? 'https'; + $host = $parts['host'] ?? 'spireason.neocities.org'; + if (str_starts_with($href, '//')) { + return encode_spaces($scheme . ':' . $href); + } + if (str_starts_with($href, '/')) { + return encode_spaces($scheme . '://' . $host . $href); + } + $path = $parts['path'] ?? '/'; + $dir = preg_replace('~/[^/]*$~', '/', $path) ?: '/'; + return encode_spaces($scheme . '://' . $host . $dir . $href); +} + +function encode_spaces(string $url): string +{ + return str_replace(' ', '%20', $url); +} diff --git a/api/scan_structure.php b/api/scan_structure.php new file mode 100644 index 0000000..b002163 --- /dev/null +++ b/api/scan_structure.php @@ -0,0 +1,316 @@ +"growing-out-of-the-shadows", "icon"=>"โš›๏ธ", "title"=>"Growing Out of the Shadows"], + ["id"=>"sheep", "icon"=>"๐Ÿ‘", "title"=>"Sheep / Laegna Counters"], + ["id"=>"infinity", "icon"=>"โ™พ๏ธ", "title"=>"Infinity"], + ["id"=>"natura", "icon"=>"๐ŸŒ€", "title"=>"Natura"], + ["id"=>"sunrise", "icon"=>"๐Ÿ”†", "title"=>"Sunrise"], + ["id"=>"bigbang", "icon"=>"๐Ÿ’ฅ", "title"=>"Bigbang"], + ["id"=>"yggdrasill", "icon"=>"๐ŸŒณ", "title"=>"Yggdrasill"], + ["id"=>"spiritrise", "icon"=>"๐Ÿ”ท", "title"=>"Spiritrise"], + ["id"=>"laelab", "icon"=>"๐Ÿ”ฌ", "title"=>"LaeLab"], + ["id"=>"geneticar", "icon"=>"๐Ÿงฌ", "title"=>"Geneticar"], + ["id"=>"handheldcal", "icon"=>"๐Ÿ–ฉ", "title"=>"HandheldCal"], + ["id"=>"puzzled", "icon"=>"๐Ÿงฉ", "title"=>"Puzzled"], + ["id"=>"chakra", "icon"=>"โœด๏ธ", "title"=>"Chakra"], + ["id"=>"wheelsgoround", "icon"=>"โš™๏ธ", "title"=>"Wheels Go Round"], + ["id"=>"laemedics", "icon"=>"๐Ÿง˜", "title"=>"LaeMedics"], + ["id"=>"coffeeandcigarettes", "icon"=>"โ˜•", "title"=>"Coffee and Cigarettes"], +]; + +$html = fetch_source($source); +if ($html === null) { + http_response_code(502); + echo json_encode(["success"=>false, "error"=>"Could not fetch source page"], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + exit; +} + +$positions = []; +foreach ($ids as $item) { + $pattern = '~\bid\s*=\s*["\x27]' . preg_quote($item["id"], '~') . '["\x27]~i'; + if (preg_match($pattern, $html, $m, PREG_OFFSET_CAPTURE)) { + $item["pos"] = $m[0][1]; + $positions[] = $item; + } +} +usort($positions, fn($a, $b) => $a["pos"] <=> $b["pos"]); + +$sections = []; +$totalLinks = 0; +$utilityChrome = []; +foreach ($positions as $idx => $item) { + $start = (int)$item["pos"]; + $end = isset($positions[$idx + 1]) ? (int)$positions[$idx + 1]["pos"] : strlen($html); + $chunk = substr($html, $start, $end - $start); + $ownedLinks = []; + if ($item["id"] === "coffeeandcigarettes") { + // Coffee is terminal prose. Links after it are footer/fixed/absolute utility chrome, + // not branch links owned by the Coffee icon. + $utilityChrome = parse_visible_links($chunk, $source); + } else { + $ownedLinks = parse_visible_links($chunk, $source); + $totalLinks += count($ownedLinks); + } + $layout = $sectionLayout[$item["id"]] ?? null; + $sections[] = [ + "id" => $item["id"], + "icon" => $item["icon"], + "title" => $item["title"], + "source_anchor" => "#" . $item["id"], + "owns_until" => $item["id"] === "coffeeandcigarettes" ? "utility chrome" : (isset($positions[$idx + 1]) ? "#" . $positions[$idx + 1]["id"] : "end"), + "layout" => $layout, + "excerpt" => unicode_limit(clean_text($chunk), 420), + "link_count" => count($ownedLinks), + "links" => $ownedLinks, + ]; +} + +$shadowBonus = [ + ["icon"=>"๐ŸŽญ", "title"=>"Dancing Shadows", "href"=>"https://material-psychic-gam-8mo3.bolt.host/"], + ["icon"=>"๐Ÿ“˜", "title"=>"Book of Shadows 2", "href"=>"https://app-bxfrqbbqegap.appmedo.com/"], + ["icon"=>"๐Ÿ“•", "title"=>"Bulk Load Book of the Dead 3", "href"=>"https://app-by9gm7mu9ssh.appmedo.com/"], +]; + +echo json_encode([ + "success" => true, + "source" => $source, + "scanned_at" => gmdate("Y-m-d H:i:s") . " UTC", + "model" => "CSS-aware: first 100vh console and fixed/absolute utility chrome are separated; document-flow icon owners keep links until the next meaningful icon/title; Coffee is terminal prose and owns no branch links.", + "layout_zones" => $layoutZones ?? [], + "section_count" => count($sections), + "link_count" => $totalLinks, + "utility_count" => count($utilityChrome), + "utility_chrome" => $utilityChrome, + "shadow_bonus" => $shadowBonus, + "sections" => $sections, +], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + +function fetch_source(string $url): ?string +{ + $context = stream_context_create([ + "http" => [ + "timeout" => 18, + "header" => "User-Agent: LandScaper structural scanner\r\n", + ], + ]); + $html = @file_get_contents($url, false, $context); + return is_string($html) && $html !== "" ? $html : null; +} + +function parse_visible_links(string $chunk, string $base): array +{ + $links = []; + if (!preg_match_all("~]*)>(.*?)~is", $chunk, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { + return $links; + } + foreach ($matches as $match) { + $attrs = $match[1][0] ?? ""; + $inner = $match[2][0] ?? ""; + $offset = (int)($match[0][1] ?? 0); + if (is_hidden_anchor($attrs)) { + continue; + } + $href = attr_value($attrs, "href"); + $label = visible_label($attrs, $inner); + if ($href === "" || $label === "") { + continue; + } + $absolute = absolute_url($href, $base); + $reason = skip_reason($href, $absolute); + if ($reason !== "") { + continue; + } + $host = strtolower((string)(parse_url($absolute, PHP_URL_HOST) ?: "")); + $category = categorize_link($absolute, $label); + $links[] = [ + "text" => unicode_limit($label, 150), + "href" => $absolute, + "host" => $host, + "category" => $category, + "category_label" => category_label($category), + "context" => context_hint($chunk, $offset), + "layout_hint" => layout_hint($attrs, $chunk, $offset), + "safety" => safety_class($host), + ]; + } + return $links; +} + + +function context_hint(string $chunk, int $offset): string +{ + $prefix = substr($chunk, max(0, $offset - 1800), min(1800, $offset)); + if (!preg_match_all('~<(article|section|blockquote|div|p|big|center)\b([^>]*)>~i', $prefix, $tags, PREG_SET_ORDER)) { + return 'flow text'; + } + $tag = end($tags); + $name = strtolower($tag[1] ?? 'flow'); + $attrs = $tag[2] ?? ''; + $id = attr_value($attrs, 'id'); + $class = attr_value($attrs, 'class'); + $label = $name; + if ($id !== '') $label .= '#' . $id; + if ($class !== '') $label .= '.' . preg_replace('/\s+/', '.', trim($class)); + return $label; +} + +function layout_hint(string $attrs, string $chunk, int $offset): string +{ + $style = strtolower(attr_value($attrs, 'style')); + $class = strtolower(attr_value($attrs, 'class')); + $prefix = strtolower(substr($chunk, max(0, $offset - 1300), min(1300, $offset))); + $haystack = $style . ' ' . $class . ' ' . $prefix; + if (str_contains($haystack, 'position: fixed') || str_contains($haystack, 'position:fixed')) return 'fixed chrome'; + if (str_contains($haystack, 'position: absolute') || str_contains($haystack, 'position:absolute') || str_contains($haystack, 'calc(100vh')) return 'absolute-positioned chrome'; + if (str_contains($haystack, 'position: relative') || str_contains($haystack, 'position:relative')) return 'relative positioned block'; + if (str_contains($haystack, ']*>.*?~is", " ", $inner) ?? $inner; + $text = html_entity_decode(strip_tags($cleanInner), ENT_QUOTES | ENT_HTML5, "UTF-8"); + $text = trim(preg_replace("/\s+/u", " ", $text) ?? ""); + if ($text !== "") return $text; + foreach (["aria-label", "title", "alt"] as $attr) { + $candidate = attr_value($attrs, $attr); + if ($candidate !== "") return trim(preg_replace("/\s+/u", " ", $candidate) ?? ""); + } + return ""; +} + +function skip_reason(string $href, string $absolute): string +{ + $hrefLower = strtolower(trim($href)); + if ($hrefLower === "" || $hrefLower[0] === "#") return "fragment"; + foreach (["javascript:", "mailto:", "tel:", "data:", "blob:"] as $scheme) { + if (str_starts_with($hrefLower, $scheme)) return "scheme"; + } + if (!preg_match("~^https?://~i", $absolute)) return "scheme"; + $path = (string)(parse_url($absolute, PHP_URL_PATH) ?: ""); + if (preg_match("~\.(?:js|mjs|css|map|png|jpe?g|gif|svg|webp|ico|woff2?|ttf|eot)(?:$|[?#])~i", $path)) return "asset"; + return ""; +} + +function absolute_url(string $href, string $base): string +{ + $href = html_entity_decode(trim($href), ENT_QUOTES | ENT_HTML5, "UTF-8"); + if (preg_match("~^https?://~i", $href)) return $href; + if (str_starts_with($href, "//")) return "https:" . $href; + $parts = parse_url($base); + $scheme = $parts["scheme"] ?? "https"; + $host = $parts["host"] ?? "spireason.neocities.org"; + if (str_starts_with($href, "/")) return $scheme . "://" . $host . $href; + $basePath = $parts["path"] ?? "/"; + $dir = rtrim(dirname($basePath), "/"); + if ($dir === "") $dir = "/"; + return $scheme . "://" . $host . rtrim($dir, "/") . "/" . str_replace(" ", "%20", $href); +} + +function clean_text(string $html): string +{ + $html = preg_replace("~<(script|style)\b[^>]*>.*?~is", " ", $html) ?? $html; + $text = html_entity_decode(strip_tags($html), ENT_QUOTES | ENT_HTML5, "UTF-8"); + $text = preg_replace("~\bid=\"[^\"]+\"\s*>~u", " ", $text) ?? $text; + $text = preg_replace("~[#.][A-Za-z0-9_-][^{}]{0,220}\\{[^{}]*\\}~u", " ", $text) ?? $text; + $text = preg_replace("~\b(?:font|color|background|padding|margin|position|display|border|box-shadow|width|height|transform|opacity|z-index|transition)[^.;]{0,180}[.;]~iu", " ", $text) ?? $text; + $text = preg_replace("~/\\*.*?\\*/~s", " ", $text) ?? $text; + $text = preg_replace("~@media[^{}]*\\{\\s*\\}~u", " ", $text) ?? $text; + return trim(preg_replace("/\s+/u", " ", $text) ?? ""); +} + +function categorize_link(string $url, string $label): string +{ + $host = strtolower((string)(parse_url($url, PHP_URL_HOST) ?: "")); + $path = strtolower((string)(parse_url($url, PHP_URL_PATH) ?: "")); + $haystack = strtolower($url . " " . $label); + if (str_ends_with($path, ".pdf")) return "pdf"; + if (str_ends_with($path, ".zip")) return "archive"; + if (str_ends_with($path, ".json") || str_contains($path, "numberdatabase")) return "dataset"; + if (str_ends_with($path, ".py") || str_contains($haystack, "script") || str_contains($haystack, "github")) return "source"; + if (str_contains($haystack, "frequency") || str_contains($haystack, "frequential") || str_contains($haystack, "octave") || str_contains($haystack, "calculator") || str_contains($haystack, "counter")) return "tool"; + if (str_contains($haystack, "bot") || str_contains($host, "perplexity.ai")) return "bot"; + if (str_contains($host, "github")) return "github"; + if (str_contains($path, "apples") || str_contains($haystack, "app") || str_contains($host, "lovable.app") || str_contains($host, "bolt.host") || str_contains($host, "appmedo.com")) return "applet"; + if (str_contains($host, "prezi") || str_contains($host, "docs.google")) return "presentation"; + if (str_contains($host, "youtube") || str_contains($host, "notion")) return "media"; + if ($host !== "spireason.neocities.org") return "external"; + return "onsite"; +} + +function category_label(string $category): string +{ + return [ + "pdf" => "PDF text", + "archive" => "Archive", + "dataset" => "Dataset", + "source" => "Source file", + "tool" => "Tool", + "bot" => "External bot/system", + "github" => "Repository", + "applet" => "Applet", + "presentation" => "Presentation", + "media" => "Media", + "external" => "External system", + "onsite" => "On-site branch", + ][$category] ?? ucfirst(str_replace("-", " ", $category)); +} + +function safety_class(string $host): string +{ + if ($host === "spireason.neocities.org") return "source"; + $knownHosts = [ + "laegna.notaku.site", + "prezi.com", + "www.perplexity.ai", + "huggingface.co", + "assorted-canopy-961.notion.site", + "www.youtube.com", + "youtube.com", + "github.com", + "tambetvali.github.io", + "archive.org", + ]; + foreach ($knownHosts as $knownHost) { + if ($host === $knownHost || str_ends_with($host, "." . $knownHost)) return "known-external"; + } + return "review"; +} + +function unicode_limit(string $text, int $limit): string +{ + if (preg_match_all("/./us", $text, $chars) && count($chars[0]) > $limit) { + return implode("", array_slice($chars[0], 0, max(0, $limit - 1))) . "โ€ฆ"; + } + return $text; +} diff --git a/assets/css/custom.css b/assets/css/custom.css index 789132e..2e9c06e 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -1,403 +1,121 @@ -body { - background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); - background-size: 400% 400%; - animation: gradient 15s ease infinite; - color: #212529; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; - font-size: 14px; - margin: 0; - min-height: 100vh; +:root{ + --bg:#f7f7f5; + --ink:#111111; + --muted:#626262; + --line:#d9d8d3; + --surface:#ffffff; + --surface-2:#eeeeea; + --accent:#202020; + --focus:#4d4d4d; + --radius-sm:4px; + --radius-md:8px; + --shadow:0 12px 35px rgba(0,0,0,.08); + --nav-h:58px; } - -.main-wrapper { - display: flex; - align-items: center; - justify-content: center; - min-height: 100vh; - width: 100%; - padding: 20px; - box-sizing: border-box; - position: relative; - z-index: 1; +[data-theme="night"]{ + --bg:#101010; + --ink:#efefec; + --muted:#aaa8a2; + --line:#2d2d2a; + --surface:#171717; + --surface-2:#21211f; + --accent:#f4f4ef; + --focus:#d8d8d2; + --shadow:0 12px 35px rgba(0,0,0,.28); } +*{box-sizing:border-box} +html{scroll-behavior:smooth;scroll-padding-top:72px} +body{margin:0;background:var(--bg);color:var(--ink);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;font-size:15px;line-height:1.55;transition:background .2s ease,color .2s ease} +a{color:inherit;text-decoration:none}.skip-link{position:fixed;left:12px;top:-48px;z-index:999;background:var(--ink);color:var(--bg);padding:.55rem .75rem;border-radius:var(--radius-sm)}.skip-link:focus{top:12px} +:focus-visible{outline:2px solid var(--focus);outline-offset:3px}.topbar{position:fixed;inset:0 0 auto 0;height:var(--nav-h);z-index:40;background:color-mix(in srgb,var(--surface) 86%,transparent);border-bottom:1px solid var(--line);backdrop-filter:blur(12px)}.topbar nav{height:100%}.brand{display:inline-flex;gap:.55rem;align-items:center;font-weight:700;letter-spacing:-.02em}.brand-mark{display:grid;place-items:center;width:31px;height:31px;border:1px solid var(--ink);font-size:.74rem}.top-links{display:flex;gap:.3rem;align-items:center;overflow-x:auto;white-space:nowrap}.top-links a,.theme-toggle{border:1px solid var(--line);background:var(--surface);padding:.42rem .64rem;border-radius:var(--radius-sm);font-size:.82rem;color:var(--muted)}.top-links a:hover,.theme-toggle:hover{color:var(--ink);border-color:var(--ink)}.theme-toggle{min-width:60px}.console-screen{position:relative;min-height:100vh;padding:calc(var(--nav-h) + 24px) 1rem 4.5rem;display:grid;place-items:center;overflow:hidden}.console-screen:before{content:"";position:absolute;inset:72px 18px 70px;border:1px solid var(--line);pointer-events:none}.console-screen:after{content:"";position:absolute;left:50%;top:50%;width:min(76vw,760px);height:min(76vw,760px);transform:translate(-50%,-50%);border:1px solid var(--line);border-radius:50%;opacity:.55;pointer-events:none}.console-panel{position:relative;z-index:2;width:min(820px,100%);background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:var(--shadow);padding:clamp(1.25rem,3vw,2.5rem);text-align:center}.eyebrow{text-transform:uppercase;letter-spacing:.16em;font-weight:700;font-size:.68rem;color:var(--muted);margin:0 0 .65rem}.console-panel h1{font-size:clamp(2rem,5vw,4.6rem);letter-spacing:-.06em;line-height:.96;margin:0 auto 1rem;max-width:760px}.lead{max-width:650px;margin:0 auto;color:var(--muted);font-size:1rem}.title-icons{display:flex;flex-wrap:wrap;justify-content:center;gap:.35rem;margin:1.5rem auto}.title-icons a,.bottom-icons a{display:grid;place-items:center;width:38px;height:38px;border:1px solid var(--line);background:var(--surface-2);border-radius:var(--radius-sm);font-size:1.15rem;transition:transform .16s ease,border-color .16s ease,background .16s ease}.title-icons a:hover,.bottom-icons a:hover{transform:translateY(-2px) scale(1.08);border-color:var(--ink);background:var(--surface)}.console-actions{display:flex;gap:.55rem;justify-content:center;flex-wrap:wrap}.fixed-cluster{position:absolute;z-index:3;display:flex;flex-direction:column;gap:.42rem}.cluster-left{left:24px;top:26vh}.cluster-right{right:24px;top:26vh}.fixed-cluster a{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);padding:.45rem .7rem;font-size:.82rem;box-shadow:var(--shadow)}.scroll-cue{position:absolute;bottom:21px;left:50%;transform:translateX(-50%);z-index:4;display:grid;place-items:center;width:40px;height:40px;border:1px solid var(--line);border-radius:50%;background:var(--surface)}.bottom-nav{position:fixed;left:50%;bottom:12px;transform:translate(-50%,110%);z-index:45;width:min(1120px,calc(100% - 18px));display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.45rem;background:color-mix(in srgb,var(--surface) 90%,transparent);border:1px solid var(--line);box-shadow:var(--shadow);border-radius:var(--radius-md);padding:.38rem;backdrop-filter:blur(14px);transition:transform .2s ease}.bottom-nav.visible{transform:translate(-50%,0)}.bottom-icons{display:flex;gap:.25rem;justify-content:center;overflow-x:auto}.bottom-icons a{width:32px;height:32px;font-size:1rem;flex:0 0 auto}.chapter-link{display:flex;align-items:center;gap:.35rem;border:1px solid var(--line);border-radius:var(--radius-sm);padding:.42rem .58rem;font-size:.78rem;color:var(--muted);white-space:nowrap}.document-shell{min-height:100vh;border-top:1px solid var(--line);padding:4rem 0 5.4rem;background:var(--surface-2)}.doc-heading{max-width:850px;margin:0 0 1.4rem}.doc-heading h2,.audit-panel h2{font-size:clamp(1.7rem,3.5vw,3rem);letter-spacing:-.05em;margin:0 0 .5rem}.doc-heading p{color:var(--muted);max-width:760px}.toolbar{position:sticky;top:calc(var(--nav-h) + 8px);z-index:10;display:flex;gap:.75rem;justify-content:space-between;align-items:center;margin:1rem 0 1.4rem;padding:.55rem;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-md)}.search-box{display:flex;align-items:center;gap:.5rem;min-width:min(420px,100%);color:var(--muted);font-size:.82rem}.search-box input{width:100%;border:1px solid var(--line);background:var(--bg);color:var(--ink);border-radius:var(--radius-sm);padding:.48rem .58rem}.mode-switch{display:flex;gap:.25rem}.mode-switch button{border:1px solid var(--line);background:var(--surface-2);color:var(--muted);border-radius:var(--radius-sm);padding:.45rem .6rem;font-size:.8rem}.mode-switch button.active{background:var(--ink);border-color:var(--ink);color:var(--bg)}.chapter-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.8rem;margin-bottom:.8rem}.chapter-card,.section-card,.audit-panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:0 1px 0 rgba(0,0,0,.02);padding:1rem}.chapter-kicker,.section-chapter{font-size:.72rem;text-transform:uppercase;letter-spacing:.13em;color:var(--muted);font-weight:700}.chapter-card h3{font-size:1.15rem;letter-spacing:-.03em;margin:.35rem 0}.chapter-card p,.section-card p{color:var(--muted);margin-bottom:0}.sections-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.8rem}.section-card{min-height:260px;scroll-margin-top:95px}.section-head{display:flex;gap:.7rem;align-items:flex-start;margin-bottom:.8rem}.section-icon{display:grid;place-items:center;width:42px;height:42px;border:1px solid var(--line);background:var(--surface-2);border-radius:var(--radius-sm);font-size:1.35rem;flex:0 0 auto}.section-card h3{font-size:1.05rem;letter-spacing:-.03em;margin:.1rem 0 0}.file-list{display:grid;gap:.4rem;margin-top:.9rem}.file-row{display:grid;grid-template-columns:auto 1fr auto;gap:.55rem;align-items:center;padding:.55rem;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--bg)}.file-row:hover{border-color:var(--ink)}.file-icon{width:26px;text-align:center}.file-copy{display:grid}.file-copy strong{font-size:.88rem}.file-copy small{color:var(--muted);font-size:.76rem}.file-arrow{color:var(--muted)}.empty-state{border:1px dashed var(--line);border-radius:var(--radius-sm);padding:.8rem;color:var(--muted);font-size:.84rem}.audit-panel{margin-top:1rem;display:grid;gap:.8rem}.audit-status{border:1px solid var(--line);background:var(--bg);border-radius:var(--radius-sm);padding:.6rem;color:var(--muted)}.audit-results{display:grid;gap:.38rem;max-height:440px;overflow:auto}.audit-row{display:grid;grid-template-columns:minmax(120px,1fr) auto;gap:.7rem;align-items:center;border:1px solid var(--line);border-radius:var(--radius-sm);padding:.55rem;background:var(--bg)}.audit-row a{font-weight:650;overflow-wrap:anywhere}.audit-row small{color:var(--muted);overflow-wrap:anywhere}.badge-soft{border:1px solid var(--line);border-radius:999px;padding:.2rem .45rem;font-size:.72rem;color:var(--muted)}.site-footer{display:flex;gap:1rem;justify-content:center;align-items:center;flex-wrap:wrap;border-top:1px solid var(--line);padding:1rem;color:var(--muted);font-size:.82rem;background:var(--surface)}.toast-wrap{position:fixed;right:12px;bottom:76px;z-index:60}.mini-toast{opacity:0;transform:translateY(8px);transition:opacity .18s ease,transform .18s ease;background:var(--ink);color:var(--bg);border-radius:var(--radius-sm);padding:.6rem .75rem;box-shadow:var(--shadow);font-size:.86rem}.mini-toast.show{opacity:1;transform:translateY(0)}.map-list{display:grid;gap:.65rem;margin:0;padding-left:1.2rem}.map-list li a{display:flex;gap:.6rem;font-weight:700}.map-list small{display:block;color:var(--muted);margin-left:1.85rem}.sections-grid.files .section-card{min-height:auto}.sections-grid.files .section-card>p{display:none}.sections-grid.text .section-card{display:block}.sections-grid.text .section-head,.sections-grid.text .file-icon,.sections-grid.text .file-arrow{display:none}.sections-grid.text .file-row{display:block;background:transparent}.is-hidden{display:none!important}@media (max-width:1100px){.sections-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.fixed-cluster{display:none}}@media (max-width:720px){.top-links{display:none}.console-screen:before{inset:68px 10px 64px}.console-panel{text-align:left}.title-icons,.console-actions{justify-content:flex-start}.chapter-grid,.sections-grid{grid-template-columns:1fr}.toolbar{position:static;display:grid}.mode-switch{overflow-x:auto}.chapter-link span{display:none}.bottom-nav{grid-template-columns:auto 1fr auto}.toast-wrap{left:12px;right:12px}.mini-toast{text-align:center}} -@keyframes gradient { - 0% { - background-position: 0% 50%; - } - 50% { - background-position: 100% 50%; - } - 100% { - background-position: 0% 50%; - } + +/* Link/category differentiation and PDF browser */ +.file-row,.pdf-card{--kind-accent:var(--line);--kind-bg:var(--bg)} +.link-kind-pdf{--kind-accent:#0f766e;--kind-bg:color-mix(in srgb,#0f766e 9%,var(--bg))} +.link-kind-applet{--kind-accent:#2563eb;--kind-bg:color-mix(in srgb,#2563eb 8%,var(--bg))} +.link-kind-bot{--kind-accent:#c2410c;--kind-bg:color-mix(in srgb,#c2410c 9%,var(--bg))} +.link-kind-external{--kind-accent:#b45309;--kind-bg:color-mix(in srgb,#b45309 9%,var(--bg))} +.link-kind-github{--kind-accent:#334155;--kind-bg:color-mix(in srgb,#334155 9%,var(--bg))} +.link-kind-tool{--kind-accent:#0369a1;--kind-bg:color-mix(in srgb,#0369a1 9%,var(--bg))} +.link-kind-archive{--kind-accent:#7c2d12;--kind-bg:color-mix(in srgb,#7c2d12 9%,var(--bg))} +.link-kind-presentation{--kind-accent:#be123c;--kind-bg:color-mix(in srgb,#be123c 8%,var(--bg))} +.link-kind-media{--kind-accent:#166534;--kind-bg:color-mix(in srgb,#166534 8%,var(--bg))} +.file-row{border-left:4px solid var(--kind-accent);background:var(--kind-bg)} +.kind-pill{display:inline-flex;align-items:center;border:1px solid color-mix(in srgb,var(--kind-accent) 45%,var(--line));color:var(--kind-accent);background:color-mix(in srgb,var(--kind-accent) 8%,var(--surface));border-radius:999px;padding:.08rem .38rem;margin-right:.28rem;font-size:.68rem;font-weight:750;white-space:nowrap}.filename{color:color-mix(in srgb,var(--muted) 78%,var(--ink));font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-size:.72rem}.pdf-library{scroll-margin-top:95px;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:0 1px 0 rgba(0,0,0,.02);padding:1rem;margin:0 0 .8rem}.pdf-library-head{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:1rem;align-items:start;margin-bottom:1rem}.pdf-library h2{font-size:clamp(1.45rem,3vw,2.45rem);letter-spacing:-.05em;margin:0 0 .45rem}.pdf-library p{color:var(--muted);max-width:780px;margin:0}.pdf-library code{font-size:.86em;color:var(--ink);background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-sm);padding:.04rem .24rem}.pdf-mode-switch{display:flex;gap:.25rem;flex-wrap:wrap;justify-content:flex-end}.pdf-mode-switch button{border:1px solid var(--line);background:var(--surface-2);color:var(--muted);border-radius:var(--radius-sm);padding:.45rem .6rem;font-size:.8rem}.pdf-mode-switch button.active{background:var(--ink);border-color:var(--ink);color:var(--bg)}.pdf-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:.55rem}.pdf-card{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:"icon title" "icon summary" "icon filename" "icon open";gap:.18rem .55rem;align-items:start;border:1px solid var(--line);border-left:4px solid var(--kind-accent);border-radius:var(--radius-sm);background:var(--kind-bg);padding:.65rem;min-height:142px;transition:transform .16s ease,border-color .16s ease,background .16s ease}.pdf-card:hover{transform:translateY(-2px);border-color:var(--kind-accent);background:color-mix(in srgb,var(--kind-bg) 75%,var(--surface))}.pdf-symbol{grid-area:icon;display:grid;place-items:center;width:34px;height:34px;border:1px solid color-mix(in srgb,var(--kind-accent) 45%,var(--line));border-radius:var(--radius-sm);background:var(--surface);font-size:1.08rem}.pdf-title{grid-area:title;font-weight:780;letter-spacing:-.02em;line-height:1.18}.pdf-summary{grid-area:summary;color:var(--muted);font-size:.8rem}.pdf-filename{grid-area:filename;color:var(--muted);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;font-size:.7rem;overflow-wrap:anywhere}.pdf-open{grid-area:open;color:var(--kind-accent);font-weight:750;font-size:.76rem}.pdf-library[data-pdf-mode="icons"] .pdf-grid{grid-template-columns:repeat(auto-fill,minmax(50px,1fr))}.pdf-library[data-pdf-mode="icons"] .pdf-card{display:grid;place-items:center;min-height:50px;padding:.45rem;border-left-width:1px}.pdf-library[data-pdf-mode="icons"] .pdf-symbol{width:38px;height:38px}.pdf-library[data-pdf-mode="icons"] .pdf-title,.pdf-library[data-pdf-mode="icons"] .pdf-summary,.pdf-library[data-pdf-mode="icons"] .pdf-filename,.pdf-library[data-pdf-mode="icons"] .pdf-open{display:none}.pdf-library[data-pdf-mode="title"] .pdf-grid{grid-template-columns:repeat(auto-fill,minmax(180px,1fr))}.pdf-library[data-pdf-mode="title"] .pdf-card{min-height:82px}.pdf-library[data-pdf-mode="title"] .pdf-summary,.pdf-library[data-pdf-mode="title"] .pdf-filename,.pdf-library[data-pdf-mode="title"] .pdf-open{display:none}.pdf-library[data-pdf-mode="summary"] .pdf-grid{grid-template-columns:repeat(auto-fill,minmax(240px,1fr))}.pdf-library[data-pdf-mode="summary"] .pdf-card{min-height:112px}.pdf-library[data-pdf-mode="summary"] .pdf-filename{display:none}.scanner-policy{border:1px dashed var(--line);border-radius:var(--radius-sm);padding:.55rem;color:var(--muted);font-size:.8rem;background:var(--bg)}.section-card.is-active{border-color:var(--ink);box-shadow:0 0 0 3px color-mix(in srgb,var(--ink) 10%,transparent),var(--shadow)}.audit-row{border-left:4px solid var(--kind-accent,var(--line))}.audit-badge-source{border-color:#0f766e;color:#0f766e}.audit-badge-known{border-color:#334155;color:#334155}.audit-badge-review{border-color:#b45309;color:#b45309}.audit-badge-new{border-color:#0369a1;color:#0369a1}@media (max-width:1100px){.pdf-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.pdf-library-head{grid-template-columns:1fr}.pdf-mode-switch{justify-content:flex-start}}@media (max-width:720px){.pdf-grid{grid-template-columns:1fr}.pdf-card{min-height:auto}.pdf-mode-switch{overflow-x:auto;flex-wrap:nowrap;justify-content:flex-start}.kind-pill{margin-bottom:.18rem}} + + +/* Ownership reference system and stable filtering */ +.link-kind-dataset{--kind-accent:#0e7490;--kind-bg:color-mix(in srgb,#0e7490 9%,var(--bg))} +.link-kind-source{--kind-accent:#475569;--kind-bg:color-mix(in srgb,#475569 9%,var(--bg))} +.link-kind-main-branch{--kind-accent:#1d4ed8;--kind-bg:color-mix(in srgb,#1d4ed8 8%,var(--bg))} +.section-meta{display:flex;flex-wrap:wrap;gap:.28rem;margin-top:.28rem;color:var(--muted);font-size:.72rem;font-weight:720;letter-spacing:.01em}.section-meta span{border:1px solid var(--line);background:var(--surface-2);border-radius:999px;padding:.08rem .4rem}.filter-status{align-self:center;color:var(--muted);font-size:.8rem;border:1px dashed var(--line);background:var(--surface);border-radius:var(--radius-sm);padding:.42rem .55rem}.is-filter-muted{opacity:.27;filter:grayscale(.45);transition:opacity .15s ease,filter .15s ease}.is-filter-hit{outline:2px solid color-mix(in srgb,var(--kind-accent,var(--ink)) 42%,transparent);outline-offset:2px}.reference-page{padding:88px 1rem 2rem;background:linear-gradient(180deg,var(--bg),color-mix(in srgb,var(--bg) 80%,var(--surface-2)));min-height:100vh}.reference-hero,.ownership-strip,.reference-tools,.source-map-panel{max-width:1440px;margin:0 auto .9rem}.reference-hero{border:1px solid var(--line);border-radius:var(--radius-md);background:radial-gradient(circle at 100% 0,color-mix(in srgb,#0f766e 13%,transparent),transparent 34%),var(--surface);box-shadow:var(--shadow);padding:clamp(1.1rem,3vw,2rem)}.reference-hero h1{font-size:clamp(2rem,5vw,4.8rem);line-height:.92;letter-spacing:-.08em;max-width:980px;margin:.2rem 0 .7rem}.reference-hero p{color:var(--muted);max-width:980px}.reference-stats{display:flex;flex-wrap:wrap;gap:.35rem;margin:1rem 0}.reference-stats span,.legend-pill{display:inline-flex;align-items:center;gap:.35rem;border:1px solid color-mix(in srgb,var(--kind-accent,var(--ink)) 35%,var(--line));background:color-mix(in srgb,var(--kind-bg,var(--surface-2)) 72%,var(--surface));border-radius:999px;padding:.32rem .58rem;font-size:.78rem;font-weight:760;color:color-mix(in srgb,var(--kind-accent,var(--ink)) 82%,var(--ink))}.ownership-strip{display:grid;grid-template-columns:minmax(0,1fr) minmax(260px,1.5fr);gap:1rem;align-items:center;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface);padding:1rem}.ownership-strip h2{font-size:clamp(1.25rem,3vw,2rem);letter-spacing:-.045em;margin:0}.ownership-icons{display:grid;grid-template-columns:repeat(auto-fill,minmax(58px,1fr));gap:.45rem}.ownership-icons a{display:grid;place-items:center;min-height:58px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--surface-2);color:var(--ink);text-decoration:none;position:relative;font-size:1.35rem;transition:transform .14s ease,border-color .14s ease}.ownership-icons a:hover{transform:translateY(-2px);border-color:var(--ink)}.ownership-icons small{position:absolute;right:.28rem;bottom:.2rem;color:var(--muted);font-size:.62rem;font-weight:800}.reference-tools{display:grid;grid-template-columns:minmax(260px,420px) minmax(200px,1fr);gap:.65rem;align-items:start;position:sticky;top:64px;z-index:6;border:1px solid var(--line);border-radius:var(--radius-md);background:color-mix(in srgb,var(--surface) 92%,transparent);backdrop-filter:blur(14px);padding:.65rem}.category-legend{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:.32rem}.reference-card h2{font-size:clamp(1.1rem,2vw,1.55rem);letter-spacing:-.04em;margin:0}.source-structure{display:grid;grid-template-columns:repeat(auto-fit,minmax(310px,1fr));gap:.7rem;margin-top:.8rem}.source-owner-card{border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface);padding:.85rem;box-shadow:0 1px 0 rgba(0,0,0,.02)}.source-owner-head{display:flex;gap:.65rem;align-items:center;margin-bottom:.55rem}.source-owner-icon{display:grid;place-items:center;width:46px;height:46px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--surface-2);font-size:1.45rem}.source-owner-card h3{margin:0;font-size:1.05rem;letter-spacing:-.025em}.source-owner-card p{color:var(--muted);font-size:.8rem;margin:.4rem 0 .65rem}.source-owner-links{display:grid;gap:.35rem;max-height:340px;overflow:auto;padding-right:.2rem}.source-link{display:grid;gap:.05rem;border-left:4px solid var(--kind-accent,var(--line));border-radius:var(--radius-sm);background:var(--kind-bg,var(--bg));padding:.42rem .52rem;color:var(--ink);text-decoration:none}.source-link span{font-weight:760;font-size:.84rem}.source-link small{color:var(--muted);font-size:.72rem}.shadow-bonus-live{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:.4rem;align-items:center;border:1px dashed var(--line);border-radius:var(--radius-md);padding:.7rem;background:radial-gradient(circle at 0 0,color-mix(in srgb,#111 8%,transparent),transparent 40%),var(--surface)}.shadow-bonus-live strong{margin-right:.35rem}.shadow-bonus-live a{color:var(--ink);text-decoration:none;border:1px solid var(--line);border-radius:999px;background:var(--surface-2);padding:.28rem .55rem;font-weight:760}.section-card[data-title*="sheep"]{--kind-accent:#0f766e}.section-card[data-title*="shadow"]{--kind-accent:#111827} +@media (max-width:900px){.ownership-strip,.reference-tools{grid-template-columns:1fr}.reference-tools{position:static}.source-structure{grid-template-columns:1fr}} + +.more-row{--kind-accent:var(--ink);--kind-bg:color-mix(in srgb,var(--ink) 5%,var(--surface));border-style:dashed}.more-row .file-copy small{display:block;color:var(--muted)} + +/* CSS-aware layout modes */ +.layout-audit,.utility-chrome-panel,.chapter-reference,.pdf-only-panel{max-width:1440px;margin:0 auto .9rem;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface);box-shadow:0 1px 0 rgba(0,0,0,.02);padding:1rem}.layout-audit-head{display:grid;gap:.25rem;margin-bottom:.9rem}.layout-audit h2,.utility-chrome-panel h2,.chapter-reference-card h2,.pdf-only-panel h2{font-size:clamp(1.45rem,3vw,2.6rem);letter-spacing:-.055em;margin:0}.layout-audit p,.utility-chrome-panel p,.chapter-reference-card p,.pdf-only-panel p{color:var(--muted);max-width:920px}.layout-zone-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:.55rem}.layout-zone-card{display:grid;grid-template-columns:auto minmax(0,1fr);gap:.65rem;align-items:start;border:1px solid var(--line);border-radius:var(--radius-sm);background:linear-gradient(180deg,var(--surface-2),color-mix(in srgb,var(--surface-2) 48%,var(--surface)));padding:.72rem}.layout-zone-card h3{font-size:.98rem;letter-spacing:-.025em;margin:0 0 .25rem}.layout-zone-card p{font-size:.8rem;margin:.2rem 0;color:var(--muted)}.layout-zone-card small{display:block;color:color-mix(in srgb,var(--muted) 82%,var(--ink));font-size:.7rem;line-height:1.4}.layout-zone-icon{display:grid;place-items:center;width:34px;height:34px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--surface);font-weight:800}.reference-mode-switch{display:flex;flex-wrap:wrap;gap:.25rem;align-items:center}.reference-mode-switch button,.manual-highlight{border:1px solid var(--line);background:var(--surface-2);color:var(--muted);border-radius:var(--radius-sm);padding:.45rem .6rem;font-size:.8rem;font-weight:720}.reference-mode-switch button.active,.reference-mode-switch button:hover,.manual-highlight:hover{background:var(--ink);border-color:var(--ink);color:var(--bg)}.reference-mode-panel[hidden]{display:none!important}.layout-note{display:grid;gap:.18rem;border:1px dashed var(--line);border-radius:var(--radius-sm);background:color-mix(in srgb,var(--surface-2) 68%,var(--surface));padding:.55rem;margin:.75rem 0;color:var(--muted);font-size:.78rem}.layout-note b{color:var(--ink);font-size:.82rem}.layout-note span{font-weight:720}.layout-note small{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace;color:color-mix(in srgb,var(--muted) 80%,var(--ink))}.layout-note em{font-style:normal}.manual-highlight{margin:0 0 .7rem}.chapter-reference{display:grid;gap:.8rem;background:transparent;border:0;padding:0;box-shadow:none}.chapter-reference-card{scroll-margin-top:95px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface);padding:1rem;box-shadow:var(--shadow)}.chapter-reference-head{display:grid;grid-template-columns:auto minmax(0,1fr);gap:.85rem;align-items:start}.chapter-reference-icon{display:grid;place-items:center;width:58px;height:58px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--surface-2);font-size:1.7rem}.chapter-trigger{display:grid;grid-template-columns:auto auto minmax(0,1fr);gap:.5rem;align-items:center;margin:.85rem 0;border:1px solid color-mix(in srgb,var(--kind-accent,#1d4ed8) 30%,var(--line));border-left:4px solid var(--kind-accent,#1d4ed8);border-radius:var(--radius-sm);background:var(--kind-bg,var(--surface-2));padding:.65rem;color:var(--ink);text-decoration:none}.chapter-trigger span{font-size:1.3rem}.chapter-trigger small{color:var(--muted)}.chapter-section-pills{display:flex;flex-wrap:wrap;gap:.35rem;margin:.4rem 0 1rem}.chapter-section-pills a{display:inline-flex;align-items:center;gap:.32rem;border:1px solid var(--line);border-radius:999px;background:var(--surface-2);padding:.25rem .55rem;color:var(--ink);font-size:.78rem;font-weight:750}.chapter-section-pills a:hover{border-color:var(--ink);background:var(--surface)}.branch-columns{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:.85rem}.branch-columns h3{font-size:.86rem;text-transform:uppercase;letter-spacing:.12em;color:var(--muted);margin:0 0 .45rem}.branch-link-list{display:grid;gap:.38rem}.branch-row{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:"icon title" "icon meta";gap:.04rem .5rem;align-items:start;border:1px solid var(--line);border-left:4px solid var(--kind-accent,var(--line));border-radius:var(--radius-sm);background:var(--kind-bg,var(--bg));padding:.5rem;color:var(--ink);text-decoration:none}.branch-row>span{grid-area:icon;display:grid;place-items:center;width:30px;height:30px;border:1px solid color-mix(in srgb,var(--kind-accent,var(--line)) 42%,var(--line));border-radius:var(--radius-sm);background:var(--surface)}.branch-row>b{grid-area:title;font-size:.86rem;letter-spacing:-.015em}.branch-row>small{grid-area:meta;color:var(--muted);font-size:.72rem;overflow-wrap:anywhere}.branch-main{background:linear-gradient(135deg,color-mix(in srgb,#1d4ed8 8%,var(--surface)),var(--kind-bg,var(--surface-2)));border-left-width:6px}.pdf-only-panel{scroll-margin-top:95px}.pdf-only-head{margin-bottom:.9rem}.utility-chrome-panel{display:grid;grid-template-columns:minmax(260px,.8fr) minmax(260px,1.2fr);gap:1rem;align-items:start}.utility-link-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:.42rem}.utility-row{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:"icon title" "icon meta";gap:.04rem .45rem;border:1px dashed var(--line);border-left:4px solid var(--kind-accent,var(--line));border-radius:var(--radius-sm);background:var(--kind-bg,var(--surface-2));padding:.52rem;color:var(--ink);text-decoration:none}.utility-row>span{grid-area:icon}.utility-row>b{grid-area:title;font-size:.84rem}.utility-row>small{grid-area:meta;color:var(--muted);font-size:.72rem}.chapter-reference-card.is-active,.pdf-card.is-active{border-color:var(--ink);box-shadow:0 0 0 3px color-mix(in srgb,var(--ink) 12%,transparent),var(--shadow)}.reference-page[data-reference-mode="chapters"] .ownership-strip,.reference-page[data-reference-mode="pdfs"] .ownership-strip{background:linear-gradient(135deg,var(--surface),color-mix(in srgb,var(--surface-2) 76%,var(--surface)))} +@media (max-width:1200px){.layout-zone-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.reference-tools{grid-template-columns:1fr}.branch-columns,.utility-chrome-panel{grid-template-columns:1fr}} +@media (max-width:720px){.layout-zone-grid{grid-template-columns:1fr}.chapter-reference-head,.chapter-trigger{grid-template-columns:1fr}.chapter-reference-icon{width:46px;height:46px}.reference-mode-switch{overflow-x:auto;flex-wrap:nowrap}.reference-mode-switch button{white-space:nowrap}} + + + +/* Joyful reference upgrades: warmer palette, clearer target pins, and category glow. */ +:root{ + --bg:#fff9ed; + --ink:#172033; + --muted:#667085; + --line:#eadfca; + --surface:#fffefb; + --surface-2:#fff2d7; + --accent:#ff7a59; + --focus:#00a6a6; + --joy:#ffb703; + --mint:#49c6a9; + --sky:#4ea3f1; + --rose:#ff5d8f; + --radius-sm:14px; + --radius-md:24px; + --shadow:0 18px 52px rgba(40,64,84,.13); } - -.chat-container { - width: 100%; - max-width: 600px; - background: rgba(255, 255, 255, 0.85); - border: 1px solid rgba(255, 255, 255, 0.3); - border-radius: 20px; - display: flex; - flex-direction: column; - height: 85vh; - box-shadow: 0 20px 40px rgba(0,0,0,0.2); - backdrop-filter: blur(15px); - -webkit-backdrop-filter: blur(15px); - overflow: hidden; +[data-theme="night"]{ + --bg:#111820; + --ink:#f8f4e8; + --muted:#b7bdc7; + --line:#2b3642; + --surface:#17212b; + --surface-2:#202b35; + --accent:#ff9f7a; + --focus:#54d6cf; + --joy:#ffd166; + --mint:#71dfbe; + --sky:#7ab8ff; + --rose:#ff85aa; + --shadow:0 18px 54px rgba(0,0,0,.36); } +body{background:radial-gradient(circle at 7% 7%,color-mix(in srgb,var(--joy) 24%,transparent),transparent 28rem),radial-gradient(circle at 92% 12%,color-mix(in srgb,var(--sky) 20%,transparent),transparent 27rem),linear-gradient(180deg,var(--bg),color-mix(in srgb,var(--bg) 78%,var(--surface-2)));} +.topbar{background:color-mix(in srgb,var(--surface) 82%,transparent);box-shadow:0 8px 30px rgba(40,64,84,.07)} +.brand-mark{border-radius:12px;border:0;background:linear-gradient(135deg,var(--joy),var(--accent));color:#172033;box-shadow:0 8px 18px color-mix(in srgb,var(--accent) 22%,transparent)} +.top-links a,.theme-toggle,.reference-mode-switch button,.manual-highlight{border-radius:999px;transition:transform .16s ease,background .16s ease,border-color .16s ease,box-shadow .16s ease}.top-links a:hover,.theme-toggle:hover,.reference-mode-switch button:hover,.manual-highlight:hover{transform:translateY(-1px);box-shadow:0 10px 24px rgba(40,64,84,.1)} +.top-links a[data-reference-mode-jump="pdfs"],.btn-joy{background:linear-gradient(135deg,var(--joy),var(--accent));border-color:transparent!important;color:#172033!important;font-weight:800;box-shadow:0 12px 28px color-mix(in srgb,var(--accent) 22%,transparent)} +.reference-hero,.layout-audit,.ownership-strip,.reference-tools,.utility-chrome-panel,.source-map-panel{border-radius:var(--radius-md);background:linear-gradient(135deg,color-mix(in srgb,var(--surface) 90%,transparent),color-mix(in srgb,var(--surface-2) 82%,transparent));border-color:color-mix(in srgb,var(--line) 70%,var(--joy));box-shadow:var(--shadow)} +.reference-hero{position:relative;overflow:hidden}.reference-hero:after{content:"";position:absolute;right:-80px;top:-100px;width:230px;height:230px;border-radius:50%;background:radial-gradient(circle,color-mix(in srgb,var(--joy) 40%,transparent),transparent 67%);pointer-events:none}.reference-hero>*{position:relative;z-index:1} +.reference-stats span,.legend-pill,.kind-pill{border-radius:999px;background:color-mix(in srgb,var(--surface) 72%,var(--kind-bg,var(--surface-2)));border:1px solid color-mix(in srgb,var(--kind-accent,var(--line)) 36%,var(--line));box-shadow:0 1px 0 rgba(255,255,255,.55) inset}.legend-pill{display:inline-flex;align-items:center;gap:.35rem}.legend-pill:before{content:"";width:.58rem;height:.58rem;border-radius:50%;background:var(--kind-accent,var(--joy));box-shadow:0 0 0 3px color-mix(in srgb,var(--kind-accent,var(--joy)) 18%,transparent)} +.reference-tools{grid-template-columns:minmax(260px,1fr) auto auto auto;gap:.55rem;align-items:center}.reference-tools .category-legend{grid-column:1/-1}.filter-mode-toggle{display:inline-flex;align-items:center;justify-content:center;gap:.38rem;min-height:38px;border:1px solid var(--line);border-radius:999px;background:var(--surface);padding:.35rem .65rem;color:var(--ink);font-weight:800;font-size:.82rem;white-space:nowrap;cursor:pointer}.filter-mode-toggle input{width:1rem;height:1rem;accent-color:var(--accent)}.filter-mode-toggle:has(input:not(:checked)){background:color-mix(in srgb,var(--surface) 76%,var(--sky));border-color:color-mix(in srgb,var(--sky) 42%,var(--line))}.filter-status{align-self:center;justify-self:start;border-radius:999px;background:color-mix(in srgb,var(--mint) 14%,var(--surface));border:1px solid color-mix(in srgb,var(--mint) 35%,var(--line));padding:.43rem .65rem;font-size:.78rem;font-weight:800;color:var(--ink)} +.section-card,.chapter-reference-card,.pdf-card,.layout-zone-card,.source-owner-card,.utility-row,.branch-row,.file-row,.source-link{transition:transform .16s ease,border-color .16s ease,box-shadow .16s ease,background .16s ease,opacity .16s ease,filter .16s ease}.section-card,.chapter-reference-card,.source-owner-card{position:relative;overflow:hidden}.section-card:before,.chapter-reference-card:before,.source-owner-card:before{content:"";position:absolute;inset:0 0 auto;height:5px;background:linear-gradient(90deg,var(--kind-accent,var(--accent)),var(--joy),var(--mint));opacity:.9}.section-card:hover,.chapter-reference-card:hover,.pdf-card:hover,.layout-zone-card:hover,.source-owner-card:hover{transform:translateY(-2px)} +.section-icon,.chapter-reference-icon,.layout-zone-icon,.source-owner-icon,.file-icon,.pdf-symbol{border-radius:18px;background:linear-gradient(135deg,color-mix(in srgb,var(--kind-accent,var(--accent)) 18%,var(--surface)),color-mix(in srgb,var(--joy) 18%,var(--surface-2)));box-shadow:inset 0 1px 0 rgba(255,255,255,.55)} +.file-row:hover,.branch-row:hover,.utility-row:hover,.source-link:hover{border-color:var(--kind-accent,var(--accent));box-shadow:0 10px 22px color-mix(in srgb,var(--kind-accent,var(--accent)) 14%,transparent);transform:translateY(-1px)} +.is-filter-muted{opacity:.2;filter:saturate(.3) grayscale(.45)}.is-filter-hit{box-shadow:0 0 0 3px color-mix(in srgb,var(--mint) 24%,transparent),0 10px 24px rgba(40,64,84,.08)!important} +.is-focus-target,.is-owner-preview{position:relative;border-color:var(--joy)!important;box-shadow:0 0 0 4px color-mix(in srgb,var(--joy) 35%,transparent),0 16px 38px color-mix(in srgb,var(--accent) 18%,transparent),var(--shadow)!important}.is-focus-target{animation:targetPulse .85s ease both}.is-focus-target:after{content:"โœจ pinned";position:absolute;right:.7rem;top:.65rem;z-index:3;border-radius:999px;background:linear-gradient(135deg,var(--joy),var(--accent));color:#172033;font-size:.7rem;font-weight:900;letter-spacing:.03em;padding:.22rem .5rem;box-shadow:0 8px 18px color-mix(in srgb,var(--accent) 25%,transparent)}.is-owner-preview{transform:translateY(-1px)} +.is-owner-link{border-color:var(--joy)!important;background:color-mix(in srgb,var(--joy) 18%,var(--surface))!important;color:var(--ink)!important;box-shadow:0 0 0 3px color-mix(in srgb,var(--joy) 22%,transparent)!important}.ownership-icons a.is-owner-link{transform:translateY(-2px) scale(1.08)} +@keyframes targetPulse{0%{transform:scale(.992)}55%{transform:scale(1.01)}100%{transform:scale(1)}} +.section-card[data-tone="pastoral"]{--kind-accent:#32b889;background:linear-gradient(135deg,color-mix(in srgb,#32b889 12%,var(--surface)),var(--surface))}.section-card[data-tone="pastoral"] .section-chapter:after{content:" ยท counter garden";color:#0f766e;font-weight:850}.section-card[data-tone="solar"]{--kind-accent:#ffb703;background:linear-gradient(135deg,color-mix(in srgb,#ffb703 18%,var(--surface)),var(--surface))}.section-card[data-tone="solar"] .section-chapter:after{content:" ยท PDF meadow";color:#b45309;font-weight:850}.section-card[data-tone="archive"]{--kind-accent:#ff7a59;border-style:dashed;background:linear-gradient(135deg,color-mix(in srgb,#ff7a59 13%,var(--surface)),var(--surface-2))}.section-card[data-tone="archive"] .section-chapter:after{content:" ยท terminal";color:#c2410c;font-weight:850}.section-card[data-tone="tool"],.section-card[data-tone="gear"]{--kind-accent:#4ea3f1}.section-card[data-tone="lab"],.section-card[data-tone="helix"]{--kind-accent:#49c6a9}.section-card[data-tone="shadow"],.section-card[data-tone="atomic"]{--kind-accent:#475569}.chapter-reference-card[data-tone="chapter"]{--kind-accent:var(--sky)} +.link-kind-pdf{--kind-accent:#16a34a;--kind-bg:color-mix(in srgb,#16a34a 11%,var(--surface))}.link-kind-applet{--kind-accent:#0284c7;--kind-bg:color-mix(in srgb,#0284c7 10%,var(--surface))}.link-kind-bot{--kind-accent:#f97316;--kind-bg:color-mix(in srgb,#f97316 11%,var(--surface))}.link-kind-tool{--kind-accent:#0891b2;--kind-bg:color-mix(in srgb,#0891b2 11%,var(--surface))}.link-kind-dataset{--kind-accent:#0d9488;--kind-bg:color-mix(in srgb,#0d9488 11%,var(--surface))}.link-kind-presentation{--kind-accent:#e11d48;--kind-bg:color-mix(in srgb,#e11d48 9%,var(--surface))}.link-kind-media{--kind-accent:#65a30d;--kind-bg:color-mix(in srgb,#65a30d 10%,var(--surface))} +.pdf-only-panel{padding:1rem;background:linear-gradient(135deg,color-mix(in srgb,var(--joy) 15%,var(--surface)),var(--surface))}.pdf-grid{gap:.6rem}.pdf-card{border-radius:18px}.pdf-open{font-weight:900;color:color-mix(in srgb,var(--kind-accent) 80%,var(--ink))}.branch-main{background:linear-gradient(135deg,color-mix(in srgb,var(--joy) 20%,var(--surface)),var(--kind-bg,var(--surface-2)))} +@media (max-width:1200px){.reference-tools{grid-template-columns:1fr auto auto}.reference-tools .reference-mode-switch,.reference-tools .category-legend{grid-column:1/-1}} +@media (max-width:720px){.reference-tools{grid-template-columns:1fr}.filter-status{justify-self:stretch;text-align:center}.filter-mode-toggle{justify-self:start}.is-focus-target:after{right:.45rem;top:.45rem}} -.chat-header { - padding: 1.5rem; - border-bottom: 1px solid rgba(0, 0, 0, 0.05); - background: rgba(255, 255, 255, 0.5); - font-weight: 700; - font-size: 1.1rem; - display: flex; - justify-content: space-between; - align-items: center; -} -.chat-messages { - flex: 1; - overflow-y: auto; - padding: 1.5rem; - display: flex; - flex-direction: column; - gap: 1.25rem; -} - -/* Custom Scrollbar */ -::-webkit-scrollbar { - width: 6px; -} - -::-webkit-scrollbar-track { - background: transparent; -} - -::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.3); - border-radius: 10px; -} - -::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.5); -} - -.message { - max-width: 85%; - padding: 0.85rem 1.1rem; - border-radius: 16px; - line-height: 1.5; - font-size: 0.95rem; - box-shadow: 0 4px 15px rgba(0,0,0,0.05); - animation: fadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -@keyframes fadeIn { - from { opacity: 0; transform: translateY(20px) scale(0.95); } - to { opacity: 1; transform: translateY(0) scale(1); } -} - -.message.visitor { - align-self: flex-end; - background: linear-gradient(135deg, #212529 0%, #343a40 100%); - color: #fff; - border-bottom-right-radius: 4px; -} - -.message.bot { - align-self: flex-start; - background: #ffffff; - color: #212529; - border-bottom-left-radius: 4px; -} - -.chat-input-area { - padding: 1.25rem; - background: rgba(255, 255, 255, 0.5); - border-top: 1px solid rgba(0, 0, 0, 0.05); -} - -.chat-input-area form { - display: flex; - gap: 0.75rem; -} - -.chat-input-area input { - flex: 1; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 12px; - padding: 0.75rem 1rem; - outline: none; - background: rgba(255, 255, 255, 0.9); - transition: all 0.3s ease; -} - -.chat-input-area input:focus { - border-color: #23a6d5; - box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.2); -} - -.chat-input-area button { - background: #212529; - color: #fff; - border: none; - padding: 0.75rem 1.5rem; - border-radius: 12px; - cursor: pointer; - font-weight: 600; - transition: all 0.3s ease; -} - -.chat-input-area button:hover { - background: #000; - transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(0,0,0,0.2); -} - -/* Background Animations */ -.bg-animations { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 0; - overflow: hidden; - pointer-events: none; -} - -.blob { - position: absolute; - width: 500px; - height: 500px; - background: rgba(255, 255, 255, 0.2); - border-radius: 50%; - filter: blur(80px); - animation: move 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1); -} - -.blob-1 { - top: -10%; - left: -10%; - background: rgba(238, 119, 82, 0.4); -} - -.blob-2 { - bottom: -10%; - right: -10%; - background: rgba(35, 166, 213, 0.4); - animation-delay: -7s; - width: 600px; - height: 600px; -} - -.blob-3 { - top: 40%; - left: 30%; - background: rgba(231, 60, 126, 0.3); - animation-delay: -14s; - width: 450px; - height: 450px; -} - -@keyframes move { - 0% { transform: translate(0, 0) rotate(0deg) scale(1); } - 33% { transform: translate(150px, 100px) rotate(120deg) scale(1.1); } - 66% { transform: translate(-50px, 200px) rotate(240deg) scale(0.9); } - 100% { transform: translate(0, 0) rotate(360deg) scale(1); } -} - -.header-link { - font-size: 14px; - color: #fff; - text-decoration: none; - background: rgba(0, 0, 0, 0.2); - padding: 0.5rem 1rem; - border-radius: 8px; - transition: all 0.3s ease; -} - -.header-link:hover { - background: rgba(0, 0, 0, 0.4); - text-decoration: none; -} - -/* Admin Styles */ -.admin-container { - max-width: 900px; - margin: 3rem auto; - padding: 2.5rem; - background: rgba(255, 255, 255, 0.85); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border-radius: 24px; - box-shadow: 0 20px 50px rgba(0,0,0,0.15); - border: 1px solid rgba(255, 255, 255, 0.4); - position: relative; - z-index: 1; -} - -.admin-container h1 { - margin-top: 0; - color: #212529; - font-weight: 800; -} - -.table { - width: 100%; - border-collapse: separate; - border-spacing: 0 8px; - margin-top: 1.5rem; -} - -.table th { - background: transparent; - border: none; - padding: 1rem; - color: #6c757d; - font-weight: 600; - text-transform: uppercase; - font-size: 0.75rem; - letter-spacing: 1px; -} - -.table td { - background: #fff; - padding: 1rem; - border: none; -} - -.table tr td:first-child { border-radius: 12px 0 0 12px; } -.table tr td:last-child { border-radius: 0 12px 12px 0; } - -.form-group { - margin-bottom: 1.25rem; -} - -.form-group label { - display: block; - margin-bottom: 0.5rem; - font-weight: 600; - font-size: 0.9rem; -} - -.form-control { - width: 100%; - padding: 0.75rem 1rem; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 12px; - background: #fff; - transition: all 0.3s ease; - box-sizing: border-box; -} - -.form-control:focus { - outline: none; - border-color: #23a6d5; - box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.1); -} - -.header-container { - display: flex; - justify-content: space-between; - align-items: center; -} - -.header-links { - display: flex; - gap: 1rem; -} - -.admin-card { - background: rgba(255, 255, 255, 0.6); - padding: 2rem; - border-radius: 20px; - border: 1px solid rgba(255, 255, 255, 0.5); - margin-bottom: 2.5rem; - box-shadow: 0 10px 30px rgba(0,0,0,0.05); -} - -.admin-card h3 { - margin-top: 0; - margin-bottom: 1.5rem; - font-weight: 700; -} - -.btn-delete { - background: #dc3545; - color: white; - border: none; - padding: 0.25rem 0.5rem; - border-radius: 4px; - cursor: pointer; -} - -.btn-add { - background: #212529; - color: white; - border: none; - padding: 0.5rem 1rem; - border-radius: 4px; - cursor: pointer; - margin-top: 1rem; -} - -.btn-save { - background: #0088cc; - color: white; - border: none; - padding: 0.8rem 1.5rem; - border-radius: 12px; - cursor: pointer; - font-weight: 600; - width: 100%; - transition: all 0.3s ease; -} - -.webhook-url { - font-size: 0.85em; - color: #555; - margin-top: 0.5rem; -} - -.history-table-container { - overflow-x: auto; - background: rgba(255, 255, 255, 0.4); - padding: 1rem; - border-radius: 12px; - border: 1px solid rgba(255, 255, 255, 0.3); -} - -.history-table { - width: 100%; -} - -.history-table-time { - width: 15%; - white-space: nowrap; - font-size: 0.85em; - color: #555; -} - -.history-table-user { - width: 35%; - background: rgba(255, 255, 255, 0.3); - border-radius: 8px; - padding: 8px; -} - -.history-table-ai { - width: 50%; - background: rgba(255, 255, 255, 0.5); - border-radius: 8px; - padding: 8px; -} - -.no-messages { - text-align: center; - color: #777; -} \ No newline at end of file +/* Viewport-aware target lighting: visible boxes tint their matching top/bottom links; pinned still glows brighter. */ +.is-in-view-target:not(.is-focus-target):not(.is-owner-preview){position:relative;border-color:color-mix(in srgb,var(--mint,#49c6a9) 44%,var(--line))!important;box-shadow:inset 0 0 0 2px color-mix(in srgb,var(--mint,#49c6a9) 18%,transparent),0 8px 22px color-mix(in srgb,var(--mint,#49c6a9) 10%,transparent)!important}.is-in-view-target:not(.is-focus-target):not(.is-owner-preview):before{opacity:1}.is-visible-owner-link:not(.is-owner-link){border-color:color-mix(in srgb,var(--mint,#49c6a9) 58%,var(--line))!important;background:linear-gradient(135deg,color-mix(in srgb,var(--mint,#49c6a9) 16%,var(--surface)),color-mix(in srgb,var(--joy,#ffd166) 10%,var(--surface)))!important;color:var(--ink)!important;box-shadow:0 0 0 2px color-mix(in srgb,var(--mint,#49c6a9) 18%,transparent),0 8px 18px color-mix(in srgb,var(--mint,#49c6a9) 10%,transparent)!important}.bottom-icons a.is-visible-owner-link:not(.is-owner-link),.title-icons a.is-visible-owner-link:not(.is-owner-link),.ownership-icons a.is-visible-owner-link:not(.is-owner-link){transform:translateY(-1px) scale(1.06)}.bottom-icons a.is-owner-link,.title-icons a.is-owner-link,.chapter-link.is-owner-link,.top-links a.is-owner-link{transform:translateY(-2px) scale(1.1)}.chapter-link.is-visible-owner-link:not(.is-owner-link),.top-links a.is-visible-owner-link:not(.is-owner-link),.manual-highlight.is-visible-owner-link:not(.is-owner-link){font-weight:850}.section-card,.chapter-card,.chapter-reference-card,.layout-zone-card,.layout-audit,.ownership-strip,.reference-tools,.reference-hero,.pdf-library,.reference-mode-panel,.utility-chrome-panel,.source-owner-card,.audit-panel,.document-shell,.console-screen{scroll-margin-top:92px}.section-card,.chapter-card,.chapter-reference-card,.source-owner-card,.layout-zone-card{cursor:default}.section-card:hover,.chapter-card:hover,.chapter-reference-card:hover,.source-owner-card:hover,.layout-zone-card:hover{border-color:color-mix(in srgb,var(--joy,#ffd166) 46%,var(--line))} diff --git a/assets/js/main.js b/assets/js/main.js index d349598..b1be74e 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,39 +1,535 @@ -document.addEventListener('DOMContentLoaded', () => { - const chatForm = document.getElementById('chat-form'); - const chatInput = document.getElementById('chat-input'); - const chatMessages = document.getElementById('chat-messages'); +(() => { + const $ = (sel, root = document) => root.querySelector(sel); + const $$ = (sel, root = document) => Array.from(root.querySelectorAll(sel)); + const toast = $("#miniToast"); + const showToast = (message) => { + if (!toast) return; + toast.textContent = message; + toast.classList.add("show"); + window.clearTimeout(showToast.t); + showToast.t = window.setTimeout(() => toast.classList.remove("show"), 2400); + }; - const appendMessage = (text, sender) => { - const msgDiv = document.createElement('div'); - msgDiv.classList.add('message', sender); - msgDiv.textContent = text; - chatMessages.appendChild(msgDiv); - chatMessages.scrollTop = chatMessages.scrollHeight; + const bottomNav = $("[data-bottom-nav]"); + const syncNav = () => bottomNav?.classList.toggle("visible", window.scrollY > 8); + window.addEventListener("scroll", syncNav, { passive: true }); + syncNav(); + + $$("[data-section-jump], .bottom-icons a, .top-links a, .scroll-cue, .chapter-link").forEach((link) => { + link.addEventListener("click", () => { + const label = link.getAttribute("data-title") || link.textContent.trim() || "section"; + showToast(`Navigating to ${label}`); + }); + }); + + const themeToggle = $("[data-theme-toggle]"); + const storedTheme = localStorage.getItem("landscaper-theme"); + if (storedTheme === "night") { + document.documentElement.dataset.theme = "night"; + if (themeToggle) { + themeToggle.textContent = "Night"; + themeToggle.setAttribute("aria-pressed", "true"); + } + } + themeToggle?.addEventListener("click", () => { + const next = document.documentElement.dataset.theme === "night" ? "day" : "night"; + if (next === "night") document.documentElement.dataset.theme = "night"; + else delete document.documentElement.dataset.theme; + themeToggle.textContent = next === "night" ? "Night" : "Day"; + themeToggle.setAttribute("aria-pressed", String(next === "night")); + localStorage.setItem("landscaper-theme", next === "night" ? "night" : "day"); + showToast(`${next === "night" ? "Night" : "Day"} mode enabled`); + }); + + const grid = $("[data-section-grid]"); + $$(".mode-switch button").forEach((button) => { + button.addEventListener("click", () => { + $$(".mode-switch button").forEach((b) => b.classList.remove("active")); + button.classList.add("active"); + grid?.classList.remove("blocks", "files", "text"); + grid?.classList.add(button.dataset.mode); + showToast(`${button.dataset.mode} mode`); + }); + }); + + const pdfLibrary = $("[data-pdf-library]"); + $$("[data-pdf-view]").forEach((button) => { + button.addEventListener("click", () => { + $$("[data-pdf-view]").forEach((b) => b.classList.remove("active")); + button.classList.add("active"); + if (pdfLibrary) pdfLibrary.dataset.pdfMode = button.dataset.pdfView || "intro"; + showToast(`PDF view: ${button.textContent.trim()}`); + }); + }); + + const referencePage = $("[data-reference-page]"); + const referenceModeButtons = $$("button[data-reference-mode]"); + const referencePanels = $$("[data-mode-panel]"); + const filter = $("#linkFilter"); + const filterDimToggle = $("#filterDimToggle"); + const filterStatus = $("#filterStatus"); + const filterModeLabel = $("[data-filter-mode-label]"); + + try { + const savedFilterMode = localStorage.getItem("curated-filter-mode"); + if (filterDimToggle && savedFilterMode === "hide") filterDimToggle.checked = false; + } catch {} + + function setReferenceMode(mode, options = {}) { + if (!referencePage || !mode) return; + referencePage.dataset.referenceMode = mode; + referenceModeButtons.forEach((button) => { + const active = button.dataset.referenceMode === mode; + button.classList.toggle("active", active); + button.setAttribute("aria-selected", String(active)); + }); + referencePanels.forEach((panel) => { + const active = panel.dataset.modePanel === mode; + panel.hidden = !active; + panel.classList.toggle("is-active", active); + }); + if (!options.quiet) showToast(mode === "pdfs" ? "PDF block ready" : (mode === "chapters" ? "Chapter groups ready" : "Icon boxes ready")); + scheduleVisibleHighlights(); + } + + function panelForMode(mode) { + return referencePanels.find((panel) => panel.dataset.modePanel === mode) || null; + } + + referenceModeButtons.forEach((button) => { + button.addEventListener("click", () => { + const mode = button.dataset.referenceMode; + setReferenceMode(mode, { quiet: true }); + const panel = panelForMode(mode); + if (panel?.id) window.setTimeout(() => markTarget(panel.id, { scroll: false, switchMode: false }), 30); + }); + }); + + $$("[data-reference-mode-jump]").forEach((link) => { + link.addEventListener("click", () => setReferenceMode(link.dataset.referenceModeJump, { quiet: true })); + }); + + document.addEventListener("click", (event) => { + const control = event.target.closest("[data-highlight-target]"); + if (!control) return; + const targetId = control.dataset.highlightTarget; + if (!targetId) return; + const href = control.getAttribute("href") || ""; + const external = control.matches("a[href]") && href && !href.startsWith("#"); + if (!external) event.preventDefault(); + markTarget(targetId, { scroll: !external, switchMode: true }); + }); + + document.addEventListener("click", (event) => { + const link = event.target.closest("a[href^=\"#\"]"); + if (!link || link.matches("[data-highlight-target]") || link.matches("[data-map-target]")) return; + const raw = link.getAttribute("href") || ""; + if (raw.length <= 1) return; + const targetId = decodeURIComponent(raw.slice(1)); + if (!document.getElementById(targetId)) return; + event.preventDefault(); + if (link.dataset.referenceModeJump) setReferenceMode(link.dataset.referenceModeJump, { quiet: true }); + window.setTimeout(() => markTarget(targetId, { scroll: true, switchMode: true }), 30); + }); + + function previewOwner(control, persist = false) { + const targetId = control?.dataset?.ownerTarget; + if (!targetId) return; + $$(".is-owner-preview").forEach((el) => el.classList.remove("is-owner-preview")); + $$(".is-owner-link").forEach((el) => el.classList.remove("is-owner-link")); + control.classList.add("is-owner-link"); + markRelatedControls(targetId, true); + const target = document.getElementById(targetId); + const hiddenPanel = target?.closest("[data-mode-panel]")?.hidden; + if (target && !hiddenPanel) target.classList.add("is-owner-preview"); + if (persist && target && !hiddenPanel) markTarget(targetId, { scroll: false, switchMode: false, toast: false }); + } + + document.addEventListener("mouseover", (event) => { + const control = event.target.closest("[data-owner-target]"); + if (control) previewOwner(control, false); + }); + document.addEventListener("focusin", (event) => { + const control = event.target.closest("[data-owner-target]"); + if (control) previewOwner(control, false); + }); + document.addEventListener("click", (event) => { + const control = event.target.closest("[data-owner-target]"); + if (control) previewOwner(control, true); + }); + + const applyFilter = () => { + const anchorState = captureScrollAnchor(); + const q = filter?.value.trim().toLowerCase() || ""; + const dimOut = filterDimToggle ? filterDimToggle.checked : true; + let total = 0; + let hits = 0; + + const setFiltered = (el, hit) => { + const miss = Boolean(q && !hit); + el.classList.toggle("is-filter-muted", miss && dimOut); + el.classList.toggle("is-hidden", miss && !dimOut); + el.classList.toggle("is-filter-hit", Boolean(q && hit)); }; - chatForm.addEventListener('submit', async (e) => { - e.preventDefault(); - const message = chatInput.value.trim(); - if (!message) return; - - appendMessage(message, 'visitor'); - chatInput.value = ''; - - try { - const response = await fetch('api/chat.php', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ message }) - }); - const data = await response.json(); - - // Artificial delay for realism - setTimeout(() => { - appendMessage(data.reply, 'bot'); - }, 500); - } catch (error) { - console.error('Error:', error); - appendMessage("Sorry, something went wrong. Please try again.", 'bot'); - } + $$("[data-pdf-card]").forEach((card) => { + total += 1; + const hit = !q || (card.dataset.search || "").includes(q); + if (hit) hits += 1; + setFiltered(card, hit); }); -}); + + $$("[data-section-card]").forEach((card) => { + const sectionMatch = !q || (card.dataset.title || "").includes(q) || (card.dataset.chapter || "").toLowerCase().includes(q); + let any = sectionMatch; + $$("[data-link-row]", card).forEach((row) => { + total += 1; + const hit = !q || (row.dataset.search || "").includes(q) || sectionMatch; + if (hit) hits += 1; + if (hit) any = true; + setFiltered(row, hit); + }); + setFiltered(card, any); + }); + + if (filterModeLabel) filterModeLabel.textContent = dimOut ? "dim" : "hide"; + try { localStorage.setItem("curated-filter-mode", dimOut ? "dim" : "hide"); } catch {} + if (filterStatus) filterStatus.textContent = q ? `${hits}/${total} ยท ${dimOut ? "dim" : "hide"}` : `All ยท ${dimOut ? "dim" : "hide"}`; + restoreScrollAnchor(anchorState); + scheduleVisibleHighlights(); + }; + + filter?.addEventListener("input", applyFilter); + filterDimToggle?.addEventListener("change", applyFilter); + applyFilter(); + + const mapBtn = $("[data-open-map]"); + mapBtn?.addEventListener("click", () => { + const modalElement = $("#mapModal"); + if (!modalElement || !window.bootstrap) return; + const modal = new bootstrap.Modal(modalElement); + modal.show(); + }); + + $$("[data-map-target]").forEach((link) => { + link.addEventListener("click", (event) => { + event.preventDefault(); + const targetId = link.getAttribute("data-map-target"); + const modalEl = $("#mapModal"); + if (modalEl && window.bootstrap) bootstrap.Modal.getInstance(modalEl)?.hide(); + window.setTimeout(() => openSection(targetId), 170); + }); + }); + + const scanBtn = $("#scanLinks"); + const auditStatus = $("#auditStatus"); + const auditResults = $("#auditResults"); + scanBtn?.addEventListener("click", async () => { + scanBtn.disabled = true; + auditStatus.textContent = "Scanning live sourceโ€ฆ"; + auditResults.innerHTML = ""; + try { + const response = await fetch("api/scan_links.php", { headers: { "Accept": "application/json" }}); + if (!response.ok) throw new Error("Scanner returned " + response.status); + const payload = await response.json(); + const known = new Set(JSON.parse(auditResults.dataset.known || "[]").map((u) => normalize(u))); + const rows = (payload.links || []).map((link) => ({ ...link, known: known.has(normalize(link.href)) })); + const newCount = rows.filter((row) => !row.known).length; + const ignored = Number(payload.ignored_count || 0); + const suppressed = Number(payload.suppressed_count || 0); + auditStatus.textContent = `${rows.length} visible source links found ยท ${newCount} not curated ยท ${ignored} noise/asset links ignored ยท ${suppressed} deliberately removed ยท scanned ${payload.scanned_at || "now"}.`; + auditResults.innerHTML = rows.map(renderAuditRow).join(""); + showToast("Live scan complete"); + } catch (error) { + auditStatus.textContent = "Scan failed. The curated structure remains available."; + showToast("Scanner unavailable"); + } finally { + scanBtn.disabled = false; + } + }); + + const structureButtons = [$("#loadStructure"), $("#loadStructureBottom")].filter(Boolean); + const structureStatus = $("#sourceStructureStatus"); + const structureTarget = $("#sourceStructure"); + structureButtons.forEach((button) => { + button.addEventListener("click", () => loadSourceStructure()); + }); + + async function loadSourceStructure() { + if (!structureTarget || !structureStatus) return; + structureButtons.forEach((button) => { button.disabled = true; }); + structureStatus.textContent = "Reading live source icon ownershipโ€ฆ"; + structureTarget.innerHTML = ""; + try { + const response = await fetch("api/scan_structure.php", { headers: { "Accept": "application/json" }}); + if (!response.ok) throw new Error("Structure scanner returned " + response.status); + const payload = await response.json(); + if (!payload.success) throw new Error(payload.error || "Structure scanner failed"); + structureStatus.textContent = `${payload.section_count} source owner icons ยท ${payload.link_count} grouped branch links ยท ${Number(payload.utility_count || 0)} separated utility links ยท scanned ${payload.scanned_at}.`; + structureTarget.innerHTML = ` +
+ Bonus shadow icon + ${(payload.shadow_bonus || []).map((item) => `${escapeHtml(item.icon)} ${escapeHtml(item.title)}`).join("")} +
+ ${renderUtilityChrome(payload.utility_chrome || [])} + ${(payload.sections || []).map(renderSourceSection).join("")} + `; + showToast("Source ownership loaded"); + } catch (error) { + structureStatus.textContent = "Could not load live structure. The curated snapshot above remains available."; + showToast("Source map unavailable"); + scheduleVisibleHighlights(); + } finally { + structureButtons.forEach((button) => { button.disabled = false; }); + } + } + + function renderAuditRow(row) { + const badgeText = row.known ? "curated" : (row.safety === "review" ? "review external" : (row.category || "new")); + const badgeClass = row.known ? "audit-badge-known" : (row.safety === "review" ? "audit-badge-review" : (row.safety === "source" ? "audit-badge-source" : "audit-badge-new")); + const category = String(row.category || "external").replace(/[^a-z0-9-]/gi, "-").toLowerCase(); + return ` + + `; + } + + + function renderUtilityChrome(items) { + if (!items.length) return ""; + return ` +
+ Separated utility chrome + ${items.slice(0, 18).map((item) => `${escapeHtml(item.text || item.href)}`).join("")} +
+ `; + } + + function renderSourceSection(section) { + return ` +
+
+ ${escapeHtml(section.icon)} +
+

${escapeHtml(section.title)}

+ ${escapeHtml(section.source_anchor)} owns ${Number(section.link_count || 0)} links until ${escapeHtml(section.owns_until || "next")} +
+
+

${escapeHtml(section.excerpt || "")}

+ + ${section.layout ? `
${escapeHtml(section.layout.zone || "layout")}${escapeHtml(section.layout.computed || "")}${escapeHtml(section.layout.parent || "")} ยท ${escapeHtml(section.layout.position || "")}${escapeHtml(section.layout.note || "")}
` : ""} + +
+ `; + } + + const highlightableTargetSelector = [ + "[data-section-card][id]", + ".section-card[id]", + ".chapter-card[id]", + ".chapter-reference-card[id]", + ".layout-zone-card[id]", + ".layout-audit[id]", + ".ownership-strip[id]", + ".reference-tools[id]", + ".reference-hero[id]", + ".pdf-library[id]", + ".reference-mode-panel[id]", + ".utility-chrome-panel[id]", + ".source-owner-card[id]", + ".audit-panel[id]", + ".document-shell[id]", + ".console-screen[id]" + ].join(","); + const boxClickTargetSelector = [ + "[data-section-card][id]", + ".section-card[id]", + ".chapter-card[id]", + ".chapter-reference-card[id]", + ".layout-zone-card[id]", + ".layout-audit[id]", + ".ownership-strip[id]", + ".reference-tools[id]", + ".reference-hero[id]", + ".pdf-library[id]", + ".reference-mode-panel[id]", + ".utility-chrome-panel[id]", + ".source-owner-card[id]", + ".audit-panel[id]" + ].join(","); + const targetControlSelector = "[data-highlight-target],[data-owner-target],[data-map-target],a[href^='#']"; + const visibleTargetSelector = highlightableTargetSelector; + const interactiveSelector = "a,button,input,select,textarea,label,summary,[role='button'],[tabindex]:not([tabindex='-1'])"; + + function controlTargetId(control) { + if (!control) return ""; + const direct = control.dataset?.highlightTarget || control.dataset?.ownerTarget || control.dataset?.mapTarget || ""; + if (direct) return direct; + const href = control.getAttribute?.("href") || ""; + if (!href.startsWith("#") || href.length <= 1) return ""; + try { return decodeURIComponent(href.slice(1)); } + catch { return href.slice(1); } + } + + function isElementHidden(el) { + if (!el || !el.isConnected || el.hidden || el.closest("[hidden]")) return true; + const style = window.getComputedStyle(el); + return style.display === "none" || style.visibility === "hidden" || Number(style.opacity || 1) === 0; + } + + function visiblePixels(el) { + const rect = el.getBoundingClientRect(); + const width = Math.max(0, Math.min(rect.right, window.innerWidth) - Math.max(rect.left, 0)); + const height = Math.max(0, Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0)); + return { width, height, area: width * height }; + } + + function isMeaningfullyVisible(el) { + if (!el?.id || isElementHidden(el)) return false; + const visible = visiblePixels(el); + return visible.width >= 20 && visible.height >= 20 && visible.area >= 400; + } + + function visibleTargetIds() { + const ids = new Set(); + $$(visibleTargetSelector).forEach((target) => { + if (isMeaningfullyVisible(target)) ids.add(target.id); + }); + return ids; + } + + function syncVisibleHighlights() { + const visibleIds = visibleTargetIds(); + $$(".is-in-view-target").forEach((el) => el.classList.remove("is-in-view-target")); + $$(".is-visible-owner-link").forEach((el) => el.classList.remove("is-visible-owner-link")); + + visibleIds.forEach((id) => { + document.getElementById(id)?.classList.add("is-in-view-target"); + }); + + $$(targetControlSelector).forEach((control) => { + const targetId = controlTargetId(control); + control.classList.toggle("is-visible-owner-link", Boolean(targetId && visibleIds.has(targetId))); + }); + } + + function scheduleVisibleHighlights() { + window.cancelAnimationFrame(scheduleVisibleHighlights.raf || 0); + scheduleVisibleHighlights.raf = window.requestAnimationFrame(syncVisibleHighlights); + } + + window.addEventListener("scroll", scheduleVisibleHighlights, { passive: true }); + window.addEventListener("resize", scheduleVisibleHighlights, { passive: true }); + window.addEventListener("hashchange", scheduleVisibleHighlights); + + document.addEventListener("click", (event) => { + const box = event.target.closest?.(boxClickTargetSelector); + if (!box?.id) return; + const interactive = event.target.closest(interactiveSelector); + if (interactive && box.contains(interactive)) { + const explicitTarget = controlTargetId(interactive); + if (explicitTarget || !interactive.matches("a[href]")) return; + } + markTarget(box.id, { scroll: false, switchMode: false, toast: !interactive }); + }); + + function openSection(id) { + markTarget(id, { scroll: true, switchMode: true }); + } + + function clearTargetHighlights() { + const activeSelector = [ + ".section-card.is-active", + ".chapter-reference-card.is-active", + ".pdf-card.is-active", + ".layout-zone-card.is-active", + ".layout-audit.is-active", + ".ownership-strip.is-active", + ".reference-tools.is-active", + ".utility-chrome-panel.is-active", + ".source-owner-card.is-active", + ".audit-panel.is-active", + ".reference-hero.is-active", + ".chapter-card.is-active", + ".document-shell.is-active", + ".console-screen.is-active", + ".pdf-library.is-active" + ].join(","); + $$(activeSelector).forEach((el) => el.classList.remove("is-active")); + $$(".is-focus-target,.is-owner-preview,.is-owner-link").forEach((el) => el.classList.remove("is-focus-target", "is-owner-preview", "is-owner-link")); + $$("[aria-current=\"location\"]").forEach((el) => el.removeAttribute("aria-current")); + } + + function markRelatedControls(targetId, lightweight = false) { + $$(targetControlSelector).forEach((el) => { + const match = controlTargetId(el) === targetId; + el.classList.toggle("is-owner-link", match); + if (match && !lightweight) el.setAttribute("aria-current", "location"); + }); + } + + function markTarget(id, options = {}) { + const target = id ? document.getElementById(id) : null; + if (!target) return; + const modePanel = target.closest("[data-mode-panel]"); + if (modePanel && modePanel.hidden && options.switchMode !== false) setReferenceMode(modePanel.dataset.modePanel || "icons", { quiet: true }); + clearTargetHighlights(); + target.classList.add("is-focus-target"); + if (!target.classList.contains("reference-mode-panel")) target.classList.add("is-active"); + markRelatedControls(id, false); + if (options.scroll !== false) { + target.scrollIntoView({ behavior: "smooth", block: "start" }); + if (history.replaceState) history.replaceState(null, "", `#${id}`); + } + window.clearTimeout(markTarget.pulseTimer); + markTarget.pulseTimer = window.setTimeout(() => target.classList.remove("is-focus-target"), 4200); + scheduleVisibleHighlights(); + window.setTimeout(scheduleVisibleHighlights, options.scroll !== false ? 520 : 40); + if (options.toast !== false) showToast(`Pinned ${target.querySelector("h1,h2,h3")?.textContent?.trim() || id}`); + } + + function captureScrollAnchor() { + const y = Math.min(Math.max(120, window.innerHeight * 0.25), window.innerHeight - 1); + const el = document.elementFromPoint(Math.min(90, window.innerWidth - 1), y); + return el ? { el, top: el.getBoundingClientRect().top } : null; + } + + function restoreScrollAnchor(state) { + if (!state || !state.el || !state.el.isConnected) return; + window.requestAnimationFrame(() => { + const diff = state.el.getBoundingClientRect().top - state.top; + if (Math.abs(diff) > 1) window.scrollBy(0, diff); + }); + } + + + scheduleVisibleHighlights(); + + if (window.location.hash && document.getElementById(window.location.hash.slice(1))) { + window.setTimeout(() => openSection(window.location.hash.slice(1)), 250); + } + + function normalize(url) { + try { return new URL(url, "https://spireason.neocities.org/").href.replace(/#$/, ""); } + catch { return String(url || "").trim(); } + } + + function escapeHtml(value) { + return String(value || "").replace(/[&<>"\x27]/g, (char) => { + if (char === "&") return "&"; + if (char === "<") return "<"; + if (char === ">") return ">"; + if (char.charCodeAt(0) === 34) return """; + return "'"; + }); + } + function escapeAttr(value) { return escapeHtml(value); } +})(); diff --git a/curated-links.php b/curated-links.php new file mode 100644 index 0000000..d1d55bb --- /dev/null +++ b/curated-links.php @@ -0,0 +1,334 @@ + "PDF text", + "applet" => "Applet", + "bot" => "External bot/system", + "tool" => "Tool", + "github" => "Repository", + "archive" => "Archive / utility", + "presentation" => "Presentation", + "media" => "Media", + "dataset" => "Dataset", + "source" => "Source file", + "external" => "External system", + "onsite" => "On-site branch", + "branch" => "Branch", + "research" => "Research system", + "manual" => "Manual", + "table" => "Table", + "main-branch" => "Main branch", + ][$category] ?? ucfirst(str_replace("-", " ", $category)); +} + +function section_by_id(array $sections, string $id): ?array +{ + foreach ($sections as $section) { + if (($section["id"] ?? "") === $id) return $section; + } + return null; +} + +function links_for_sections(array $links, array $ids): array +{ + $set = array_fill_keys($ids, true); + return array_values(array_filter($links, static fn(array $link): bool => isset($set[$link["section"] ?? ""]))); +} + +$categoryCounts = []; +foreach ($links as $link) { + $cat = ref_category($link); + $categoryCounts[$cat] = ($categoryCounts[$cat] ?? 0) + 1; +} +ksort($categoryCounts); +$pdfLinks = array_values(array_filter($links, fn($link) => ref_category($link) === "pdf")); +$pdfCount = count($pdfLinks); +$utilityCount = isset($utilityLinks) ? count($utilityLinks) : 0; +?> + + + + + + <?= htmlspecialchars($projectName) ?> + + + + + + + + + + + + + +
+ +
+ +
+
+

CSS-aware reference system

+

Separate console chrome, chapter gates, icon blocks, PDFs, and utility links.

+

+
+ owner icons + branch entries + PDF-only entries + separated utility links +
+
+ Browse icon blocks + Open PDF block + +
+
+ +
+
+

Position model from CSS + computed layout

+

The source is four layers before it is a link list.

+

The public page uses inline CSS, fixed clusters, absolute panels, nested articles/sections, and small JavaScript hover/scroll helpers. This page separates those layers before grouping links.

+
+
+ +
"> + +
+

+

+ CSS: ยท Computed: +
+
+ +
+
+ +
+
+

Icon order + bright pins

+

Tap any icon, chapter pill, or box link to glow the exact owner on the page.

+
+ +
+ +
+ +
+ + + +
+ +
All ยท dim
+
+ $count): ?> + + +
+
+ +
+ + $link["section"] === $section["id"])); $layout = $sectionLayout[$section["id"]] ?? null; ?> + + +
+ + + + + +
+
+

Separated utility chrome

+

After Coffee: footer/download/RSS/lander links are not Coffee-owned branches.

+

These links still exist in the source, but CSS/JS places some of them as fixed or absolute controls. They are listed here only as utility chrome.

+
+ +
+ +
+
+

Live precision scanner

+

Source ownership map from spireason.neocities.org

+

This scanner now reports the same CSS-aware separation: fixed/absolute chrome is not Coffee ownership, and every link keeps its source-order block context when possible.

+
+ +
Not loaded yet.
+
+
+
+ + + + + + + diff --git a/healthz.php b/healthz.php new file mode 100644 index 0000000..fdbd9a8 --- /dev/null +++ b/healthz.php @@ -0,0 +1,4 @@ + true, 'time' => gmdate('c'), 'php' => PHP_VERSION]); diff --git a/includes/curated_data.php b/includes/curated_data.php new file mode 100644 index 0000000..29f7394 --- /dev/null +++ b/includes/curated_data.php @@ -0,0 +1,206 @@ +'shadow-books','icon'=>'๐ŸŒ‘','title'=>'Books of Shadows','summary'=>'Bonus prelude before the standard icon sequence: Dancing Shadows, Book of Shadows 2, and Bulk Load Book of the Dead 3.','chapter'=>'Console โ†’ Shadow Prelude','tone'=>'shadow','source_count'=>3,'source_until'=>'#growing-out-of-the-shadows'], + ['id'=>'growing-out-of-the-shadows','icon'=>'โš›๏ธ','title'=>'Growing Out of the Shadows','summary'=>'Archetype, shadow, Wu Wei, AI narrative, illumination games, repositories, and the large shadow-story prelude before the counter material.','chapter'=>'Console โ†’ Document','tone'=>'atomic','source_count'=>42,'source_until'=>'#sheep'], + ['id'=>'sheep','icon'=>'๐Ÿ‘','title'=>'Sheep / Laegna Counters','summary'=>'Laegna number-learning area: sheep counters, logecs counter, octave counter, manuals, scripts, JSON/databases, coordinate visualizers, and counterspace introductions. No video-player links belong here.','chapter'=>'Document ยท counters','tone'=>'pastoral','source_count'=>32,'source_until'=>'#infinity'], + ['id'=>'infinity','icon'=>'โ™พ๏ธ','title'=>'Infinity','summary'=>'Infinity portals, Simply about Infinities, Laegna manual, theorem repositories, physical infinity simulations, count/matter, proponential and infinity runtime surfaces.','chapter'=>'โœฆ Foundational Texts','tone'=>'infinite','source_count'=>23,'source_until'=>'#natura'], + ['id'=>'natura','icon'=>'๐ŸŒ€','title'=>'Natura','summary'=>'Compact nature/war/polarity opening: Holy War and the positive/negative text.','chapter'=>'โœฆ Foundational Texts','tone'=>'spiral','source_count'=>2,'source_until'=>'#sunrise'], + ['id'=>'sunrise','icon'=>'๐Ÿ”†','title'=>'Sunrise','summary'=>'Material Magic and practical-spiritual PDFs: imperfection, karma, star children, material truth, Buddhism/Christianity comparison, tuning, meditation polarity, conflict psychology, and an overview of the two parts.','chapter'=>'โœฆ Foundational Texts','tone'=>'solar','source_count'=>19,'source_until'=>'#bigbang'], + ['id'=>'bigbang','icon'=>'๐Ÿ’ฅ','title'=>'Bigbang','summary'=>'Spireason starting pair: Karma as Spireason 1, its add-on, and Evolution as Spireason 2.','chapter'=>'โŸฒ Continuing Studies','tone'=>'burst','source_count'=>3,'source_until'=>'#yggdrasill'], + ['id'=>'yggdrasill','icon'=>'๐ŸŒณ','title'=>'Yggdrasill','summary'=>'Tree-like continuation through meditation, truth tables, reincarnation, root chakra, material meditation, SOMA, magic as mental image, and karma/rationality notes.','chapter'=>'โŸฒ Continuing Studies','tone'=>'tree','source_count'=>10,'source_until'=>'#spiritrise'], + ['id'=>'spiritrise','icon'=>'๐Ÿ”ท','title'=>'Spiritrise','summary'=>'Chakra frequency, metaphysical/lifelike structures, Logecs and E factor, social archetype, spiritual/material logecs, skepticism/science, and a collaboration presentation.','chapter'=>'โŸฒ Continuing Studies','tone'=>'crystal','source_count'=>8,'source_until'=>'#laelab'], + ['id'=>'laelab','icon'=>'๐Ÿ”ฌ','title'=>'LaeLab','summary'=>'Conceptual lab text in the source: Laegna theory, lived experience, infinity, mathematics, logec, AI modelling, and resonant source frameworks.','chapter'=>'โŸฒ Continuing Studies','tone'=>'lab','source_count'=>0,'source_until'=>'#geneticar'], + ['id'=>'geneticar','icon'=>'๐Ÿงฌ','title'=>'Geneticar','summary'=>'AI-native Laegna modelling and visualizations: atomic, molecular, and genetic surfaces.','chapter'=>'โŸฒ Continuing Studies','tone'=>'helix','source_count'=>4,'source_until'=>'#handheldcal'], + ['id'=>'handheldcal','icon'=>'๐Ÿ–ฉ','title'=>'HandheldCal / Resonant Calculus','summary'=>'Laegna math introduction, Exponometer concept, Frequential Calculator, Octavial Calculator, and a relativity simplification branch.','chapter'=>'Tools','tone'=>'tool','source_count'=>5,'source_until'=>'#puzzled'], + ['id'=>'puzzled','icon'=>'๐Ÿงฉ','title'=>'Puzzled / Source Texts','summary'=>'GitHub root and formal source repositories behind Laegna AI, calculators, integrals, and LaeMath.','chapter'=>'Document ยท source','tone'=>'puzzle','source_count'=>4,'source_until'=>'#chakra'], + ['id'=>'chakra','icon'=>'โœด๏ธ','title'=>'Chakra','summary'=>'SpiRe primitives, Trinity, frequency/body/plane, enlightenment, infinity boundaries, infinite circle, exterior, and infinities playground.','chapter'=>'โœฆ Foundational Texts','tone'=>'center','source_count'=>8,'source_until'=>'#wheelsgoround'], + ['id'=>'wheelsgoround','icon'=>'โš™๏ธ','title'=>'Wheels Go Round','summary'=>'Open-source and cloneable calculator backbone: OS page, frequency/harmonics calculator, and Octave/Exponometer repository.','chapter'=>'โŸฒ Continuing Studies','tone'=>'gear','source_count'=>3,'source_until'=>'#laemedics'], + ['id'=>'laemedics','icon'=>'๐Ÿง˜','title'=>'LaeMedics / SpiBody','summary'=>'SpiBody/SpiZenTao health and body-research anchors, continuation jump, lettering for spheres, and Kybalion reference.','chapter'=>'โœฆ Foundational Texts','tone'=>'calm','source_count'=>5,'source_until'=>'#coffeeandcigarettes'], + ['id'=>'coffeeandcigarettes','icon'=>'โ˜•','title'=>'Coffee and Cigarettes / Terminal Notes','summary'=>'Terminal prose and reading guidance. The visual source has no Coffee-owned branch links; footer/archive/RSS/lander/scroll controls after it are utility chrome, not part of this owner.','chapter'=>'Terminal prose','tone'=>'archive','source_count'=>0,'source_until'=>'utility chrome'], +]; + +$links = [ + ['section'=>'shadow-books','icon'=>'๐ŸŽญ','name'=>'Dancing Shadows ยท Material Psychic Game','href'=>'https://material-psychic-gam-8mo3.bolt.host/','kind'=>'applet','summary'=>'Interactive archetype/shadow game from the pre-icon shadow prelude.'], + ['section'=>'shadow-books','icon'=>'๐Ÿ“˜','name'=>'Book of Shadows 2','href'=>'https://app-bxfrqbbqegap.appmedo.com/','kind'=>'applet','summary'=>'Four-history symbolic frame: childhood unity, frozen roles, satire, illumination.'], + ['section'=>'shadow-books','icon'=>'๐Ÿ“•','name'=>'Bulk Load Book of the Dead 3','href'=>'https://app-by9gm7mu9ssh.appmedo.com/','kind'=>'applet','summary'=>'Dark glowing index of conspiracy, matter, murder, and illumination narratives.'], + ['section'=>'growing-out-of-the-shadows','icon'=>'โš›๏ธ','name'=>'Tales and Stories of Me and an AI','href'=>'https://github.com/tambetvali/TalesAndStoriesOfMeAndAnAI/','kind'=>'github','summary'=>'Root repository for the AI/narrative shadow-story branch.'], + ['section'=>'growing-out-of-the-shadows','icon'=>'๐Ÿง ','name'=>'Tales Illuminated','href'=>'https://tales-illuminated.lovable.app/','kind'=>'applet','summary'=>'Simplified interactive illumination version of the shadow-story material.'], + ['section'=>'growing-out-of-the-shadows','icon'=>'๐Ÿ•ฏ๏ธ','name'=>'Simulations of Illumination','href'=>'https://github.com/tambetvali/IlluminationSimulatorCapable','kind'=>'github','summary'=>'Repository for illumination simulator material.'], + ['section'=>'wheelsgoround','icon'=>'โš™๏ธ','name'=>'Contribute','href'=>'https://spireason.neocities.org/repos.html','kind'=>'branch','summary'=>'Repository and contribution entry point for the network.'], + ['section'=>'sunrise','icon'=>'Study','name'=>'Laegna Study','href'=>'https://laegna.notaku.site/','kind'=>'main branch','summary'=>'Central Notaku study manual branch.'], + ['section'=>'puzzled','icon'=>'?','name'=>'Prezi intermediate introduction','href'=>'https://prezi.com/view/8jmEfNRocsOrwNAP8ejz/?referral_token=G4RyDElnB3FN','kind'=>'presentation','summary'=>'Question-mark explanatory bridge.'], + ['section'=>'yggdrasill','icon'=>'Chat','name'=>'Bots','href'=>'https://spireason.neocities.org/Additional/bots.html','kind'=>'bot','summary'=>'Chat and bot collection; categorized separately from source/PDF resources.'], + ['section'=>'laelab','icon'=>'Find','name'=>'Perplexity Space','href'=>'https://www.perplexity.ai/spaces/laegna-spireason-and-related-m-dLTaZz8CSd2FUCjIiYQARA','kind'=>'research','summary'=>'External research/search space for the knowledge network.'], + ['section'=>'wheelsgoround','icon'=>'Apps','name'=>'Apps','href'=>'https://spireason.neocities.org/apples.html','kind'=>'applet','summary'=>'Application branch list.'], + ['section'=>'handheldcal','icon'=>'๐ŸŽถ','name'=>'Frequency Calculator','href'=>'https://3oumxxajlfzw2.mocha.app/','kind'=>'tool','summary'=>'Harmonics/frequential calculator app; essential numeric Laegna tool.'], + ['section'=>'handheldcal','icon'=>'๐Ÿ“ˆ','name'=>'Octavial / Exponometer Calculator','href'=>'https://accelerative-complex-6gs6.bolt.host/','kind'=>'tool','summary'=>'Source-listed octavial calculator / Exponometer surface.'], + ['section'=>'handheldcal','icon'=>'๐Ÿ“ˆ','name'=>'Octave Counter','href'=>'https://spireason.neocities.org/Playground/OctaveCounter/','kind'=>'tool','summary'=>'On-site Laegna octave counter and exponometer path.'], + ['section'=>'sunrise','icon'=>'โž”','name'=>'Introduce','href'=>'https://prezi.com/view/JHeiwaeN6qqPG3h5RMRd/?referral_token=G4RyDElnB3FN','kind'=>'presentation','summary'=>'Introductory presentation path.'], + ['section'=>'wheelsgoround','icon'=>'๐Ÿ“ฆ','name'=>'PDFs.zip','href'=>'https://huggingface.co/datasets/tvaeli/LaegnaSpi/resolve/main/Spireason.zip','kind'=>'archive','summary'=>'Critical downloadable archive of PDFs.'], + ['section'=>'coffeeandcigarettes','icon'=>'๐ŸŽฌ','name'=>'Top Video Selection','href'=>'https://assorted-canopy-961.notion.site/Laegna-1a575bfc115480a38129e9a9787ab565','kind'=>'media','summary'=>'Curated video landing branch, intentionally outside Sheep.'], + ['section'=>'coffeeandcigarettes','icon'=>'โ–ถ๏ธ','name'=>'YouTube Channel','href'=>'https://www.youtube.com/@TambetV%C3%A4li','kind'=>'media','summary'=>'Main YouTube channel, intentionally outside Sheep.'], + + ['section'=>'sheep','icon'=>'๐Ÿ–ผ๏ธ','name'=>'Sheep Intro','href'=>'https://laegna-wave-decoder.lovable.app/','kind'=>'applet','summary'=>'Introductory visual decoder for the sheep/counter learning area.'], + ['section'=>'sheep','icon'=>'๐Ÿ‘','name'=>'Laegna Sheep Counter โถ','href'=>'https://spireason.neocities.org/Playground/SheepCounter1/sheepiotae.html','kind'=>'tool','summary'=>'Ordinary/logecs math sheep counter for learning Laegna numbers by counting.'], + ['section'=>'sheep','icon'=>'๐Ÿ“œ','name'=>'Sheep Counter Manual','href'=>'https://spireason.neocities.org/Playground/SheepCounter1/manual.html','kind'=>'manual','summary'=>'Manual for the first sheep counter.'], + ['section'=>'sheep','icon'=>'๐Ÿ‘๐Ÿ‘','name'=>'Laegna Logecs Counter โท','href'=>'https://spireason.neocities.org/Playground/SheepCounter1/sheepiotae1.html','kind'=>'tool','summary'=>'Companion counter for logical structures of Laegna systems.'], + ['section'=>'sheep','icon'=>'๐Ÿ“–','name'=>'Number System Manual','href'=>'https://spireason.neocities.org/Playground/SheepCounter1/manual','kind'=>'manual','summary'=>'Number-system manual linked from the sheep section.'], + ['section'=>'sheep','icon'=>'๐Ÿ“','name'=>'SheepCounter Folder','href'=>'https://spireason.neocities.org/Playground/SheepCounter1/','kind'=>'source','summary'=>'Open folder for the sheep counter resources.'], + ['section'=>'sheep','icon'=>'๐Ÿ“œ','name'=>'sheepdebug script','href'=>'https://spireason.neocities.org/Playground/SheepCounter1/sheepdebug.html','kind'=>'source','summary'=>'Visible script/debug timeline for the sheep counter.'], + ['section'=>'sheep','icon'=>'๐Ÿ–ฅ๏ธ','name'=>'sheepdebug human table','href'=>'https://spireason.neocities.org/Playground/SheepCounter1/sheepdebug','kind'=>'table','summary'=>'Human number table/debug view.'], + ['section'=>'sheep','icon'=>'๐Ÿ’ป','name'=>'sheepcounter.json','href'=>'https://spireason.neocities.org/Playground/SheepCounter1/sheepcounter.json','kind'=>'dataset','summary'=>'AI/machine-readable sheep counter dataset.'], + ['section'=>'sheep','icon'=>'๐Ÿงฌ','name'=>'sheepjason generator','href'=>'https://spireason.neocities.org/Playground/SheepCounter1/sheepjason.html','kind'=>'source','summary'=>'Number data generator used by the counter.'], + ['section'=>'sheep','icon'=>'๐Ÿ‘','name'=>'Laegna Sheep Counter โธ','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/PlaceholderResearchitem/','kind'=>'tool','summary'=>'Mathematecs/higher-math counter branch.'], + ['section'=>'sheep','icon'=>'๐Ÿ“œ','name'=>'Inference counter manual','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/PlaceholderResearchitem/manual.html','kind'=>'manual','summary'=>'Manual for the higher-math inference counter.'], + ['section'=>'sheep','icon'=>'โŸฃ','name'=>'Waveweaver Tails and Bones','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/Trailer/tailandbones','kind'=>'applet','summary'=>'Tails-and-bones visualization under the inference counter branch.'], + ['section'=>'sheep','icon'=>'โŸข','name'=>'Dragontail visualization','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/dragontail.html','kind'=>'applet','summary'=>'Coordinate/dragontail visualization.'], + ['section'=>'sheep','icon'=>'โ–ง','name'=>'Angry birds wrap the coordinates','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/angryspacebirdsbirdswwrap.html','kind'=>'applet','summary'=>'Coordinate wrapping visualizer.'], + ['section'=>'sheep','icon'=>'โ–ค','name'=>'Flat List','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/numberdatabase/flatlist/','kind'=>'dataset','summary'=>'Flat number database list.'], + ['section'=>'sheep','icon'=>'{}','name'=>'JSON List','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/numberdatabase/complete.json','kind'=>'dataset','summary'=>'Complete JSON number database.'], + ['section'=>'sheep','icon'=>'๐Ÿ‘๐Ÿ‘','name'=>'Laegna Octave Counter','href'=>'https://spireason.neocities.org/Playground/OctaveCounter/','kind'=>'tool','summary'=>'Octave counter under the sheep learning area.'], + ['section'=>'sheep','icon'=>'โš–๏ธ','name'=>'Octave strict decoder','href'=>'https://spireason.neocities.org/Playground/OctaveCounter/decoder.html','kind'=>'tool','summary'=>'Strict octave decoder.'], + ['section'=>'sheep','icon'=>'๐Ÿ“˜','name'=>'Octave formal manual','href'=>'https://spireason.neocities.org/Playground/OctaveCounter/manual.html','kind'=>'manual','summary'=>'Formal manual for the octave counter.'], + ['section'=>'sheep','icon'=>'๐Ÿ”ท','name'=>'Octave spiritual manual','href'=>'https://spireason.neocities.org/Playground/OctaveCounter/spirit.html','kind'=>'manual','summary'=>'Spiritual reading of the octave counter.'], + ['section'=>'sheep','icon'=>'๐Ÿ','name'=>'Octave decoder.py','href'=>'https://spireason.neocities.org/Playground/OctaveCounter/decoder.py','kind'=>'source','summary'=>'Visible Python decoder source.'], + ['section'=>'sheep','icon'=>'{}','name'=>'octaves.json','href'=>'https://spireason.neocities.org/Playground/OctaveCounter/octaves.json','kind'=>'dataset','summary'=>'Octave JSON database.'], + ['section'=>'sheep','icon'=>'๐Ÿ“','name'=>'InferenceCounter Folder','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/','kind'=>'source','summary'=>'Open folder for inference counter resources.'], + ['section'=>'sheep','icon'=>'๐Ÿ“œ','name'=>'Inference script/user manual','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/userman.html','kind'=>'manual','summary'=>'User manual/script for inference counter.'], + ['section'=>'sheep','icon'=>'๐Ÿ“บ','name'=>'Number database view','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/numberdatum.html','kind'=>'table','summary'=>'Human-readable number database view.'], + ['section'=>'sheep','icon'=>'๐Ÿ–ฅ๏ธ','name'=>'numbers.bin.json','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/numbers.bin.json','kind'=>'dataset','summary'=>'Base-2 custom JSON number data.'], + ['section'=>'sheep','icon'=>'๐Ÿ’ป','name'=>'animation.json','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/animation.json','kind'=>'dataset','summary'=>'Base-4 compiled animation JSON.'], + ['section'=>'sheep','icon'=>'๐Ÿงฌ','name'=>'animatorjson generator','href'=>'https://spireason.neocities.org/Playground/InferenceCounter/animatorjson.html','kind'=>'source','summary'=>'Generator from genetic.py to numbers.json.'], + ['section'=>'sheep','icon'=>'โ˜ฏ','name'=>'Laegna Counterspaces Hologram','href'=>'https://spireason.neocities.org/counterspaces.html','kind'=>'applet','summary'=>'Counterspaces hologram introduction.'], + ['section'=>'sheep','icon'=>'๐ŸŒŒ','name'=>'Grand Introduction','href'=>'https://materialmagic.floot.app/','kind'=>'applet','summary'=>'Grand introduction linked from the sheep/counterspace run.'], + ['section'=>'sheep','icon'=>'๐ŸŒˆ','name'=>'The Unified Spectrum','href'=>'https://coreweave-cosmos.lovable.app/','kind'=>'applet','summary'=>'Unified spectrum continuation link.'], + + ['section'=>'infinity','icon'=>'โ™พ๏ธ','name'=>'Simply about Infinities','href'=>'https://spireason.neocities.org/Simply%20about%20Infinities.pdf','kind'=>'pdf','summary'=>'Core infinity document.'], + ['section'=>'infinity','icon'=>'๐Ÿ“š','name'=>'Laegna Manual','href'=>'https://laegna.notaku.site/#1ac75bfc1154809b8037da3fbfaaf000','kind'=>'manual','summary'=>'Manual entry for infinity and related theory.'], + ['section'=>'infinity','icon'=>'๐Ÿ“™','name'=>'Science Study','href'=>'https://github.com/tambetvali/LaeSpiEssentialTheorems/tree/main/LaegnaTheorems/InfinityAndZero','kind'=>'github','summary'=>'Infinity and zero theorem source material.'], + ['section'=>'infinity','icon'=>'๐ŸŸช','name'=>'Infinities are Logecs','href'=>'https://github.com/tambetvali/FuzzyLogecs/','kind'=>'github','summary'=>'Logecs and infinity source branch.'], + ['section'=>'infinity','icon'=>'โ™ˆ','name'=>'Count and Matter','href'=>'https://laegnanumbers.freebuff.app/','kind'=>'applet','summary'=>'Source-listed count/matter surface.'], + + ['section'=>'natura','icon'=>'โš”๏ธ','name'=>'Holy War','href'=>'https://spireason.neocities.org/Holy%20War.pdf','kind'=>'pdf','summary'=>'Foundational spiritual conflict document.'], + ['section'=>'natura','icon'=>'โ˜ฏ๏ธ','name'=>'Short Text about Positive and Negative','href'=>'https://spireason.neocities.org/Short%20Text%20about%20what%20I%20say%20about%20Positive%20and%20Negative.pdf','kind'=>'pdf','summary'=>'Positive/negative conceptual frame.'], + + ['section'=>'sunrise','icon'=>'โœจ','name'=>'Principles of Material Magic','href'=>'https://spireason.neocities.org/Principles%20of%20Material%20Magic.pdf','kind'=>'pdf','summary'=>'Material magic foundation document.'], + ['section'=>'sunrise','icon'=>'๐ŸŒธ','name'=>'Principles of Material Magic โ€“ short version','href'=>'https://spireason.neocities.org/Principles%20of%20Material%20Magic%20%E2%80%93%20short%20version.pdf','kind'=>'pdf','summary'=>'Compact companion version.'], + ['section'=>'sunrise','icon'=>'โš ๏ธ','name'=>'The Power of Negative Thinking','href'=>'https://spireason.neocities.org/The%20Power%20of%20Negative%20Thinking.pdf','kind'=>'pdf','summary'=>'Critical karma/logecs document.'], + ['section'=>'sunrise','icon'=>'โš–๏ธ','name'=>'The Law of Imperfection and Karma','href'=>'https://spireason.neocities.org/The%20Law%20of%20Imperfection%20and%20Karma.pdf','kind'=>'pdf','summary'=>'Karma and imperfection study.'], + ['section'=>'sunrise','icon'=>'โญ','name'=>'One Short Theory about Star Children','href'=>'https://spireason.neocities.org/One%20Short%20Theory%20about%20Star%20Children.pdf','kind'=>'pdf','summary'=>'Spiritual child/star theory text.'], + ['section'=>'sunrise','icon'=>'๐Ÿ“œ','name'=>'The Material Laws of Truth','href'=>'https://spireason.neocities.org/The%20Material%20Laws%20of%20Truth.pdf','kind'=>'pdf','summary'=>'Truth and material law document.'], + ['section'=>'sunrise','icon'=>'๐Ÿ“–','name'=>'Comparison of, mostly, Buddhism and Christianity','href'=>'https://spireason.neocities.org/Comparison%20of,%20mostly,%20Buddhism%20and%20Christianity.pdf','kind'=>'pdf','summary'=>'Comparative religious/spiritual text.'], + ['section'=>'sunrise','icon'=>'๐Ÿ“ก','name'=>'Tuning into Material Reality','href'=>'https://spireason.neocities.org/Tuning%20into%20Material%20Reality.pdf','kind'=>'pdf','summary'=>'Applied reality-tuning document.'], + ['section'=>'sunrise','icon'=>'โ˜ฏ๏ธ','name'=>'Yin and Yang in Meditation','href'=>'https://spireason.neocities.org/Yin%20and%20Yang%20in%20Meditation.pdf','kind'=>'pdf','summary'=>'Meditation and polarity study.'], + ['section'=>'sunrise','icon'=>'๐Ÿ’ฌ','name'=>'Healthy Conflict Psychology','href'=>'https://spireason.neocities.org/Healthy%20Conflict%20Psychology.pdf','kind'=>'pdf','summary'=>'Practical psychology document.'], + + ['section'=>'bigbang','icon'=>'๐ŸŒฑ','name'=>'Karma','href'=>'https://spireason.neocities.org/Karma.pdf','kind'=>'pdf','summary'=>'Spireason 1 / first core text.'], + ['section'=>'bigbang','icon'=>'๐Ÿ“','name'=>'Evolution','href'=>'https://spireason.neocities.org/Evolution.pdf','kind'=>'pdf','summary'=>'Spireason 2 / second core text.'], + + ['section'=>'yggdrasill','icon'=>'๐Ÿง˜','name'=>'Meditation and Position','href'=>'https://spireason.neocities.org/Meditation%20and%20Position.pdf','kind'=>'pdf','summary'=>'Body position and meditation.'], + ['section'=>'yggdrasill','icon'=>'โš›๏ธ','name'=>'Truth Value Tables, Matter and Mind','href'=>'https://spireason.neocities.org/Truth%20Value%20Tables,%20Matter%20and%20Mind.pdf','kind'=>'pdf','summary'=>'Logic/alchemistry table document.'], + ['section'=>'yggdrasill','icon'=>'โ™ป๏ธ','name'=>'The Simpler Theorem of Karma','href'=>'https://spireason.neocities.org/The%20Simpler%20Theorem%20of%20Karma.pdf','kind'=>'pdf','summary'=>'Karma theorem simplification.'], + ['section'=>'yggdrasill','icon'=>'๐Ÿ”„','name'=>'Reincarnation Basics','href'=>'https://spireason.neocities.org/Reincarnation%20Basics.pdf','kind'=>'pdf','summary'=>'Reincarnation foundation notes.'], + ['section'=>'yggdrasill','icon'=>'๐Ÿ”ด','name'=>'Material Alchemy and Root Chakra','href'=>'https://spireason.neocities.org/Material%20Alchemy%20and%20Root%20Chakra.pdf','kind'=>'pdf','summary'=>'Root chakra and material alchemy.'], + ['section'=>'yggdrasill','icon'=>'๐Ÿ’ญ','name'=>'Karma and Material Meditation','href'=>'https://spireason.neocities.org/Karma%20and%20Material%20Meditation.pdf','kind'=>'pdf','summary'=>'Karma in meditative material frame.'], + ['section'=>'yggdrasill','icon'=>'๐Ÿ”ฎ','name'=>'Magic as Mental Image','href'=>'https://spireason.neocities.org/Magic%20as%20Mental%20Image.pdf','kind'=>'pdf','summary'=>'Mental-image theory of magic.'], + ['section'=>'yggdrasill','icon'=>'โ•ผโ–ฃโ•พ','name'=>'SOMA: Enter into Material World','href'=>'https://soma-material-path.lovable.app/','kind'=>'applet','summary'=>'SOMA material-world applet from the tree section.'], + + ['section'=>'spiritrise','icon'=>'๐Ÿ“ถ','name'=>'Frequential Analysis of System of Chakras in Buddhism','href'=>'https://spireason.neocities.org/Frequential%20Analysis%20of%20System%20of%20Chakras%20in%20Buddhism.pdf','kind'=>'pdf','summary'=>'Frequency/chakra bridge document.'], + ['section'=>'spiritrise','icon'=>'โ“','name'=>'Logecs and E factor โ€“ what is bad in positive affirmations','href'=>'https://spireason.neocities.org/Logecs%20and%20E%20factor%20%E2%80%93%20what%20is%20bad%20in%20positive%20affirmations.pdf','kind'=>'pdf','summary'=>'Positive affirmations critique via logecs.'], + ['section'=>'spiritrise','icon'=>'๐Ÿ“‹','name'=>'Spiritual Logecs Cheat Sheet','href'=>'https://spireason.neocities.org/Additional/bizpon','kind'=>'table','summary'=>'Spiritual logecs/Posegation reference.'], + ['section'=>'spiritrise','icon'=>'๐Ÿ“‹','name'=>'Material Logecs','href'=>'https://spireason.neocities.org/Additional/Ponegatetables.pdf','kind'=>'table','summary'=>'Ponegation/material logic tables.'], + ['section'=>'spiritrise','icon'=>'๐Ÿ”ฌ','name'=>'Skepticism and Science for Spiritual People','href'=>'https://spireason.neocities.org/Skepticism%20and%20Science%20for%20Spiritual%20People.pdf','kind'=>'pdf','summary'=>'Science bridge for spiritual readers.'], + ['section'=>'spiritrise','icon'=>'๐ŸŒ','name'=>'Laegna and Spireason: be the Force','href'=>'https://docs.google.com/presentation/d/e/2PACX-1vSHZ-w9sdtsUNt4T73wTpPIRNSDALDZ_Xph5NLDIMhFSdOaKkCi2tMddQI8Yuh_gQ/pub?start=false&loop=false','kind'=>'presentation','summary'=>'Collaboration presentation from the source.'], + + ['section'=>'geneticar','icon'=>'๐Ÿค–','name'=>'Laegna AI โ€” Intro to Intelligent Modelling','href'=>'https://nexus-warp.lovable.app/','kind'=>'applet','summary'=>'AI-native introduction to intelligent modelling.'], + ['section'=>'geneticar','icon'=>'โš›๏ธ','name'=>'Atomic Visualization of AI','href'=>'https://chem-visions-ai.lovable.app/','kind'=>'applet','summary'=>'Atomic AI visualization.'], + ['section'=>'geneticar','icon'=>'โŸ','name'=>'Molecular Visualization of AI','href'=>'https://mind-spark-visions.lovable.app/','kind'=>'applet','summary'=>'Molecular AI visualization.'], + ['section'=>'geneticar','icon'=>'๐ŸŒ„','name'=>'Genetic Visualization of AI','href'=>'https://ai-jungle-viz.lovable.app/','kind'=>'applet','summary'=>'Genetic AI visualization.'], + + ['section'=>'puzzled','icon'=>'โˆฟ','name'=>'Laegna Source Texts โ€” GitHub Space','href'=>'https://github.com/tambetvali','kind'=>'github','summary'=>'Root GitHub space behind Laegna source texts.'], + ['section'=>'puzzled','icon'=>'๐Ÿงฌ','name'=>'Basis for Laegna AI Visualization','href'=>'https://github.com/tambetvali/LaegnaAIHDvisualization','kind'=>'github','summary'=>'Source basis for Laegna AI visualization.'], + ['section'=>'puzzled','icon'=>'๐Ÿ“˜','name'=>'Basis for Laegna Calculators & Integrals','href'=>'https://github.com/tambetvali/LaeMath/blob/main/MathFuncs/Docs/README.md','kind'=>'github','summary'=>'Calculator/integral documentation.'], + ['section'=>'puzzled','icon'=>'โŒ‚','name'=>'LaeMath home page','href'=>'https://github.com/tambetvali/LaeMath','kind'=>'github','summary'=>'LaeMath repository home.'], + + ['section'=>'chakra','icon'=>'๐ŸŒ€','name'=>'SpiRe Primitives','href'=>'https://spireason.neocities.org/elementchakra.html','kind'=>'onsite','summary'=>'Symbolic correspondences between elements, bodies, and philosophical systems.'], + ['section'=>'chakra','icon'=>'๐Ÿ“˜','name'=>'Frequency, Body and Plane','href'=>'https://spireason.neocities.org/freqbodyplane','kind'=>'onsite','summary'=>'Frequency/body/plane reference.'], + ['section'=>'chakra','icon'=>'โœจ','name'=>'Enlightenment Atlas','href'=>'https://spireason.neocities.org/enlightenment.html','kind'=>'onsite','summary'=>'Enlightenment atlas branch.'], + ['section'=>'chakra','icon'=>'โญ•','name'=>'Infinite Circle','href'=>'https://github.com/tambetvali/Landscopes/blob/main/Landscapes/infinitecircle.md','kind'=>'github','summary'=>'Infinite circle landscape note.'], + ['section'=>'chakra','icon'=>'๐ŸŒŒ','name'=>'Exterior','href'=>'https://github.com/tambetvali/Landscopes/blob/main/Landscapes/exterior.md','kind'=>'github','summary'=>'Exterior landscape note.'], + + ['section'=>'wheelsgoround','icon'=>'โš™๏ธ','name'=>'Laegna Calculators โ€” Open Source & Cloneable','href'=>'https://spireason.neocities.org/os.html','kind'=>'onsite','summary'=>'Open-source calculator hub.'], + ['section'=>'wheelsgoround','icon'=>'๐Ÿ”ข','name'=>'Frequency / Harmonics Calculator Source','href'=>'https://getmocha.com/apps/01995d5d-50b9-759c-8547-535df4800815','kind'=>'tool','summary'=>'Source-listed frequency/harmonics calculator.'], + ['section'=>'wheelsgoround','icon'=>'๐Ÿ“ˆ','name'=>'Octave / Exponometer Calculator Source','href'=>'https://github.com/tambetvali/exponometer.app','kind'=>'github','summary'=>'Open-source Octave/Exponometer calculator repository.'], + + ['section'=>'laemedics','icon'=>'๐Ÿ—‚๏ธ','name'=>'Laegna SpiBody โ€” Core Directory','href'=>'https://4ycacx8u7s.youware.app','kind'=>'applet','summary'=>'Core SpiBody directory and external anchor.'], + ['section'=>'laemedics','icon'=>'๐ŸŒฑ','name'=>'SpiBody Unified Theory','href'=>'https://embeddable.live/embed/Utg4YGE0tV','kind'=>'applet','summary'=>'Central SpiBody site.'], + ['section'=>'laemedics','icon'=>'๐ŸŒฌ๏ธ','name'=>'SpiZenTao','href'=>'https://eal22hc5nr.youware.app/','kind'=>'applet','summary'=>'SpiBody 2 trivia and intuitive insights.'], + ['section'=>'laemedics','icon'=>'๐Ÿงญ','name'=>'Continue basic lettering for spheres','href'=>'https://spireason.neocities.org/exceetaebox.html','kind'=>'onsite','summary'=>'Continuation for sphere lettering.'], + ['section'=>'laemedics','icon'=>'๐Ÿ“œ','name'=>'Kybalion','href'=>'https://archive.org/details/kybalionstudyofh00init','kind'=>'archive','summary'=>'Hermetic philosophy reference.'], + + ['section'=>'coffeeandcigarettes','icon'=>'๐Ÿค','name'=>'Open creations','href'=>'https://spireason.neocities.org/collaborate.html','kind'=>'onsite','summary'=>'Collaboration/creation branch.'], + ['section'=>'coffeeandcigarettes','icon'=>'๐Ÿ“š','name'=>'Access Spireason + Laegna','href'=>'https://huggingface.co/datasets/tvaeli/LaegnaSpi/tree/main','kind'=>'archive','summary'=>'Dataset/archive home for Spireason + Laegna.'], + ['section'=>'coffeeandcigarettes','icon'=>'๐Ÿ“š','name'=>'Mar 19 2025 Texts archive','href'=>'https://huggingface.co/datasets/tvaeli/LaegnaSpi/resolve/main/Spireason.zip','kind'=>'archive','summary'=>'Text archive download.'], + ['section'=>'coffeeandcigarettes','icon'=>'๐Ÿ—„๏ธ','name'=>'17.05.2026 Database archive','href'=>'https://github.com/tambetvali/SpireasonWebsite17052026/archive/refs/heads/main.zip','kind'=>'archive','summary'=>'Database/source archive.'], + ['section'=>'coffeeandcigarettes','icon'=>'RSS','name'=>'RSS','href'=>'https://spireason.neocities.org/atom.html','kind'=>'onsite','summary'=>'RSS feed.'], + ['section'=>'coffeeandcigarettes','icon'=>'๐ŸŒŸ','name'=>'Lander1','href'=>'https://spireason.freebuff.app/','kind'=>'external','summary'=>'External landing branch.'], +]; + +// Links that appear after the Coffee icon in source are footer/download/navigation chrome. +// Keep them available for layout notes, but do not treat them as Coffee-owned branch links. +$utilityLinks = array_values(array_filter($links, static fn(array $link): bool => ($link['section'] ?? '') === 'coffeeandcigarettes')); +$links = array_values(array_filter($links, static fn(array $link): bool => ($link['section'] ?? '') !== 'coffeeandcigarettes')); + +$layoutZones = [ + ['id'=>'first-panel','icon'=>'โ–ฃ','title'=>'First 100vh console panel','css'=>'root absolute panel: position:absolute; top:0; padding-left/right:120px','computed'=>'Starts y=0; roughly 38 visible anchors before the document flow.','summary'=>'The welcome/console area is its own positioned surface, not the same stream as the document icons. It contains center links and is overlaid by fixed side/top menus.'], + ['id'=>'fixed-chrome','icon'=>'โŒ–','title'=>'Fixed static buttons around the viewport','css'=>'fixed clusters: left square-buttons/local-buttons, right city-buttons, top-right menu; some inner links are relative/absolute','computed'=>'Left fixed xโ‰ˆ20, right fixed xโ‰ˆ1790, top-right fixed xโ‰ˆ1188 on a 1911px viewport.','summary'=>'These buttons are symbolic menu chrome. The left-side ordering follows chakra/yin-yang logic rather than source-flow ownership: base/head groups separated by yin/yang spacing.'], + ['id'=>'document-flow','icon'=>'โ†ง','title'=>'Document flow after the console','css'=>'#spireason-anchor: position:absolute; top:100%; padding-left/right:120px','computed'=>'Document begins at yโ‰ˆ988; main icon/navigation row appears before the deep blocks.','summary'=>'This is the normal reading stream. Main title anchors and icon IDs belong here; most later PDF and branch links are direct descendants of blockquotes, articles, sections, or prose in this flow.'], + ['id'=>'chapter-titles','icon'=>'โœฆ','title'=>'Two main chapter title gates','css'=>'static h2 titles in document flow followed by styled blockquote branch openers','computed'=>'Foundational title yโ‰ˆ31,230; Continuing Studies title yโ‰ˆ37,752.','summary'=>'When a main title mode is selected, links should be read as branch main links (PDFs) plus branch links under these two title gates.'], + ['id'=>'terminal-utility','icon'=>'โ˜•','title'=>'Coffee terminal and utility chrome','css'=>'Coffee is a static icon paragraph; after it fixed scroll/RSS and absolute lander buttons appear','computed'=>'Coffee yโ‰ˆ48,471. Lander buttons use top:calc(100vh + 20px), so their source position is late but visual position is near the initial panel.','summary'=>'Do not assign footer/download/RSS/lander controls to Coffee. Coffee is the last icon and closes the branch ownership model.'], +]; + +$sectionLayout = [ + 'shadow-books' => ['zone'=>'Shadow prelude', 'visual'=>'before first standard icon', 'computed'=>'pre-icon source region', 'parent'=>'rich prelude blocks', 'position'=>'relative sections/articles', 'note'=>'Promoted as a bonus owner because the shadow trilogy appears before the standard icon sequence.'], + 'growing-out-of-the-shadows' => ['zone'=>'Shadow document block', 'visual'=>'large rich section', 'computed'=>'yโ‰ˆ2,342; hโ‰ˆ1,652', 'parent'=>'section#growing-out-of-the-shadows', 'position'=>'relative', 'note'=>'This is a section block, not a simple icon paragraph; links sit inside hologram, illumination, article and grid substructures.'], + 'sheep' => ['zone'=>'Counter bridge', 'visual'=>'counter/manual/data columns before the first chapter title', 'computed'=>'yโ‰ˆ24,422', 'parent'=>'p#sheep then counter columns/blockquotes', 'position'=>'static in #spireason-anchor', 'note'=>'Counter links are direct flow/counter descendants: manuals, JSON/databases, scripts and calculators; no media/video ownership.'], + 'infinity' => ['zone'=>'Foundational chapter', 'visual'=>'left icon after ๐ŸŒŒ Grand Introduction', 'computed'=>'yโ‰ˆ31,731', 'parent'=>'i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Branch main links in this chapter are PDFs; secondary links are manuals, simulations and repositories.'], + 'natura' => ['zone'=>'Foundational chapter', 'visual'=>'compact two-PDF block', 'computed'=>'yโ‰ˆ32,981', 'parent'=>'i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Direct PDF block under the foundational title gate.'], + 'sunrise' => ['zone'=>'Foundational chapter', 'visual'=>'long PDF run with add-ons', 'computed'=>'yโ‰ˆ33,461', 'parent'=>'i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Material Magic branch; PDF main links plus inline app/manual add-ons in prose.'], + 'bigbang' => ['zone'=>'Continuing Studies chapter', 'visual'=>'opening icon after ๐Ÿ“š Overview of the Two Parts', 'computed'=>'yโ‰ˆ38,428', 'parent'=>'i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Karma/Evolution are the two branch-main PDFs for the second chapter.'], + 'yggdrasill' => ['zone'=>'Continuing Studies chapter', 'visual'=>'tree continuation', 'computed'=>'yโ‰ˆ38,838', 'parent'=>'i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Mostly PDF branch-main texts with a few supporting references.'], + 'spiritrise' => ['zone'=>'Continuing Studies chapter', 'visual'=>'blue diamond continuation', 'computed'=>'yโ‰ˆ39,694', 'parent'=>'i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'PDFs plus table/presentation links; the Force presentation is a later styled branch opener.'], + 'laelab' => ['zone'=>'Continuing Studies chapter', 'visual'=>'conceptual text gate', 'computed'=>'yโ‰ˆ40,478', 'parent'=>'i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Mostly text/concept block in source; curated external entries are intentionally sparse.'], + 'geneticar' => ['zone'=>'Continuing Studies chapter', 'visual'=>'inside blockquote cluster', 'computed'=>'yโ‰ˆ40,881', 'parent'=>'blockquote > i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'AI visualization applets are branch links under the ongoing chapter.'], + 'handheldcal' => ['zone'=>'Tools inside continuing flow', 'visual'=>'calculator branch', 'computed'=>'yโ‰ˆ41,562', 'parent'=>'blockquote > i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Calculator and resonant calculus links are tool branches, not PDF chapter-openers.'], + 'puzzled' => ['zone'=>'Source texts inside continuing flow', 'visual'=>'repository branch', 'computed'=>'yโ‰ˆ42,509', 'parent'=>'blockquote > i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Repository/source links sit under a nested blockquote region.'], + 'chakra' => ['zone'=>'Foundational cross-reference inside continuing flow', 'visual'=>'chakra/element branch', 'computed'=>'yโ‰ˆ43,089', 'parent'=>'blockquote > i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Relates to elementchakra logic and the fixed chakra menu; links are branch references rather than fixed menu buttons.'], + 'wheelsgoround' => ['zone'=>'Continuing tool/source flow', 'visual'=>'gear branch', 'computed'=>'yโ‰ˆ44,320', 'parent'=>'blockquote > i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Open-source calculator backbone.'], + 'laemedics' => ['zone'=>'Body/health study flow', 'visual'=>'last substantive branch before Coffee', 'computed'=>'yโ‰ˆ45,032', 'parent'=>'i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'SpiBody/SpiZenTao branch plus Kybalion reference before the terminal Coffee notes.'], + 'coffeeandcigarettes' => ['zone'=>'Terminal prose', 'visual'=>'last icon, no branch links', 'computed'=>'yโ‰ˆ48,471', 'parent'=>'i > #spireason-anchor', 'position'=>'static icon paragraph', 'note'=>'Closes branch ownership. Footer, archive, RSS, scroll and lander controls are utility chrome and are listed separately.'], +]; + +$chapterGroups = [ + [ + 'id' => 'chapter-foundational', + 'icon' => 'โœฆ', + 'title' => 'Foundational Texts', + 'trigger' => ['icon'=>'๐ŸŒŒ', 'name'=>'Grand Introduction', 'href'=>'https://materialmagic.floot.app/', 'summary'=>'Styled blockquote opener with data-title="Introduction to first chapter of PDF documents".'], + 'sections' => ['infinity', 'natura', 'sunrise'], + 'computed' => 'h2 yโ‰ˆ31,230; trigger yโ‰ˆ31,569', + 'summary' => 'The first main title gate. PDFs are the branch-main links; manuals, repositories, simulations and applets are branch links under those owners.', + ], + [ + 'id' => 'chapter-continuing', + 'icon' => 'โŸฒ', + 'title' => 'Continuing Studies', + 'trigger' => ['icon'=>'๐Ÿ“š', 'name'=>'Overview of the Two Parts', 'href'=>'https://www.popai.pro/ppt-share?shareKey=87543f5adbb61069fd42a0fc439738d802d1aaf72585bc0e0665d9d40fec1375', 'summary'=>'Styled blockquote opener with data-title="Introduction to both first and second part".'], + 'sections' => ['bigbang', 'yggdrasill', 'spiritrise', 'laelab', 'geneticar', 'handheldcal', 'puzzled', 'chakra', 'wheelsgoround', 'laemedics'], + 'computed' => 'h2 yโ‰ˆ37,752; trigger yโ‰ˆ38,267', + 'summary' => 'The second main title gate. Karma/Evolution start the run, then tree, spirit, lab, source, chakra and body branches continue in the same flow.', + ], +]; + diff --git a/index.php b/index.php index 7205f3d..9c26c69 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,289 @@ 'PDF text', + 'applet' => 'Applet', + 'bot' => 'External bot/system', + 'tool' => 'Tool', + 'github' => 'Repository', + 'archive' => 'Archive', + 'presentation' => 'Presentation', + 'media' => 'Media', + 'dataset' => 'Dataset', + 'source' => 'Source file', + 'external' => 'External system', + 'onsite' => 'On-site branch', + 'branch' => 'Branch', + 'research' => 'Research system', + 'manual' => 'Manual', + 'table' => 'Table', + ][$category] ?? ucfirst(str_replace('-', ' ', $category)); +} + +$pdfLinks = array_values(array_filter($links, fn($link) => ($link['kind'] ?? '') === 'pdf')); + ?> - - - New Style - - - - - - - - - - - - - - - - - - - + + + <?= htmlspecialchars($projectName) ?> + + + + + + + + + + + + -
-
-

Analyzing your requirements and generating your websiteโ€ฆ

-
- Loadingโ€ฆ + +
+
+ + + + +
+
+
+ Study + Repos + PDFs.zip +
+
+ Chat + Find + Apps +
+
+

Structural clone ยท main webpage only

+

Laegna & Spireason Trivia: LandScaper.

+

A restrained console layer folds into a document map. Each icon is treated as an owner: its source anchor owns the visible links until the next large icon, with a bonus shadow-books icon for the prelude.

+
+ + + +
+
+ Enter Document + Curated links page + +
+
+ โ†“ +
+ + + +
+
+
+

Document layer

+

Console-to-document structural index

+

This slice now follows the live ownership rule: It exposes verified root PDFs, curated links, and a filtered visible-link scanner for the current reference page.

+
+ +
+ +
Filter keeps card heights stable; non-matches dim instead of disappearing.
+
+ + + +
+
+ +
+
+
โœฆ Foundational Texts
+

Start: infinity, material magic, karma, chakra, meditation.

+

PDF documents are treated as central files: they keep their exact names, direct links, and short summaries.

+
+
+
โŸฒ Continuing Studies
+

Continuation: apps, repositories, datasets, generated studies.

+

Main branches remain first-class paths; child links are represented as branch/file entities rather than hidden prose.

+
+
+ + +
+
+
+

Verified PDF library

+

25 root-folder PDFs, exact filenames preserved

+

These are direct spireason.neocities.org/<filename>.pdf URLs. Mojibake dash text is normalized to the real en dash (โ€“), while filenames stay visible in a quieter line.

+
+
+ + + + +
+
+ +
+ +
+ + $link['section'] === $section['id'])); ?> + + + +
+ +
+
+

Automated scanner

+

New Links scanner

+

Checks the live reference page, lists visible, human-facing anchors only, suppresses asset/script/noise and deliberately removed URLs, then flags links not represented in this curated structure.

+
+ +
Idle. Click scan to compare with the live page.
+
Policy: visible anchors only ยท no JavaScript/mail/asset links ยท known removals suppressed ยท unknown external hosts marked for review.
+
'>
+
+
+
-