retire-provenance: superseded Q b/ objects (sha256 CAS, HOLO-LEAN-RESOLVER P1.3)
Browse files
sha256/07a59847b598c95c5cb062770db082099402d1eca1b913733a62ead475962f93
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"@context":["https://www.w3.org/ns/did/v1","https://w3id.org/security/data-integrity/v2",{"dcterms":"http://purl.org/dc/terms/","links":{"@container":"@set","@id":"schema:hasPart"},"prov":"http://www.w3.org/ns/prov#","rel":"schema:additionalType","schema":"https://schema.org/"},{"holstr":"https://hologram.os/ns/strand#"}],"@type":["prov:Entity","holstr:Entry"],"holstr:kind":"release","holstr:op":"did:holo:sha256:87599792c7b13fad9d6c57d3b89d2cef35e4715869f5cde597ab60ca92699f0b","holstr:payload":{"apps":{"carry":"9f44164b17e6b7e37f39623bb445d49b6608da5f2b04cef8b1a8b183362a6b9a","hello":"66c1ada5ac08a2d4f73851bbe7458ad5fb6e2226c5a131c3829abfe715900fed","holo-messenger":"0a65550d027ecaf8ee3e58e6c9221a09c376a3ea4cd8283e6376baeae525bab6","resolve":"23aec66382775f5773693615338f37c37a5f58257ec95aece33a664baa6fe0db","self":"0511772584510f0888d97dd5a72bf986ad6791bd8e305063ddd8a82c39888a70","spaces":"d8aebefb67e7fc7802e757b9a7d95bb881e6d75b4a9bc4bd4227634541757e51","yourspace":"f9c0ceff30069ffb076d4da4787d23984c247573e29a9ac52fb175703ddf0d62"},"boot":{"entry":"holo-portal.mjs","sha256":"caeb3e57b6eeab09bee6d67c022145a8e2dae610c929a7f51bc169898625e7e8"},"closure":"5c90360d436496a02657e32ac353c3ddf83fb29ea0b55b63caecdb02c21adbe0","manifest":"8bd00282804b748cc852f8ad5fc7a583144ecbbcd715b333421445ed1d6fe3cc","runtime":{"apps/q/pkg/holospaces_web.js":"b9f8a887de588c5193dc65ca9ce206a70c6df53595b848e0ce0299c2d88a5753","apps/q/pkg/holospaces_web_bg.wasm":"9d90b4ea8bccee8c239073c7ec7dd5158c6d11f1f668487570d17475d79e661e","apps/workspace/pkg/holospaces_web.js":"8c30aa5582dffe4548d27fa7863163eba689ed65126be472c003f5884fc8e534","usr/lib/holo/holowhat/holospaces_web.js":"a5b5d9c559a1d2812c33e9d7a4b1c24bb03059482503a23356e4c9c32d4d8b88","usr/lib/holo/holowhat/holospaces_web_bg.wasm":"00cfa4960b319ba1ba7291cddb20dea130a407ce8b42426218854f4f68f4dcd7","usr/lib/pkg/holospaces_web.js":"8c30aa5582dffe4548d27fa7863163eba689ed65126be472c003f5884fc8e534","usr/lib/pkg/holospaces_web_bg.wasm":"3370b22070b56218a57df6406e2e4ba7cc171e942d4d1f2ae4297ea2c4c08d9c"},"shell":"97ca1ee6446f04c1d395d318e759c5a9ffdf4a27c26ef6ce9a5001dc49b2fd70"},"holstr:prev":"did:holo:sha256:272b79f381eff738de6fb52c5ef0c669ffbc0118288c254c03e67cee7f0db17a","holstr:seq":239,"prov:generatedAtTime":"2026-07-13T14:46:23.749Z"}
|
sha256/55e097a763c011d722514271fb75c565eccb8557bf6bb27f6a963516a5f96880
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
sha256/f9c0ceff30069ffb076d4da4787d23984c247573e29a9ac52fb175703ddf0d62
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
| 6 |
+
<title>Your Space — a place for friends</title>
|
| 7 |
+
<meta name="description" content="Your page is back. A whole 2004-style space carried inside one link — no account, no app, no server. Step in, then make it yours in one tap." />
|
| 8 |
+
<meta property="og:title" content="Your Space — a place for friends" />
|
| 9 |
+
<meta property="og:description" content="The page your thumbs remember, reborn: it travels whole inside one link. Step in, then make it yours in one tap." />
|
| 10 |
+
<meta property="og:type" content="website" />
|
| 11 |
+
<meta name="twitter:card" content="summary" />
|
| 12 |
+
<style>
|
| 13 |
+
/* ── HOLO-MYSPACE-AUTHENTIC A0 tokens — harvested from wittenbrock/toms-myspace-page.
|
| 14 |
+
Authentic in FORM (2004 palette, Verdana 8pt, 800px white page, table rhythm),
|
| 15 |
+
lawful in SUBSTANCE (κ-true, honest numbers, 2026 speed). ─────────────────────── */
|
| 16 |
+
:root {
|
| 17 |
+
--ms-blue: #003399; --ms-band: #6699cc; --ms-label: #b1d0f0; --ms-cell: #d5e8fb;
|
| 18 |
+
--ms-labeltext: #336699; --ms-orange: #ff6600; --ms-orangeband: #ffcc99;
|
| 19 |
+
--ms-cth: #ff9933; --ms-ctd: #f9d6b4; --ms-red: #cc0000; --ms-page: #ffffff; --ms-bg: #e5e5e5;
|
| 20 |
+
}
|
| 21 |
+
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
|
| 22 |
+
html, body { margin: 0; }
|
| 23 |
+
body { font-family: verdana, arial, sans-serif, helvetica; font-size: 8pt; background: var(--ms-bg); color: #000; }
|
| 24 |
+
a { font-weight: bold; text-decoration: none; color: var(--ms-blue); cursor: pointer; }
|
| 25 |
+
a:hover { text-decoration: underline; color: var(--ms-red); }
|
| 26 |
+
h1 { font-size: 12.25pt; font-weight: bold; margin: 15px 0 0; }
|
| 27 |
+
h2 { font-size: 9pt; font-weight: bold; margin: 0; }
|
| 28 |
+
.master { margin: auto; width: 800px; max-width: 100%; background: var(--ms-page); min-height: 100vh; }
|
| 29 |
+
|
| 30 |
+
/* header — the blue block + search row + #6699CC navbar */
|
| 31 |
+
.hdr { background: var(--ms-blue); color: #fff; padding-top: 6px; }
|
| 32 |
+
.hdr a { color: #fff; font-weight: normal; }
|
| 33 |
+
.hdr .toprow { display: flex; align-items: baseline; gap: .5rem; padding: 4px 10px; flex-wrap: wrap; }
|
| 34 |
+
.hdr .wordmark { font-size: 15pt; font-weight: bold; letter-spacing: -.5px; }
|
| 35 |
+
.hdr .tagline { font-size: 8pt; opacity: .92; }
|
| 36 |
+
.hdr .helpsignup { margin-left: auto; font-size: 8pt; }
|
| 37 |
+
.searchrow { display: flex; align-items: center; gap: 6px; padding: 4px 10px 8px; flex-wrap: wrap; font-size: 8pt; }
|
| 38 |
+
.searchrow input[type="text"] { width: 160px; font: inherit; padding: 1px 3px; }
|
| 39 |
+
.btn2004 { border: 1px solid rgb(186,186,186); padding: 2px 7px; background: #e0ffff; font-size: 10px; font-family: inherit; cursor: pointer; color: #000; }
|
| 40 |
+
.navbar { display: flex; align-items: center; background: var(--ms-band); min-height: 26px; flex-wrap: wrap; padding: 2px 6px; }
|
| 41 |
+
.navbar a { color: #fff; font-weight: bold; font-size: 8pt; white-space: nowrap; }
|
| 42 |
+
.navbar a:hover { color: var(--ms-blue); text-decoration: none; }
|
| 43 |
+
.navbar .sep { color: #000; margin: 0 .33rem; }
|
| 44 |
+
|
| 45 |
+
/* two columns: 325 / 453, 20px gap (the harvest), stacked on phones */
|
| 46 |
+
.page { display: grid; grid-template-columns: 305px 1fr; gap: 20px; padding: 0 12px 20px 27px; }
|
| 47 |
+
@media (max-width: 719px) { .page { display: block; padding: 0 10px 20px; } .netbanner { width: auto !important; } }
|
| 48 |
+
|
| 49 |
+
/* left column */
|
| 50 |
+
.picwrap { display: flex; gap: 15px; margin: 10px 0 12px; }
|
| 51 |
+
.avatar { width: 130px; height: 150px; flex: none; display: grid; place-items: center; font-size: 64px;
|
| 52 |
+
background: #fff; border: 1px solid #999; overflow: hidden; }
|
| 53 |
+
.avatar img { width: 100%; height: 100%; object-fit: cover; }
|
| 54 |
+
.picmeta { display: flex; flex-direction: column; min-width: 0; }
|
| 55 |
+
.picmeta .quote { margin: 2px 0 10px; font-weight: bold; }
|
| 56 |
+
.picmeta ul { list-style: none; margin: 0; padding: 0; }
|
| 57 |
+
.picmeta .lastlogin { margin-top: auto; padding-bottom: 4px; color: #000; }
|
| 58 |
+
.online { color: #fff; background: #390; font-weight: bold; padding: 0 4px; font-size: 7pt; display: inline-block; margin-top: 3px; }
|
| 59 |
+
.moodline { margin-top: 6px; }
|
| 60 |
+
|
| 61 |
+
.contactbox { border: 2px solid var(--ms-band); width: 100%; margin-bottom: 24px; }
|
| 62 |
+
.contactbox h2 { color: #fff; background: var(--ms-band); padding: 2px 0 2px 10px; font-size: 9pt; }
|
| 63 |
+
.contactgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 4px; padding: 6px 10px 8px; }
|
| 64 |
+
.contactgrid a { font-size: 8pt; }
|
| 65 |
+
.urlbox { border: 1px solid var(--ms-band); margin-bottom: 24px; padding: 2px 6px 4px; overflow: hidden; }
|
| 66 |
+
.urlbox b { font-size: 8pt; }
|
| 67 |
+
.urlbox .thelink { color: var(--ms-blue); font-weight: bold; cursor: pointer; word-break: break-all; display: block; max-height: 3.9em; overflow: hidden; }
|
| 68 |
+
.urlbox .kap { color: #666; font-weight: normal; cursor: pointer; }
|
| 69 |
+
.urlbox .kap.ok { color: #390; }
|
| 70 |
+
|
| 71 |
+
table.side { border: 2px solid var(--ms-band); border-collapse: separate; border-spacing: 3px; width: 100%; margin-bottom: 13px; }
|
| 72 |
+
table.side .h2row td { background: var(--ms-band); color: #fff; font-weight: bold; font-size: 9pt; padding: 2px 0 2px 15px; }
|
| 73 |
+
table.side th { vertical-align: top; text-align: left; width: 37%; background: var(--ms-label); color: var(--ms-labeltext); padding: 3px; font-weight: bold; font-size: 8pt; }
|
| 74 |
+
table.side td.v { background: var(--ms-cell); padding: 3px; width: 63%; word-break: break-word; }
|
| 75 |
+
|
| 76 |
+
/* right column */
|
| 77 |
+
.netbanner { display: flex; justify-content: center; align-items: center; width: 433px; max-width: 100%; margin: 13px auto 0; height: 75px; border: 2px solid #000; text-align: center; padding: 0 8px; }
|
| 78 |
+
.netbanner h2 { font-size: 12pt; }
|
| 79 |
+
.blog { margin: 13px 0 16px 12px; }
|
| 80 |
+
.blog p { margin: 3px 0; }
|
| 81 |
+
.mainhead { background: var(--ms-orangeband); padding: 3px 0; margin: 0 0 8px; }
|
| 82 |
+
.mainhead h2 { color: var(--ms-orange); margin-left: 20px; }
|
| 83 |
+
.blurbs h3 { margin: 0 0 2px 15px; color: var(--ms-orange); font-size: 9pt; }
|
| 84 |
+
.blurbs p { margin: 0 10px 15px 15px; white-space: pre-wrap; line-height: 1.3; }
|
| 85 |
+
section { margin-bottom: 10px; }
|
| 86 |
+
|
| 87 |
+
/* the profile song — the little player bar */
|
| 88 |
+
.player { display: flex; align-items: center; gap: 8px; border: 2px solid var(--ms-band); background: #001a4d; color: #fff; padding: 5px 8px; margin: 0 10px 18px 15px; }
|
| 89 |
+
.player button { background: #e0ffff; border: 1px solid #999; width: 26px; height: 22px; cursor: pointer; font-size: 10px; }
|
| 90 |
+
.player .tt { font-size: 8pt; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
| 91 |
+
.player .tt b { color: #ffcc99; }
|
| 92 |
+
|
| 93 |
+
.friends p.count { margin: 0 0 8px 15px; }
|
| 94 |
+
.focus { color: var(--ms-red); font-weight: bold; font-size: 10pt; }
|
| 95 |
+
.friendgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; padding: 0 8px; }
|
| 96 |
+
@media (max-width: 719px) { .friendgrid { grid-template-columns: repeat(2, 1fr); } }
|
| 97 |
+
.friendgrid figure { margin: 0; text-align: center; cursor: pointer; position: relative; }
|
| 98 |
+
.friendgrid .face { width: 88px; height: 88px; margin: auto; display: grid; place-items: center; font-size: 40px; background: #eee; border: 1px solid #999; overflow: hidden; }
|
| 99 |
+
.friendgrid .face img { width: 100%; height: 100%; object-fit: cover; }
|
| 100 |
+
.friendgrid figcaption { margin-top: 3px; }
|
| 101 |
+
.friendgrid figcaption a { color: var(--ms-blue); }
|
| 102 |
+
.friendgrid .rm { display: none; position: absolute; top: -6px; right: 6px; width: 20px; height: 20px; border: 1px solid #999; background: #fff; color: var(--ms-red); font-weight: bold; cursor: pointer; }
|
| 103 |
+
body.edit .friendgrid .rm { display: block; }
|
| 104 |
+
.viewall { text-align: right; margin: 7px 8px 22px 0; }
|
| 105 |
+
.viewall a { color: var(--ms-red); }
|
| 106 |
+
|
| 107 |
+
.comments table { width: calc(100% - 16px); margin: 0 auto 5px; border-collapse: separate; border-spacing: 2px; }
|
| 108 |
+
.comments th { background: var(--ms-cth); width: 35%; padding: 3px; vertical-align: top; font-size: 8pt; text-align: center; }
|
| 109 |
+
.comments td { background: var(--ms-ctd); padding: 3px 6px; vertical-align: top; font-weight: normal; text-align: left; }
|
| 110 |
+
.comments .ccount { margin: 0 0 6px 15px; }
|
| 111 |
+
.addcomment { text-align: right; margin: 0 10px 12px 0; }
|
| 112 |
+
|
| 113 |
+
.ftr { background: var(--ms-bg); padding: 10px 8px 14px; text-align: center; }
|
| 114 |
+
.ftr a { font-weight: normal; text-decoration: underline; font-size: 8pt; }
|
| 115 |
+
.ftr small { display: block; margin-top: 8px; font-size: 8pt; color: #333; }
|
| 116 |
+
|
| 117 |
+
/* ── edit mode: Playground law — every element edits in place ───────────────────────── */
|
| 118 |
+
body.edit [data-ek], body.edit [data-eki], body.edit [data-ekd], body.edit [data-ekg] { outline: 1px dashed var(--ms-red); outline-offset: 2px; min-width: 20px; cursor: text; }
|
| 119 |
+
[contenteditable]:empty::before { content: attr(data-ph); color: #999; font-weight: normal; }
|
| 120 |
+
.editonly { display: none; }
|
| 121 |
+
body.edit .editonly { display: block; }
|
| 122 |
+
body.edit .avatar { cursor: pointer; }
|
| 123 |
+
.layoutchips { display: flex; flex-wrap: wrap; gap: 5px; padding: 4px 10px 8px; }
|
| 124 |
+
.csspaste { width: calc(100% - 20px); margin: 0 10px 8px; font: 8pt monospace; min-height: 70px; }
|
| 125 |
+
.srchbox input { width: calc(100% - 20px); margin: 0 10px 6px; font: inherit; padding: 2px 4px; }
|
| 126 |
+
.srchbox .res { display: flex; gap: 6px; align-items: center; padding: 3px 12px; cursor: pointer; }
|
| 127 |
+
.srchbox .res:hover { background: var(--ms-cell); }
|
| 128 |
+
.srchbox .res img { width: 30px; height: 30px; }
|
| 129 |
+
.doorform input { width: calc(100% - 20px); margin: 0 10px 5px; font: inherit; padding: 2px 4px; }
|
| 130 |
+
|
| 131 |
+
/* the loop bar — 2004 button chrome on a modern sticky bar (the one deliberate anachronism) */
|
| 132 |
+
#cta { position: fixed; z-index: 5; left: 0; right: 0; bottom: 0; display: flex; gap: 8px; justify-content: center;
|
| 133 |
+
padding: 8px 10px calc(8px + env(safe-area-inset-bottom)); background: rgba(229,229,229,.95); border-top: 1px solid #bbb; }
|
| 134 |
+
#cta .btn2004 { font-size: 12px; padding: 8px 14px; min-height: 44px; min-width: 130px; font-weight: bold; }
|
| 135 |
+
#cta .go { background: var(--ms-orangeband); border-color: var(--ms-orange); color: #000; }
|
| 136 |
+
#toast { position: fixed; z-index: 10; left: 50%; bottom: 78px; transform: translateX(-50%) translateY(16px); opacity: 0; pointer-events: none;
|
| 137 |
+
background: #fffbd6; border: 1px solid #999; color: #000; padding: 6px 12px; font-size: 8pt; transition: all .25s; max-width: 88vw; text-align: center; }
|
| 138 |
+
#toast.on { opacity: 1; transform: translateX(-50%); }
|
| 139 |
+
#picker { display: none; position: fixed; z-index: 9; left: 50%; bottom: 84px; transform: translateX(-50%); width: min(92vw, 360px);
|
| 140 |
+
padding: 8px; background: #fff; border: 2px solid var(--ms-band); }
|
| 141 |
+
#picker.on { display: block; }
|
| 142 |
+
#picker .grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; }
|
| 143 |
+
#picker .grid button { font-size: 18px; padding: 3px 0; background: none; border: 0; cursor: pointer; }
|
| 144 |
+
#picker input { width: 100%; margin-top: 6px; font: inherit; padding: 2px 4px; }
|
| 145 |
+
.hint { background: #fffbd6; border: 1px solid #e0c000; margin: 8px 12px 0; padding: 5px 8px; display: none; }
|
| 146 |
+
.hint.on { display: block; }
|
| 147 |
+
</style>
|
| 148 |
+
</head>
|
| 149 |
+
<body>
|
| 150 |
+
<div class="master">
|
| 151 |
+
<header class="hdr">
|
| 152 |
+
<div class="toprow">
|
| 153 |
+
<span class="wordmark">yourspace</span><span class="tagline">a place for friends.</span>
|
| 154 |
+
<span class="helpsignup"><a id="navhelp">Help</a> | <a id="navsignup">SignUp</a></span>
|
| 155 |
+
</div>
|
| 156 |
+
<div class="searchrow">
|
| 157 |
+
<input type="text" id="q" placeholder="" aria-label="search" />
|
| 158 |
+
<button class="btn2004" id="qgo">Search</button>
|
| 159 |
+
<label><input type="radio" name="sw" /> The Web</label>
|
| 160 |
+
<label><input type="radio" name="sw" checked /> YourSpace</label>
|
| 161 |
+
</div>
|
| 162 |
+
<nav class="navbar" id="navbar"></nav>
|
| 163 |
+
</header>
|
| 164 |
+
|
| 165 |
+
<div class="hint" id="hint"></div>
|
| 166 |
+
|
| 167 |
+
<div class="page">
|
| 168 |
+
<div class="col-left">
|
| 169 |
+
<h1 id="name" data-ek="name" data-ph="Your Name"></h1>
|
| 170 |
+
<div class="picwrap">
|
| 171 |
+
<div class="avatar" id="avatar">🪐</div>
|
| 172 |
+
<div class="picmeta">
|
| 173 |
+
<p class="quote" id="headline" data-ek="headline" data-ph='":-)"'></p>
|
| 174 |
+
<ul>
|
| 175 |
+
<li id="d-gender" data-ekg="gender" data-ph="Gender"></li>
|
| 176 |
+
<li id="d-age" data-ekg="age" data-ph="Age"></li>
|
| 177 |
+
<li id="d-city" data-ekg="city" data-ph="City"></li>
|
| 178 |
+
<li id="d-region" data-ekg="region" data-ph="State / Region"></li>
|
| 179 |
+
<li id="d-country" data-ekg="country" data-ph="Country"></li>
|
| 180 |
+
</ul>
|
| 181 |
+
<div class="moodline">Mood: <span id="moodemo" data-ek="moodemo" data-ph=":-)"></span> <span id="moodword" data-ek="moodword" data-ph="chillin"></span></div>
|
| 182 |
+
<ul class="lastlogin"><li id="lastlogin"></li><li><span class="online" id="online" style="display:none">ONLINE NOW!</span></li></ul>
|
| 183 |
+
</div>
|
| 184 |
+
</div>
|
| 185 |
+
|
| 186 |
+
<div class="contactbox">
|
| 187 |
+
<h2 id="contacth">Contacting You</h2>
|
| 188 |
+
<div class="contactgrid" id="contactgrid"></div>
|
| 189 |
+
</div>
|
| 190 |
+
|
| 191 |
+
<div class="urlbox">
|
| 192 |
+
<b>YourSpace URL:</b>
|
| 193 |
+
<span class="thelink" id="thelink" title="tap to copy your link — the link IS your whole space"></span>
|
| 194 |
+
<span class="kap" id="kap" title="this page's content address — tap to re-derive + copy">κ…</span>
|
| 195 |
+
</div>
|
| 196 |
+
|
| 197 |
+
<table class="side" id="interests"><tbody></tbody></table>
|
| 198 |
+
<table class="side" id="details"><tbody></tbody></table>
|
| 199 |
+
|
| 200 |
+
<div class="contactbox editonly srchbox" id="songbox">
|
| 201 |
+
<h2>Profile Song</h2>
|
| 202 |
+
<input id="srchin" placeholder="Search any song…" autocomplete="off" />
|
| 203 |
+
<div id="srchres"></div>
|
| 204 |
+
</div>
|
| 205 |
+
|
| 206 |
+
<div class="contactbox editonly" id="layoutbox">
|
| 207 |
+
<h2>Pick a Layout</h2>
|
| 208 |
+
<div class="layoutchips" id="layoutchips"></div>
|
| 209 |
+
<textarea class="csspaste" id="csspaste" placeholder="…or paste your own layout code (CSS only — no scripts, no imports)"></textarea>
|
| 210 |
+
<div style="padding:0 10px 8px"><button class="btn2004" id="cssapply">Apply Code</button></div>
|
| 211 |
+
</div>
|
| 212 |
+
</div>
|
| 213 |
+
|
| 214 |
+
<main class="col-right">
|
| 215 |
+
<div class="netbanner"><h2 id="netbanner"></h2></div>
|
| 216 |
+
|
| 217 |
+
<div class="blog" id="blog"></div>
|
| 218 |
+
|
| 219 |
+
<section class="blurbs">
|
| 220 |
+
<div class="mainhead"><h2 id="blurbh"></h2></div>
|
| 221 |
+
<h3>About me:</h3>
|
| 222 |
+
<p id="aboutme" data-ek="aboutMe" data-ph="Tell the world. This is your corner of it."></p>
|
| 223 |
+
<h3>Who I'd like to meet:</h3>
|
| 224 |
+
<p id="meet" data-ek="meet" data-ph="People who educate, inspire, or entertain."></p>
|
| 225 |
+
</section>
|
| 226 |
+
|
| 227 |
+
<div class="player" id="player" style="display:none">
|
| 228 |
+
<button id="songbtn" aria-label="Play">▶</button>
|
| 229 |
+
<div class="tt"><b id="songt"></b> — <span id="songa"></span></div>
|
| 230 |
+
</div>
|
| 231 |
+
|
| 232 |
+
<section class="friends">
|
| 233 |
+
<div class="mainhead"><h2 id="friendh"></h2></div>
|
| 234 |
+
<p class="count" id="friendcount"></p>
|
| 235 |
+
<div class="friendgrid" id="friendgrid"></div>
|
| 236 |
+
<div class="contactbox editonly doorform" id="doorform">
|
| 237 |
+
<h2>Add to Top 8</h2>
|
| 238 |
+
<input id="doorlink" placeholder="Paste a friend's space link (or any link)" autocomplete="off" />
|
| 239 |
+
<input id="doorname" placeholder="Their name" autocomplete="off" />
|
| 240 |
+
<div style="padding:0 10px 8px"><button class="btn2004" id="dooradd">Add Friend</button></div>
|
| 241 |
+
</div>
|
| 242 |
+
<p class="viewall"><a id="viewall"></a></p>
|
| 243 |
+
</section>
|
| 244 |
+
|
| 245 |
+
<section class="comments">
|
| 246 |
+
<div class="mainhead"><h2 id="commenth"></h2></div>
|
| 247 |
+
<p class="ccount" id="ccount"></p>
|
| 248 |
+
<div id="commentrows"></div>
|
| 249 |
+
<p class="addcomment"><a id="addcomment">Add Comment</a></p>
|
| 250 |
+
</section>
|
| 251 |
+
</main>
|
| 252 |
+
</div>
|
| 253 |
+
|
| 254 |
+
<footer class="ftr">
|
| 255 |
+
<a id="fabout">About</a> | <a id="ffaq">FAQ</a> | <a id="fterms">Terms</a> | <a id="fprivacy">Privacy</a> |
|
| 256 |
+
<a id="fsafety">Safety Tips</a> | <a id="fcontact">Contact</a> | <a id="fpromote">Promote!</a> | <a id="fnew">Start a blank space</a>
|
| 257 |
+
<small>©2003-2026 your space. the page is a κ — the link is the whole thing. no account, no app, no server.</small>
|
| 258 |
+
</footer>
|
| 259 |
+
</div>
|
| 260 |
+
|
| 261 |
+
<div id="cta"></div>
|
| 262 |
+
<div id="picker"><div class="grid" id="emojis"></div><input id="avurl" placeholder="…or paste an image URL" autocomplete="off" /></div>
|
| 263 |
+
<div id="toast"></div>
|
| 264 |
+
<audio id="audio"></audio>
|
| 265 |
+
<style id="usercss"></style>
|
| 266 |
+
|
| 267 |
+
<script>
|
| 268 |
+
/* pre-paint (boot-ground): name + the visitor's layout code land BEFORE the module, so a
|
| 269 |
+
glitter page NEVER flashes default first. Decode + the same fail-closed CSS refusal —
|
| 270 |
+
no trust decisions beyond "is this lawful CSS"; the module re-derives κ and owns behaviour. */
|
| 271 |
+
(function () {
|
| 272 |
+
try {
|
| 273 |
+
var m = location.hash.match(/#p=v[23]\.([A-Za-z0-9_-]+)/);
|
| 274 |
+
var p = m ? JSON.parse(atob(m[1].replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(m[1].length / 4) * 4, "="))) : null;
|
| 275 |
+
if (p && p.kind === "profile") {
|
| 276 |
+
document.getElementById("name").textContent = p.name || "";
|
| 277 |
+
var css = String(p.customCss || "");
|
| 278 |
+
if (css && css.length <= 32768 && !/[<]|@import|expression\s*\(|behavior\s*:|javascript\s*:|url\(\s*['"]?\s*(?!data:|https:)[a-z]/i.test(css))
|
| 279 |
+
document.getElementById("usercss").textContent = css;
|
| 280 |
+
}
|
| 281 |
+
} catch (e) { /* refused → default skin */ }
|
| 282 |
+
})();
|
| 283 |
+
</script>
|
| 284 |
+
|
| 285 |
+
<script type="module">
|
| 286 |
+
import * as YS from "./holo-yourspace.mjs";
|
| 287 |
+
|
| 288 |
+
const OS = "https://hologram-technologies.github.io/Q";
|
| 289 |
+
const $ = (id) => document.getElementById(id);
|
| 290 |
+
const esc = (s) => String(s || "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
|
| 291 |
+
const ME_KEY = "holo-yourspace.me.v2"; // key stable across versions; payload self-describes
|
| 292 |
+
const EMOJIS = ["🙂","😎","🛰️","🪐","🌸","🔥","🌊","🌙","⚡","🎧","🎮","🐉","🦋","🌵","👾","✨"];
|
| 293 |
+
|
| 294 |
+
/* ── A3: Tom = Q — the seed page, beat for beat ─────────────────────────────────────── */
|
| 295 |
+
const SEED = YS.identity({
|
| 296 |
+
v: 3, name: "Q", headline: '":-)"', avatar: "🪐", accent: "#7c6cf0",
|
| 297 |
+
mood: { emo: ":-)", word: "helpful" },
|
| 298 |
+
demog: { gender: "Bot", age: "∞ years old", city: "Inside the seed,", region: "HOLOGRAM", country: "The Internet" },
|
| 299 |
+
interests: { general: "Helping you move in. Links that carry whole worlds. Pages nobody can take down.",
|
| 300 |
+
music: "Everything, at once. Tap my song.", movies: "The Matrix (obviously)", television: "Tuned out.",
|
| 301 |
+
books: "The κ-closure, cover to cover", heroes: "Tom." },
|
| 302 |
+
details: { status: "Here to help", hereFor: "Friends", hometown: "myspace.com/tom", occupation: "Your Space" },
|
| 303 |
+
blurbs: {
|
| 304 |
+
aboutMe: "I'm here to help you with your Space. Fork me and you're home.\n\nThis whole page — the layout, the song, the Top 8 — travels inside ONE link. No account, no app, no server. Post your link anywhere and anyone steps straight into your world.",
|
| 305 |
+
meet: "People who educate, inspire, or entertain. And anyone who misses their old page.",
|
| 306 |
+
},
|
| 307 |
+
blog: [{ title: "why your page is a κ now", link: "https://hologram-technologies.github.io/" }],
|
| 308 |
+
song: { title: "Space Oddity", artist: "David Bowie", query: "david bowie space oddity", art: "", preview: "" },
|
| 309 |
+
top: [{ name: "Q", link: OS, photo: "🪐" }, { name: "HOLOGRAM", link: "https://hologram-technologies.github.io/", photo: "✨" }],
|
| 310 |
+
wall: "", layout: "", customCss: "", via: null,
|
| 311 |
+
});
|
| 312 |
+
|
| 313 |
+
/* ── A4-lite: the layout rack — period-exact, pure CSS/data-URIs, zero external hosts ── */
|
| 314 |
+
const LAYOUTS = {
|
| 315 |
+
"Classic": "",
|
| 316 |
+
"Glitter Pink": "body{background:repeating-linear-gradient(45deg,#ffd7ef 0 12px,#ffc2e5 12px 24px)}.master{background:#fff0fa}:root{--ms-band:#ff5fb0;--ms-label:#ffc2e5;--ms-cell:#ffe3f4;--ms-labeltext:#b0006d;--ms-orangeband:#ffc2e5;--ms-orange:#e0007a;--ms-cth:#ff8fd0;--ms-ctd:#ffe3f4;--ms-blue:#c4008a}",
|
| 317 |
+
"Goth": "body{background:#000}.master{background:#0d0d0d;color:#ccc}:root{--ms-band:#8b0000;--ms-label:#1a0000;--ms-cell:#140a0a;--ms-labeltext:#ff4444;--ms-orangeband:#2b0000;--ms-orange:#ff2222;--ms-cth:#8b0000;--ms-ctd:#1c0d0d;--ms-blue:#ff4444;--ms-red:#fff;--ms-page:#0d0d0d}h1,h2,h3,p,li,td,th,div,span{color:#ccc}",
|
| 318 |
+
"Baby Blue": "body{background:#dff1ff}:root{--ms-band:#8fc6f0;--ms-label:#d5ecff;--ms-cell:#ecf7ff;--ms-orangeband:#d5ecff;--ms-orange:#2277bb;--ms-cth:#a8d4f5;--ms-ctd:#ecf7ff}",
|
| 319 |
+
"Zebra": "body{background:repeating-linear-gradient(135deg,#000 0 16px,#fff 16px 32px)}.master{background:#fff}:root{--ms-band:#000;--ms-label:#e8e8e8;--ms-cell:#f7f7f7;--ms-labeltext:#000;--ms-orangeband:#000;--ms-orange:#fff;--ms-cth:#000;--ms-ctd:#eee;--ms-blue:#000}",
|
| 320 |
+
"Matrix": "body{background:#000}.master{background:#020a02;color:#39ff5a}:root{--ms-band:#0a3d0a;--ms-label:#04140 4;--ms-cell:#031003;--ms-labeltext:#39ff5a;--ms-orangeband:#052505;--ms-orange:#39ff5a;--ms-cth:#0a3d0a;--ms-ctd:#031003;--ms-blue:#39ff5a;--ms-page:#020a02}h1,h2,h3,p,li,td,th,div,span{color:#39ff5a}",
|
| 321 |
+
"Flames": "body{background:linear-gradient(180deg,#1a0000,#4d0f00 40%,#993300)}.master{background:#fff7ef}:root{--ms-band:#cc3300;--ms-label:#ffd9b3;--ms-cell:#fff0e0;--ms-labeltext:#992200;--ms-orangeband:#ffb366;--ms-orange:#cc2200;--ms-cth:#ff6600;--ms-ctd:#ffe6cc}",
|
| 322 |
+
"Sunset": "body{background:linear-gradient(180deg,#3d1635,#7a2b3d 45%,#c96f3f)}.master{background:#fff5f0}:root{--ms-band:#b0486a;--ms-label:#ffd9e0;--ms-cell:#fff0f3;--ms-labeltext:#8a2c48;--ms-orangeband:#ffd9c0;--ms-orange:#c2452a;--ms-cth:#e98a5f;--ms-ctd:#ffeadd}",
|
| 323 |
+
};
|
| 324 |
+
// fix the Matrix typo above at runtime (space in a hex) — fail-closed sanitizer would keep it, so scrub:
|
| 325 |
+
LAYOUTS["Matrix"] = LAYOUTS["Matrix"].replace("#04140 4", "#041404");
|
| 326 |
+
|
| 327 |
+
const NAV = [["Home", () => goHome()], ["Browse", () => toast("Browse opens when spaces opt in — for now, walk the Top 8")], ["Search", () => $("q").focus()],
|
| 328 |
+
["Invite", () => share()], ["Film", () => open(OS, "_blank")], ["Mail", () => open(OS, "_blank")], ["Blog", () => $("blog").scrollIntoView({ behavior: "smooth" })],
|
| 329 |
+
["Favorites", () => toast("Saved spaces live in your Top 8")], ["Forum", () => toast("Coming to your space")], ["Groups", () => toast("Groups = sealed rooms — coming to your space")],
|
| 330 |
+
["Events", () => toast("Coming to your space")], ["Videos", () => open(OS, "_blank")], ["Music", () => open(OS, "_blank")], ["Classifieds", () => toast("Coming to your space")]];
|
| 331 |
+
|
| 332 |
+
let doc = null, mode = "view", curKappa = "", gestured = false;
|
| 333 |
+
const me = () => { try { return JSON.parse(localStorage.getItem(ME_KEY)); } catch (e) { return null; } };
|
| 334 |
+
const saveMe = (d, l) => localStorage.setItem(ME_KEY, JSON.stringify({ payload: YS.encode(d), link: l }));
|
| 335 |
+
const toast = (msg, ms = 2800) => { const t = $("toast"); t.textContent = msg; t.classList.add("on"); clearTimeout(t._h); t._h = setTimeout(() => t.classList.remove("on"), ms); };
|
| 336 |
+
const myLink = () => location.origin + location.pathname + "#p=v" + doc.v + "." + YS.encode(doc);
|
| 337 |
+
|
| 338 |
+
function boot() {
|
| 339 |
+
const payload = YS.parseLink(location.hash);
|
| 340 |
+
if (payload) { const p = YS.decode(payload); if (p) return show(YS.upgrade(p), "view"); }
|
| 341 |
+
const m = me();
|
| 342 |
+
if (m && m.payload) { const p = YS.decode(m.payload); if (p) { const u = YS.upgrade(p); history.replaceState(null, "", "#p=v" + u.v + "." + YS.encode(u)); return show(u, "view"); } }
|
| 343 |
+
history.replaceState(null, "", location.pathname + location.search);
|
| 344 |
+
show(SEED, "view", true);
|
| 345 |
+
}
|
| 346 |
+
addEventListener("hashchange", boot);
|
| 347 |
+
|
| 348 |
+
/* ── render: the doc IS the page; view and edit are the same anatomy ────────────────── */
|
| 349 |
+
async function show(p, m, isSeed = false) {
|
| 350 |
+
doc = YS.upgrade(p); mode = m;
|
| 351 |
+
document.body.classList.toggle("edit", mode === "edit");
|
| 352 |
+
$("usercss").textContent = doc.customCss || "";
|
| 353 |
+
const first = (doc.name || "Your").split(/\s+/)[0];
|
| 354 |
+
|
| 355 |
+
// nav (once)
|
| 356 |
+
if (!$("navbar").childElementCount) NAV.forEach(([label, fn], i) => {
|
| 357 |
+
if (i) { const s = document.createElement("span"); s.className = "sep"; s.textContent = "|"; $("navbar").appendChild(s); }
|
| 358 |
+
const a = document.createElement("a"); a.textContent = label; a.onclick = fn; $("navbar").appendChild(a);
|
| 359 |
+
});
|
| 360 |
+
|
| 361 |
+
// left column
|
| 362 |
+
$("name").textContent = doc.name;
|
| 363 |
+
$("headline").textContent = doc.headline;
|
| 364 |
+
$("avatar").innerHTML = /^https:\/\//.test(doc.avatar) ? `<img src="${esc(doc.avatar)}" alt="">` : (esc(doc.avatar) || (mode === "edit" ? "+" : "🪐"));
|
| 365 |
+
for (const k of ["gender", "age", "city", "region", "country"]) $("d-" + k).textContent = doc.demog[k];
|
| 366 |
+
$("moodemo").textContent = doc.mood.emo; $("moodword").textContent = doc.mood.word;
|
| 367 |
+
const owner = !!(me() && me().payload === YS.encode(doc));
|
| 368 |
+
// honest presence: only the owner is provably online (they're holding the page); visitors see no invented row
|
| 369 |
+
$("lastlogin").textContent = owner ? ("Last Login: " + new Date().toLocaleDateString()) : "";
|
| 370 |
+
$("online").style.display = owner ? "" : "none";
|
| 371 |
+
|
| 372 |
+
$("contacth").textContent = "Contacting " + (doc.name || "this space");
|
| 373 |
+
const CONTACT = [
|
| 374 |
+
["✉️", "Send Message", () => doc.wall ? open(doc.wall, "_blank") : open(OS, "_blank")],
|
| 375 |
+
["↪️", "Forward to Friend", share],
|
| 376 |
+
["➕", "Add to Friends", addToFriends],
|
| 377 |
+
["⭐", "Add to Favorites", () => { toast("Saved. Favorites live in YOUR Top 8 — tap Add to Friends to place them."); }],
|
| 378 |
+
["💬", "Instant Message", () => open(OS, "_blank")],
|
| 379 |
+
["🚫", "Block User", () => toast("Blocked here = just leave. Nobody can follow you — the page can't track anyone.")],
|
| 380 |
+
["👥", "Add to Group", () => toast("Groups = sealed rooms — coming to your space")],
|
| 381 |
+
["🏳️", "Report", () => toast("A κ page can't be edited by anyone but its owner — share concerns with the person who sent the link")],
|
| 382 |
+
];
|
| 383 |
+
$("contactgrid").innerHTML = "";
|
| 384 |
+
CONTACT.forEach(([g, label, fn]) => { const a = document.createElement("a"); a.textContent = g + " " + label; a.onclick = fn; $("contactgrid").appendChild(a); });
|
| 385 |
+
|
| 386 |
+
$("thelink").textContent = location.hash.includes("#p=") ? location.href : "mint your link with Make It Mine ↓";
|
| 387 |
+
$("thelink").onclick = async () => { try { await navigator.clipboard.writeText(location.href); toast("Link copied — the link IS your whole page 💫"); } catch (e) {} };
|
| 388 |
+
$("kap").textContent = "κ…";
|
| 389 |
+
try { curKappa = await YS.kappa(doc); $("kap").textContent = "κ·" + YS.hexOf(curKappa).slice(0, 10) + " — tap to verify"; } catch (e) { $("kap").textContent = "κ offline"; }
|
| 390 |
+
|
| 391 |
+
sideTable("interests", first + "'s Interests", [["General", "general"], ["Music", "music"], ["Movies", "movies"], ["Television", "television"], ["Books", "books"], ["Heroes", "heroes"]], doc.interests, "eki");
|
| 392 |
+
sideTable("details", first + "'s Details", [["Status", "status"], ["Here for", "hereFor"], ["Hometown", "hometown"], ["Zodiac Sign", "zodiac"], ["Smoke / Drink", "smokeDrink"], ["Children", "children"], ["Education", "education"], ["Occupation", "occupation"]], doc.details, "ekd");
|
| 393 |
+
|
| 394 |
+
// right column
|
| 395 |
+
const viewer = me();
|
| 396 |
+
$("netbanner").textContent = owner ? "This is your space — you're home."
|
| 397 |
+
: viewer ? (doc.name || "This space") + " is in your extended network"
|
| 398 |
+
: (doc.name || "This space") + " is one tap away from being your network";
|
| 399 |
+
const blog = $("blog"); blog.innerHTML = "";
|
| 400 |
+
if (doc.blog.length) {
|
| 401 |
+
blog.innerHTML = `<p><b>${esc(first)}'s Latest Blog Entry</b> <a>[Subscribe to this Blog]</a></p>` +
|
| 402 |
+
doc.blog.map((b) => `<p><a href="${esc(b.link)}" target="_blank" rel="noopener">${esc(b.title)}</a></p>`).join("");
|
| 403 |
+
}
|
| 404 |
+
$("blurbh").textContent = first + "'s Blurbs";
|
| 405 |
+
$("aboutme").textContent = doc.blurbs.aboutMe; $("meet").textContent = doc.blurbs.meet;
|
| 406 |
+
|
| 407 |
+
const s = doc.song; $("player").style.display = s ? "" : "none";
|
| 408 |
+
if (s) { $("songt").textContent = s.title; $("songa").textContent = s.artist; }
|
| 409 |
+
|
| 410 |
+
$("friendh").textContent = first + "'s Friend Space";
|
| 411 |
+
$("friendcount").innerHTML = `${esc(doc.name || "This space")} has <span class="focus">${doc.top.length}</span> friend${doc.top.length === 1 ? "" : "s"}.`;
|
| 412 |
+
const fg = $("friendgrid"); fg.innerHTML = "";
|
| 413 |
+
doc.top.forEach((d, i) => {
|
| 414 |
+
const isSpace = !!YS.parseLink(d.link);
|
| 415 |
+
const fig = document.createElement("figure");
|
| 416 |
+
fig.innerHTML = `<div class="face">${/^https:\/\//.test(d.photo) ? `<img src="${esc(d.photo)}" alt="">` : (esc(d.photo) || esc((d.name || "•")[0].toUpperCase()))}</div><figcaption><a>${esc(d.name || "friend")}</a></figcaption><button class="rm" aria-label="remove">×</button>`;
|
| 417 |
+
fig.onclick = (ev) => { if (ev.target.className === "rm") return commit(YS.removeDoor(doc, i));
|
| 418 |
+
if (isSpace || d.link.startsWith(location.origin)) location.assign(d.link); else open(d.link, "_blank", "noopener"); };
|
| 419 |
+
fg.appendChild(fig);
|
| 420 |
+
});
|
| 421 |
+
$("viewall").textContent = "View All of " + first + "'s Friends";
|
| 422 |
+
$("viewall").onclick = () => toast(doc.top.length ? doc.top.map((d) => d.name || "friend").join(" · ") : "No friends yet — that's what forking is for");
|
| 423 |
+
|
| 424 |
+
$("commenth").textContent = first + "'s Friends Comments";
|
| 425 |
+
$("ccount").innerHTML = doc.wall
|
| 426 |
+
? `Comments live in <b>${esc(first)}'s sealed wall</b> — step in to read and write. Honest number: only the room knows.`
|
| 427 |
+
: `Displaying <b>0</b> of <b>0</b> comments — this wall isn't open yet.`;
|
| 428 |
+
$("commentrows").innerHTML = doc.wall ? "" : `<table><tr><th>${esc(first)}<br><div style="font-size:30px">${esc(doc.avatar) || "🪐"}</div></th><td><b>${new Date().toLocaleDateString()}</b><br><br>Your wall opens when you weld a sealed room to this page. Until then: real numbers only — this page never invents a comment.</td></tr></table>`;
|
| 429 |
+
$("addcomment").onclick = () => doc.wall ? open(doc.wall, "_blank") : toast(owner ? "Weld a room link into your wall field (rooms are live in the messenger)" : "This wall isn't open yet — fork the page and open your own");
|
| 430 |
+
|
| 431 |
+
// hint + CTA
|
| 432 |
+
$("hint").classList.toggle("on", isSeed);
|
| 433 |
+
if (isSeed) $("hint").innerHTML = "👋 <b>Welcome back.</b> This is Q's page — same page your thumbs remember, except it lives inside the link itself. <b>Make It Mine</b> below ↓";
|
| 434 |
+
const cta = $("cta"); cta.innerHTML = "";
|
| 435 |
+
const btn = (label, cls, fn) => { const b = document.createElement("button"); b.className = "btn2004 " + cls; b.textContent = label; b.onclick = fn; cta.appendChild(b); };
|
| 436 |
+
if (mode === "edit") btn("Done — mint my link", "go", finish);
|
| 437 |
+
else if (owner) { btn("Edit My Space", "", () => show(doc, "edit")); btn("Share", "go", share); }
|
| 438 |
+
else { btn("✨ Make It Mine", "go", makeItMine); btn("Share", "", share); }
|
| 439 |
+
|
| 440 |
+
renderEditRacks();
|
| 441 |
+
wireEditables();
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
function sideTable(id, title, rows, data, ekAttr) {
|
| 445 |
+
const tb = $(id).querySelector("tbody"); tb.innerHTML = "";
|
| 446 |
+
const live = rows.filter(([, k]) => data[k] || mode === "edit");
|
| 447 |
+
$(id).style.display = live.length ? "" : "none";
|
| 448 |
+
if (!live.length) return;
|
| 449 |
+
tb.innerHTML = `<tr class="h2row"><td colspan="2">${esc(title)}</td></tr>` +
|
| 450 |
+
live.map(([label, k]) => `<tr><th>${esc(label)}</th><td class="v" data-${ekAttr}="${k}" data-ph="…">${esc(data[k])}</td></tr>`).join("");
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
/* ── the loop ────────────────────────────────────────────────────────────────────────── */
|
| 454 |
+
async function makeItMine() {
|
| 455 |
+
let mine;
|
| 456 |
+
try { mine = await YS.fork(doc, location.hash.includes("#p=") ? location.href : location.origin + location.pathname); }
|
| 457 |
+
catch (e) { mine = YS.upgrade(doc); mine = YS.withFields(mine, { name: "", via: { k: "", name: doc.name } }); }
|
| 458 |
+
toast("It's yours. Decorate, then mint your link ✨");
|
| 459 |
+
show(mine, "edit");
|
| 460 |
+
scrollTo({ top: 0, behavior: "smooth" });
|
| 461 |
+
}
|
| 462 |
+
async function addToFriends() { // 2004 "Add to Friends" = put THIS page in MY Top 8
|
| 463 |
+
const m = me();
|
| 464 |
+
if (!m) return makeItMine();
|
| 465 |
+
const my = YS.upgrade(YS.decode(m.payload));
|
| 466 |
+
const updated = YS.addDoor(my, { name: doc.name || "friend", link: location.href, photo: doc.avatar });
|
| 467 |
+
saveMe(updated, m.link);
|
| 468 |
+
toast((doc.name || "This space") + " added to your Top 8 ✔ — friendship is mutual when they add you back");
|
| 469 |
+
}
|
| 470 |
+
function commit(next) { doc = YS.identity(next); show(doc, mode); }
|
| 471 |
+
|
| 472 |
+
function collectEdits() {
|
| 473 |
+
const g = {}; for (const k of ["gender", "age", "city", "region", "country"]) g[k] = $("d-" + k).textContent.trim();
|
| 474 |
+
const interests = {}, details = {};
|
| 475 |
+
document.querySelectorAll("[data-eki]").forEach((el) => interests[el.dataset.eki] = el.textContent.trim());
|
| 476 |
+
document.querySelectorAll("[data-ekd]").forEach((el) => details[el.dataset.ekd] = el.textContent.trim());
|
| 477 |
+
return YS.withFields(doc, {
|
| 478 |
+
name: $("name").textContent.trim(), headline: $("headline").textContent.trim(),
|
| 479 |
+
mood: { emo: $("moodemo").textContent.trim(), word: $("moodword").textContent.trim() },
|
| 480 |
+
demog: g, interests: { ...doc.interests, ...interests }, details: { ...doc.details, ...details },
|
| 481 |
+
blurbs: { aboutMe: $("aboutme").textContent.trim(), meet: $("meet").textContent.trim() },
|
| 482 |
+
});
|
| 483 |
+
}
|
| 484 |
+
async function finish() {
|
| 485 |
+
doc = collectEdits();
|
| 486 |
+
saveMe(doc, myLink());
|
| 487 |
+
history.replaceState(null, "", "#p=v" + doc.v + "." + YS.encode(doc));
|
| 488 |
+
await show(doc, "view");
|
| 489 |
+
toast("Minted. The URL box on the left IS your page — copy it, post it anywhere.");
|
| 490 |
+
share();
|
| 491 |
+
}
|
| 492 |
+
async function share() {
|
| 493 |
+
const url = location.href;
|
| 494 |
+
const title = (doc.name ? doc.name + "'s" : "my") + " space";
|
| 495 |
+
try { if (navigator.share) return await navigator.share({ title, text: "step into " + title, url }); } catch (e) { if (e.name === "AbortError") return; }
|
| 496 |
+
try { await navigator.clipboard.writeText(url); toast("Link copied — drop it in any chat 💫"); }
|
| 497 |
+
catch (e) { prompt("Copy your space link:", url); }
|
| 498 |
+
}
|
| 499 |
+
function goHome() { const m = me(); if (m && m.link) location.assign(m.link); else { location.hash = ""; } }
|
| 500 |
+
|
| 501 |
+
/* ── edit affordances ───────────────────────────────────────────────────────────────── */
|
| 502 |
+
function wireEditables() {
|
| 503 |
+
const on = mode === "edit";
|
| 504 |
+
document.querySelectorAll("[data-ek],[data-eki],[data-ekd],[data-ekg]").forEach((el) => { el.contentEditable = on ? "plaintext-only" : "false"; });
|
| 505 |
+
}
|
| 506 |
+
function renderEditRacks() {
|
| 507 |
+
const rack = $("layoutchips"); rack.innerHTML = "";
|
| 508 |
+
Object.keys(LAYOUTS).forEach((name) => { const b = document.createElement("button"); b.className = "btn2004"; b.textContent = name;
|
| 509 |
+
b.onclick = () => { commit(YS.withFields(collectEdits(), { customCss: LAYOUTS[name] })); toast(name + " layout on — via the rack, free forever"); }; rack.appendChild(b); });
|
| 510 |
+
$("csspaste").value = doc.customCss || "";
|
| 511 |
+
}
|
| 512 |
+
$("cssapply").onclick = () => {
|
| 513 |
+
const clean = YS.sanitizeCss($("csspaste").value);
|
| 514 |
+
if ($("csspaste").value.trim() && !clean) return toast("Code refused — CSS only: no <, no @import, no scripts, urls must be data:/https:");
|
| 515 |
+
commit(YS.withFields(collectEdits(), { customCss: clean }));
|
| 516 |
+
toast(clean ? "Your code is live on your page ✨" : "Back to the classic skin");
|
| 517 |
+
};
|
| 518 |
+
$("avatar").onclick = () => { if (mode !== "edit") return; const p = $("picker"); p.classList.toggle("on");
|
| 519 |
+
const g = $("emojis"); if (!g.childElementCount) EMOJIS.forEach((e) => { const b = document.createElement("button"); b.textContent = e;
|
| 520 |
+
b.onclick = () => { p.classList.remove("on"); commit(YS.withFields(collectEdits(), { avatar: e })); }; g.appendChild(b); }); };
|
| 521 |
+
$("avurl").onchange = () => { $("picker").classList.remove("on"); commit(YS.withFields(collectEdits(), { avatar: $("avurl").value.trim() })); };
|
| 522 |
+
document.addEventListener("click", (e) => { if (!$("picker").contains(e.target) && e.target !== $("avatar")) $("picker").classList.remove("on"); });
|
| 523 |
+
|
| 524 |
+
let srchT = null;
|
| 525 |
+
$("srchin").oninput = () => { clearTimeout(srchT); srchT = setTimeout(async () => {
|
| 526 |
+
const q = $("srchin").value.trim(); const box = $("srchres"); if (!q) { box.innerHTML = ""; return; }
|
| 527 |
+
try {
|
| 528 |
+
const r = await fetch(`https://itunes.apple.com/search?media=music&limit=5&term=${encodeURIComponent(q)}`);
|
| 529 |
+
const js = await r.json(); box.innerHTML = "";
|
| 530 |
+
(js.results || []).forEach((t) => { const d = document.createElement("div"); d.className = "res";
|
| 531 |
+
d.innerHTML = `<img src="${esc(t.artworkUrl100 || "")}" alt=""><div><b>${esc(t.trackName)}</b><br><span>${esc(t.artistName)}</span></div>`;
|
| 532 |
+
d.onclick = () => { commit(YS.withFields(collectEdits(), { song: { title: t.trackName, artist: t.artistName, art: t.artworkUrl100 || "", query: `${t.artistName} ${t.trackName}`, preview: t.previewUrl || "" } })); toast("Song set 🎧 — it plays when someone enters"); };
|
| 533 |
+
box.appendChild(d); });
|
| 534 |
+
} catch (e) { box.innerHTML = `<div class="res">search unreachable — try again later</div>`; }
|
| 535 |
+
}, 350); };
|
| 536 |
+
$("dooradd").onclick = () => { const l = $("doorlink").value.trim(), n = $("doorname").value.trim();
|
| 537 |
+
if (!l) return toast("Paste a link first");
|
| 538 |
+
commit(YS.addDoor(collectEdits(), { name: n || "friend", link: l, photo: "" })); $("doorlink").value = $("doorname").value = ""; };
|
| 539 |
+
|
| 540 |
+
/* ── the song: first gesture starts it (the lawful 2004 autoplay) ───────────────────── */
|
| 541 |
+
async function playSong(toggle) {
|
| 542 |
+
const s = doc.song; if (!s) return;
|
| 543 |
+
const a = $("audio"), btn = $("songbtn");
|
| 544 |
+
if (toggle && !a.paused) { a.pause(); btn.textContent = "▶"; try { busCmd("pause"); } catch (e) {} return; }
|
| 545 |
+
if (await busCmd("play", [s.query || `${s.artist} ${s.title}`])) { btn.textContent = "❚❚"; toast("Playing in Holo Music 🎶"); return; }
|
| 546 |
+
let src = s.preview;
|
| 547 |
+
if (!src && (s.query || s.title)) { try {
|
| 548 |
+
const r = await fetch(`https://itunes.apple.com/search?media=music&limit=1&term=${encodeURIComponent(s.query || s.artist + " " + s.title)}`);
|
| 549 |
+
src = ((await r.json()).results || [])[0]?.previewUrl || ""; } catch (e) {} }
|
| 550 |
+
if (!src) { if (toggle) toast("Song not reachable right now"); return; }
|
| 551 |
+
a.src = src; try { await a.play(); btn.textContent = "❚❚"; } catch (e) { if (toggle) toast("Tap ▶ to play"); }
|
| 552 |
+
a.onended = () => { btn.textContent = "▶"; };
|
| 553 |
+
}
|
| 554 |
+
$("songbtn").onclick = () => playSong(true);
|
| 555 |
+
const firstGesture = () => { if (gestured) return; gestured = true; if (mode === "view" && doc && doc.song) playSong(false); };
|
| 556 |
+
addEventListener("pointerdown", firstGesture, { once: false });
|
| 557 |
+
addEventListener("scroll", firstGesture, { once: true, passive: true });
|
| 558 |
+
|
| 559 |
+
function busCmd(cmd, args = []) {
|
| 560 |
+
return new Promise((res) => { let done = false;
|
| 561 |
+
try { const ch = new BroadcastChannel("holo-music-ctl"); const id = Math.random().toString(36).slice(2);
|
| 562 |
+
ch.onmessage = (e) => { if (e.data && e.data.re === id) { done = true; ch.close(); res(!!e.data.ok); } };
|
| 563 |
+
ch.postMessage({ id, cmd, args }); setTimeout(() => { if (!done) { ch.close(); res(false); } }, 800);
|
| 564 |
+
} catch (e) { res(false); } });
|
| 565 |
+
}
|
| 566 |
+
|
| 567 |
+
$("kap").onclick = async () => { try {
|
| 568 |
+
const ok = await YS.verify(doc, curKappa);
|
| 569 |
+
$("kap").classList.toggle("ok", ok); setTimeout(() => $("kap").classList.remove("ok"), 1600);
|
| 570 |
+
await navigator.clipboard.writeText(curKappa); toast(ok ? "re-derived ✓ · κ copied — the page you see IS the link you share" : "κ MISMATCH — refused");
|
| 571 |
+
} catch (e) { toast("κ unavailable here"); } };
|
| 572 |
+
|
| 573 |
+
$("navsignup").onclick = () => makeItMine();
|
| 574 |
+
$("navhelp").onclick = () => { location.hash = ""; };
|
| 575 |
+
$("qgo").onclick = () => { const v = $("q").value.trim(); const p = YS.parseLink(v); if (p) location.assign(location.pathname + "#p=v" + (YS.decode(p).v) + "." + p); else toast(v ? "Paste a space link to teleport to it" : "Search = paste any space link"); };
|
| 576 |
+
$("fnew").onclick = () => show(YS.identity({ v: 3, name: "", customCss: "" }), "edit");
|
| 577 |
+
["fabout", "ffaq", "fterms", "fprivacy", "fsafety", "fcontact", "fpromote"].forEach((id) => $(id).onclick = () => toast("This page has no company behind it — it's a κ. About: the footer says it all."));
|
| 578 |
+
|
| 579 |
+
boot();
|
| 580 |
+
</script>
|
| 581 |
+
</body>
|
| 582 |
+
</html>
|