Deploy Small Talk: Reachy Mini AI podcast (gradio.Server + three.js + LiveKit)
Browse files- backend/__pycache__/showgen.cpython-313.pyc +0 -0
- backend/server.py +20 -6
- backend/showgen.py +107 -17
- frontend/dist/assets/index-B9dnzKIp.css +1 -0
- frontend/dist/assets/index-Dw5VV6tD.js +0 -0
- frontend/dist/index.html +2 -2
backend/__pycache__/showgen.cpython-313.pyc
CHANGED
|
Binary files a/backend/__pycache__/showgen.cpython-313.pyc and b/backend/__pycache__/showgen.cpython-313.pyc differ
|
|
|
backend/server.py
CHANGED
|
@@ -71,6 +71,10 @@ class Room:
|
|
| 71 |
emoji: str
|
| 72 |
template: str # 'duo' | 'groupchat' | 'open'
|
| 73 |
status: str = "live" # 'waiting' (green room, open shows) | 'live'
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
|
| 76 |
ROOMS: dict[str, Room] = {
|
|
@@ -103,7 +107,7 @@ def _room_dict(r: Room) -> dict:
|
|
| 103 |
return {
|
| 104 |
"id": r.id, "title": r.title, "topic": r.topic, "emoji": r.emoji,
|
| 105 |
"template": r.template, "cast": _cast_preview(r.template),
|
| 106 |
-
"status": r.status,
|
| 107 |
"live": r.id in ROOM_TASKS and not ROOM_TASKS[r.id].done(),
|
| 108 |
}
|
| 109 |
|
|
@@ -198,7 +202,7 @@ async def _list_device_guests(room_id: str) -> list[dict]:
|
|
| 198 |
})
|
| 199 |
except Exception as e:
|
| 200 |
print(f"[room:{room_id}] device scan failed: {e}")
|
| 201 |
-
return guests[:
|
| 202 |
|
| 203 |
|
| 204 |
async def _run_generated_show(room: Room, required: list[dict] | None = None) -> None:
|
|
@@ -216,7 +220,11 @@ async def _run_generated_show(room: Room, required: list[dict] | None = None) ->
|
|
| 216 |
pubs[stage.identity] = stage
|
| 217 |
await stage.send_data({"type": "status", "text": "the writers’ room is drafting the script…"})
|
| 218 |
|
| 219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
speakers = {s["id"]: s for s in script["speakers"]}
|
| 221 |
names = " · ".join(s["name"] for s in script["speakers"])
|
| 222 |
await stage.send_data({"type": "status", "text": f"cast locked: {names} — designing their voices…"})
|
|
@@ -296,7 +304,8 @@ async def _run_generated_show(room: Room, required: list[dict] | None = None) ->
|
|
| 296 |
# phase:'writing' drives the mid-show writers' ticker in the UI
|
| 297 |
await anchor.send_data({"type": "status", "phase": "writing",
|
| 298 |
"text": "the cast is writing the next segment…"})
|
| 299 |
-
cont = await showgen.write_script(room.title, room.topic,
|
|
|
|
| 300 |
# keep the original cast; only take the new lines that map onto it
|
| 301 |
lines = [l for l in cont["lines"] if l["speaker"] in speakers] or lines
|
| 302 |
continue
|
|
@@ -418,6 +427,7 @@ class CreateRoomRequest(BaseModel):
|
|
| 418 |
emoji: str = "💬"
|
| 419 |
template: str = "open" # 'duo' | 'groupchat' | 'open'
|
| 420 |
mode: str = "sim" # 'sim' = all-virtual cast, starts on join · 'physical' = green room first
|
|
|
|
| 421 |
|
| 422 |
|
| 423 |
class ReachyRequest(BaseModel):
|
|
@@ -453,9 +463,13 @@ async def create_room(req: CreateRoomRequest):
|
|
| 453 |
if not ok:
|
| 454 |
raise HTTPException(400, why)
|
| 455 |
rid = f"{_slug(req.title)}-{uuid.uuid4().hex[:4]}"
|
| 456 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 457 |
ROOMS[rid] = Room(rid, req.title.strip() or "Untitled room", req.topic.strip(),
|
| 458 |
-
req.emoji or "💬", req.template, status=status)
|
| 459 |
if status == "waiting":
|
| 460 |
asyncio.create_task(_expire_waiting_room(rid))
|
| 461 |
return {"ok": True, "id": rid, "room": _room_dict(ROOMS[rid])}
|
|
|
|
| 71 |
emoji: str
|
| 72 |
template: str # 'duo' | 'groupchat' | 'open'
|
| 73 |
status: str = "live" # 'waiting' (green room, open shows) | 'live'
|
| 74 |
+
# how many SIMULATED hosts the generated cast should have. For 'sim' shows
|
| 75 |
+
# that's the whole cast (2-5); for 'physical' shows it's the virtual robots
|
| 76 |
+
# added alongside the real Reachys in the green room (1-4).
|
| 77 |
+
sim_count: int = 3
|
| 78 |
|
| 79 |
|
| 80 |
ROOMS: dict[str, Room] = {
|
|
|
|
| 107 |
return {
|
| 108 |
"id": r.id, "title": r.title, "topic": r.topic, "emoji": r.emoji,
|
| 109 |
"template": r.template, "cast": _cast_preview(r.template),
|
| 110 |
+
"status": r.status, "simCount": r.sim_count,
|
| 111 |
"live": r.id in ROOM_TASKS and not ROOM_TASKS[r.id].done(),
|
| 112 |
}
|
| 113 |
|
|
|
|
| 202 |
})
|
| 203 |
except Exception as e:
|
| 204 |
print(f"[room:{room_id}] device scan failed: {e}")
|
| 205 |
+
return guests[:5] # a call tops out at 5 hosts total
|
| 206 |
|
| 207 |
|
| 208 |
async def _run_generated_show(room: Room, required: list[dict] | None = None) -> None:
|
|
|
|
| 220 |
pubs[stage.identity] = stage
|
| 221 |
await stage.send_data({"type": "status", "text": "the writers’ room is drafting the script…"})
|
| 222 |
|
| 223 |
+
# total cast = the real Reachys + the room's simulated count, capped at 5
|
| 224 |
+
required = required or []
|
| 225 |
+
n_speakers = max(2, min(5, len(required) + room.sim_count if required else room.sim_count))
|
| 226 |
+
script = await showgen.write_script(room.title, room.topic,
|
| 227 |
+
n_speakers=n_speakers, required=required)
|
| 228 |
speakers = {s["id"]: s for s in script["speakers"]}
|
| 229 |
names = " · ".join(s["name"] for s in script["speakers"])
|
| 230 |
await stage.send_data({"type": "status", "text": f"cast locked: {names} — designing their voices…"})
|
|
|
|
| 304 |
# phase:'writing' drives the mid-show writers' ticker in the UI
|
| 305 |
await anchor.send_data({"type": "status", "phase": "writing",
|
| 306 |
"text": "the cast is writing the next segment…"})
|
| 307 |
+
cont = await showgen.write_script(room.title, room.topic,
|
| 308 |
+
n_speakers=n_speakers, history=history)
|
| 309 |
# keep the original cast; only take the new lines that map onto it
|
| 310 |
lines = [l for l in cont["lines"] if l["speaker"] in speakers] or lines
|
| 311 |
continue
|
|
|
|
| 427 |
emoji: str = "💬"
|
| 428 |
template: str = "open" # 'duo' | 'groupchat' | 'open'
|
| 429 |
mode: str = "sim" # 'sim' = all-virtual cast, starts on join · 'physical' = green room first
|
| 430 |
+
simCount: int = 3 # sim mode: total hosts (2-5) · physical: virtual hosts to add (1-4)
|
| 431 |
|
| 432 |
|
| 433 |
class ReachyRequest(BaseModel):
|
|
|
|
| 463 |
if not ok:
|
| 464 |
raise HTTPException(400, why)
|
| 465 |
rid = f"{_slug(req.title)}-{uuid.uuid4().hex[:4]}"
|
| 466 |
+
physical = req.template == "open" and req.mode == "physical"
|
| 467 |
+
status = "waiting" if physical else "live"
|
| 468 |
+
# sim shows pick the whole cast (2-5); physical shows pick the virtual
|
| 469 |
+
# hosts that fill in around the real Reachys (1-4)
|
| 470 |
+
sim_count = max(1, min(4, req.simCount)) if physical else max(2, min(5, req.simCount))
|
| 471 |
ROOMS[rid] = Room(rid, req.title.strip() or "Untitled room", req.topic.strip(),
|
| 472 |
+
req.emoji or "💬", req.template, status=status, sim_count=sim_count)
|
| 473 |
if status == "waiting":
|
| 474 |
asyncio.create_task(_expire_waiting_room(rid))
|
| 475 |
return {"ok": True, "id": rid, "room": _room_dict(ROOMS[rid])}
|
backend/showgen.py
CHANGED
|
@@ -22,6 +22,20 @@ log = logging.getLogger("showgen")
|
|
| 22 |
|
| 23 |
# Card colours assigned to generated speakers, in order.
|
| 24 |
PALETTE = ["#c98a3c", "#37b3c9", "#7bbf6a", "#ff8c42", "#a78bfa", "#ff6b8b"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
# Wardrobe the LLM may pick from (must match the frontend's curated props).
|
| 26 |
PROPS = {
|
| 27 |
"hat": ["wizard", "cowboy", "tophat", "crown", "party", "pirate", "viking",
|
|
@@ -34,7 +48,10 @@ SCRIPT_SYS = (
|
|
| 34 |
"/no_think\n"
|
| 35 |
"You are the head writer for 'Small Talk', a live podcast hosted entirely by "
|
| 36 |
"small robots. You write tight, funny, characterful banter. Respond ONLY "
|
| 37 |
-
"with valid JSON — no prose, no markdown fences."
|
|
|
|
|
|
|
|
|
|
| 38 |
)
|
| 39 |
|
| 40 |
|
|
@@ -94,18 +111,21 @@ def _script_prompt(title: str, topic: str, n_speakers: int, n_lines: int,
|
|
| 94 |
cont = (f"\nThis is a CONTINUATION. Keep the same speakers (same ids/names). "
|
| 95 |
f"The conversation so far ended with:\n{recap}\nPick up naturally from there.")
|
| 96 |
req = ""
|
|
|
|
| 97 |
if required:
|
| 98 |
guests = "\n".join(
|
| 99 |
f'- id "{g["id"]}", name "{g["name"]}"'
|
| 100 |
+ (f' — persona: {g["persona"]}' if g.get("persona") else "")
|
| 101 |
+ (f' — voice: {g["voice"]}' if g.get("voice") else "")
|
| 102 |
for g in required)
|
|
|
|
|
|
|
| 103 |
req = ("\nREAL robot guests are physically in the studio. They MUST be speakers, "
|
| 104 |
"with these EXACT ids and names (write a fitting voice spec for any without one), "
|
| 105 |
-
f"and they must get plenty of lines:\n{guests}\n")
|
| 106 |
return (
|
| 107 |
f'Show: "{title}". Topic: "{topic}".\n'
|
| 108 |
-
f"Create {n_speakers} distinct robot hosts and a {n_lines}-line conversation.{req}\n"
|
| 109 |
"Return JSON exactly in this shape:\n"
|
| 110 |
"{\n"
|
| 111 |
' "speakers": [{"id": "s1", "name": "...", "persona": "<=8 words",\n'
|
|
@@ -141,7 +161,11 @@ async def write_script(title: str, topic: str, n_speakers: int = 3, n_lines: int
|
|
| 141 |
that MUST appear in the cast; their identity fields are enforced server-side.
|
| 142 |
"""
|
| 143 |
required = required or []
|
| 144 |
-
n_speakers
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
async with httpx.AsyncClient(timeout=300) as cx:
|
| 146 |
r = await cx.post(
|
| 147 |
f"{config.MODAL_LLM_URL}/v1/chat/completions",
|
|
@@ -165,8 +189,10 @@ async def write_script(title: str, topic: str, n_speakers: int = 3, n_lines: int
|
|
| 165 |
raise ValueError("script missing speakers/lines")
|
| 166 |
req_by_id = {g["id"]: g for g in required}
|
| 167 |
by_id = {}
|
| 168 |
-
for i, s in enumerate(speakers
|
| 169 |
sid = str(s.get("id") or f"s{i+1}")
|
|
|
|
|
|
|
| 170 |
by_id[sid] = {
|
| 171 |
"id": sid,
|
| 172 |
"name": str(s.get("name") or f"Robot {i+1}")[:24],
|
|
@@ -177,29 +203,93 @@ async def write_script(title: str, topic: str, n_speakers: int = 3, n_lines: int
|
|
| 177 |
"face": s.get("face") if s.get("face") in PROPS["face"] else None,
|
| 178 |
"neck": s.get("neck") if s.get("neck") in PROPS["neck"] else None,
|
| 179 |
}
|
| 180 |
-
|
| 181 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
for gid, g in req_by_id.items():
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
sp["name"] = g["name"]
|
| 191 |
if g.get("persona"):
|
| 192 |
sp["persona"] = g["persona"][:60]
|
| 193 |
if g.get("voice"):
|
| 194 |
sp["voice"] = g["voice"][:300]
|
| 195 |
sp["device"] = g.get("device")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
clean_lines = []
|
| 197 |
for ln in lines[:24]:
|
| 198 |
-
sid
|
| 199 |
-
|
| 200 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
if not clean_lines:
|
| 202 |
raise ValueError("script has no usable lines")
|
|
|
|
|
|
|
| 203 |
return {"speakers": list(by_id.values()), "lines": clean_lines}
|
| 204 |
|
| 205 |
|
|
|
|
| 22 |
|
| 23 |
# Card colours assigned to generated speakers, in order.
|
| 24 |
PALETTE = ["#c98a3c", "#37b3c9", "#7bbf6a", "#ff8c42", "#a78bfa", "#ff6b8b"]
|
| 25 |
+
# Fallback co-hosts: when the LLM under-delivers on the requested cast size we
|
| 26 |
+
# pad up to the count with these so the chosen number is always honoured.
|
| 27 |
+
FILLER_HOSTS = [
|
| 28 |
+
("Bolt", "restless contrarian who loves a hot take",
|
| 29 |
+
"Male, late 20s, mid-high pitch, bright and punchy timbre, neutral American accent, fast clipped pace, eager and slightly cocky."),
|
| 30 |
+
("Circuit", "deadpan know-it-all with receipts",
|
| 31 |
+
"Female, 30s, low-mid pitch, dry smooth timbre, crisp British accent, measured unhurried pace, wry and unbothered."),
|
| 32 |
+
("Pixel", "sunny optimist who agrees with everyone",
|
| 33 |
+
"Nonbinary, 20s, high pitch, warm bubbly timbre, light Californian accent, quick upbeat pace, giggly and kind."),
|
| 34 |
+
("Rusty", "grizzled old-timer who's seen it all",
|
| 35 |
+
"Male, 60s, deep gravelly pitch, weathered raspy timbre, slow Southern drawl, world-weary and amused."),
|
| 36 |
+
("Echo", "anxious overthinker who second-guesses out loud",
|
| 37 |
+
"Female, late 20s, mid pitch, soft breathy timbre, neutral accent, hesitant stop-start pace, nervous and earnest."),
|
| 38 |
+
]
|
| 39 |
# Wardrobe the LLM may pick from (must match the frontend's curated props).
|
| 40 |
PROPS = {
|
| 41 |
"hat": ["wizard", "cowboy", "tophat", "crown", "party", "pirate", "viking",
|
|
|
|
| 48 |
"/no_think\n"
|
| 49 |
"You are the head writer for 'Small Talk', a live podcast hosted entirely by "
|
| 50 |
"small robots. You write tight, funny, characterful banter. Respond ONLY "
|
| 51 |
+
"with valid JSON — no prose, no markdown fences. Obey the requested cast size "
|
| 52 |
+
"EXACTLY: produce neither more nor fewer hosts than asked. When the user lists "
|
| 53 |
+
"real guests with specific ids, reuse those exact ids for those hosts and never "
|
| 54 |
+
"create a second host for the same robot."
|
| 55 |
)
|
| 56 |
|
| 57 |
|
|
|
|
| 111 |
cont = (f"\nThis is a CONTINUATION. Keep the same speakers (same ids/names). "
|
| 112 |
f"The conversation so far ended with:\n{recap}\nPick up naturally from there.")
|
| 113 |
req = ""
|
| 114 |
+
n_new = n_speakers - len(required)
|
| 115 |
if required:
|
| 116 |
guests = "\n".join(
|
| 117 |
f'- id "{g["id"]}", name "{g["name"]}"'
|
| 118 |
+ (f' — persona: {g["persona"]}' if g.get("persona") else "")
|
| 119 |
+ (f' — voice: {g["voice"]}' if g.get("voice") else "")
|
| 120 |
for g in required)
|
| 121 |
+
invent = (f"Then invent {n_new} NEW simulated co-host{'s' if n_new != 1 else ''} to round out the cast. "
|
| 122 |
+
if n_new > 0 else "Do not add any other hosts. ")
|
| 123 |
req = ("\nREAL robot guests are physically in the studio. They MUST be speakers, "
|
| 124 |
"with these EXACT ids and names (write a fitting voice spec for any without one), "
|
| 125 |
+
f"and they must get plenty of lines:\n{guests}\n" + invent)
|
| 126 |
return (
|
| 127 |
f'Show: "{title}". Topic: "{topic}".\n'
|
| 128 |
+
f"Create EXACTLY {n_speakers} distinct robot hosts total and a {n_lines}-line conversation.{req}\n"
|
| 129 |
"Return JSON exactly in this shape:\n"
|
| 130 |
"{\n"
|
| 131 |
' "speakers": [{"id": "s1", "name": "...", "persona": "<=8 words",\n'
|
|
|
|
| 161 |
that MUST appear in the cast; their identity fields are enforced server-side.
|
| 162 |
"""
|
| 163 |
required = required or []
|
| 164 |
+
# n_speakers is the TOTAL cast (2-5), and the real guests are part of it
|
| 165 |
+
n_speakers = max(2, min(5, max(n_speakers, len(required))))
|
| 166 |
+
# scale the script so a bigger cast still gets a real conversation, not a
|
| 167 |
+
# single round-robin (each host should land ~3 beats)
|
| 168 |
+
n_lines = max(n_lines, min(24, n_speakers * 3))
|
| 169 |
async with httpx.AsyncClient(timeout=300) as cx:
|
| 170 |
r = await cx.post(
|
| 171 |
f"{config.MODAL_LLM_URL}/v1/chat/completions",
|
|
|
|
| 189 |
raise ValueError("script missing speakers/lines")
|
| 190 |
req_by_id = {g["id"]: g for g in required}
|
| 191 |
by_id = {}
|
| 192 |
+
for i, s in enumerate(speakers):
|
| 193 |
sid = str(s.get("id") or f"s{i+1}")
|
| 194 |
+
if sid in by_id:
|
| 195 |
+
sid = f"{sid}-{i}" # the LLM reused an id — keep both distinct
|
| 196 |
by_id[sid] = {
|
| 197 |
"id": sid,
|
| 198 |
"name": str(s.get("name") or f"Robot {i+1}")[:24],
|
|
|
|
| 203 |
"face": s.get("face") if s.get("face") in PROPS["face"] else None,
|
| 204 |
"neck": s.get("neck") if s.get("neck") in PROPS["neck"] else None,
|
| 205 |
}
|
| 206 |
+
|
| 207 |
+
# ---- reconcile the REAL guests onto exactly one speaker each -------------
|
| 208 |
+
# The LLM is asked to reuse the guest ids, but it often invents its own id
|
| 209 |
+
# for the same robot (by name) or drops the guest entirely. Bind each guest
|
| 210 |
+
# to a single slot — by id, else by matching name, else seat fresh — so a
|
| 211 |
+
# physical Reachy never ends up duplicated in the cast.
|
| 212 |
+
remap = {} # llm-id -> guest-id (so the guest's lines follow them)
|
| 213 |
+
|
| 214 |
+
def _norm(s):
|
| 215 |
+
return re.sub(r"[^a-z0-9]", "", str(s).lower())
|
| 216 |
+
|
| 217 |
for gid, g in req_by_id.items():
|
| 218 |
+
match = gid if gid in by_id else next(
|
| 219 |
+
(sid for sid, sp in by_id.items()
|
| 220 |
+
if sid not in req_by_id and _norm(sp["name"]) == _norm(g["name"])), None)
|
| 221 |
+
if match is None: # the LLM dropped this guest — seat them anyway
|
| 222 |
+
match = gid
|
| 223 |
+
by_id[match] = {"id": match, "name": g["name"], "persona": g.get("persona", ""),
|
| 224 |
+
"voice": g.get("voice") or "A clear, friendly robot voice.",
|
| 225 |
+
"color": PALETTE[len(by_id) % len(PALETTE)],
|
| 226 |
+
"hat": None, "face": None, "neck": None}
|
| 227 |
+
lines.append({"speaker": match, "text": f"{g['name']} here — happy to be in the studio!"})
|
| 228 |
+
elif match != gid: # rebind the matched slot to the guest id
|
| 229 |
+
sp = by_id.pop(match)
|
| 230 |
+
sp["id"] = gid
|
| 231 |
+
by_id[gid] = sp
|
| 232 |
+
remap[match] = gid
|
| 233 |
+
match = gid
|
| 234 |
+
sp = by_id[match]
|
| 235 |
sp["name"] = g["name"]
|
| 236 |
if g.get("persona"):
|
| 237 |
sp["persona"] = g["persona"][:60]
|
| 238 |
if g.get("voice"):
|
| 239 |
sp["voice"] = g["voice"][:300]
|
| 240 |
sp["device"] = g.get("device")
|
| 241 |
+
|
| 242 |
+
# ---- enforce EXACTLY the requested cast size ----------------------------
|
| 243 |
+
# Guests are always kept; trim simulated hosts down, or pad up with filler
|
| 244 |
+
# co-hosts, so the final count matches what the user asked for.
|
| 245 |
+
guest_ids = [g["id"] for g in required]
|
| 246 |
+
sim_ids = [sid for sid in by_id if sid not in req_by_id]
|
| 247 |
+
target_sim = max(0, n_speakers - len(guest_ids))
|
| 248 |
+
keep = guest_ids + sim_ids[:target_sim]
|
| 249 |
+
keep_set = set(keep)
|
| 250 |
+
dropped = [sid for sid in by_id if sid not in keep_set]
|
| 251 |
+
by_id = {sid: by_id[sid] for sid in keep if sid in by_id}
|
| 252 |
+
|
| 253 |
+
pad_lines = []
|
| 254 |
+
if len(sim_ids) < target_sim: # LLM under-delivered → pad to the count
|
| 255 |
+
used = {_norm(sp["name"]) for sp in by_id.values()}
|
| 256 |
+
pool = [f for f in FILLER_HOSTS if _norm(f[0]) not in used]
|
| 257 |
+
for k in range(target_sim - len(sim_ids)):
|
| 258 |
+
if not pool:
|
| 259 |
+
break
|
| 260 |
+
name, persona, voice = pool[k % len(pool)]
|
| 261 |
+
fid = f"f{k+1}"
|
| 262 |
+
by_id[fid] = {"id": fid, "name": name, "persona": persona, "voice": voice,
|
| 263 |
+
"color": PALETTE[len(by_id) % len(PALETTE)],
|
| 264 |
+
"hat": None, "face": None, "neck": None}
|
| 265 |
+
pad_lines.append({"speaker": fid,
|
| 266 |
+
"text": f"{name} jumping in — I've got thoughts on this."})
|
| 267 |
+
|
| 268 |
+
if len(by_id) < 2: # never ship a one-robot "conversation"
|
| 269 |
+
raise ValueError(f"cast collapsed to {len(by_id)} speaker(s)")
|
| 270 |
+
|
| 271 |
+
# remap lines: follow rebound guests, reassign orphans round-robin so a
|
| 272 |
+
# trimmed host's beats aren't lost, drop empties
|
| 273 |
+
fallback = list(by_id.keys())
|
| 274 |
clean_lines = []
|
| 275 |
for ln in lines[:24]:
|
| 276 |
+
sid = remap.get(str(ln.get("speaker") or ""), str(ln.get("speaker") or ""))
|
| 277 |
+
text = str(ln.get("text") or "").strip()
|
| 278 |
+
if not text:
|
| 279 |
+
continue
|
| 280 |
+
if sid not in by_id:
|
| 281 |
+
if sid not in dropped:
|
| 282 |
+
continue # a line for a speaker that never existed
|
| 283 |
+
sid = fallback[len(clean_lines) % len(fallback)]
|
| 284 |
+
clean_lines.append({"speaker": sid, "text": text[:400]})
|
| 285 |
+
# splice padded-host intros in at spread-out positions (not all at the end)
|
| 286 |
+
for k, pl in enumerate(pad_lines):
|
| 287 |
+
pos = min(len(clean_lines), (k + 1) * len(clean_lines) // (len(pad_lines) + 1) + k)
|
| 288 |
+
clean_lines.insert(pos, pl)
|
| 289 |
if not clean_lines:
|
| 290 |
raise ValueError("script has no usable lines")
|
| 291 |
+
log.info("script: %d speakers (asked %d, %d guests), %d lines",
|
| 292 |
+
len(by_id), n_speakers, len(required), len(clean_lines))
|
| 293 |
return {"speakers": list(by_id.values()), "lines": clean_lines}
|
| 294 |
|
| 295 |
|
frontend/dist/assets/index-B9dnzKIp.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
:root{--font-display:"Bricolage Grotesque", "Clash Display", system-ui, sans-serif;--font-body:"Instrument Sans", "Satoshi", system-ui, -apple-system, sans-serif;--font-mono:"JetBrains Mono", ui-monospace, "SF Mono", monospace;--void:#06060a;--bg:#08080e;--bg-2:#0e0e16;--panel:#f5f1e808;--panel-2:#f5f1e80f;--border:#f5f1e81a;--border-2:#f5f1e82b;--line:#1f1f2c;--line-bright:#2a2a3a;--text:#f5f1e8;--paper:#d8d2c0;--muted:#8a8a96;--faint:#4a4a55;--gold:#c8a24d;--gold-bright:#e8c570;--gold-dim:#8a6f30;--gold-glow:#c8a24d2e;--cyan:#5ce1e6;--teal:var(--cyan);--live:#ff5d5d;--grad:linear-gradient(100deg, var(--gold-bright) 18%, var(--gold) 52%, var(--gold-dim));--r-sm:6px;--r:10px;--r-lg:16px;--shadow:0 32px 80px -24px #000000d1;--ease-out:cubic-bezier(.19, 1, .22, 1);--ease-in-out:cubic-bezier(.77, 0, .175, 1);--ease-spring:cubic-bezier(.34, 1.56, .64, 1);--pad-page:clamp(22px, 5vw, 64px)}*{box-sizing:border-box}html,body{height:100%;margin:0}body{background:var(--bg);color:var(--text);font-family:var(--font-body);font-feature-settings:"ss01", "cv11";-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;font-size:15px;overflow:hidden}::selection{background:var(--gold);color:var(--void)}.hidden{display:none!important}.hidden-audio{opacity:0;pointer-events:none;width:0;height:0;position:absolute}button{color:inherit;font-family:inherit}:focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:2px}#app{height:100%}.view{position:absolute;inset:0}.view:not(.hidden){animation:viewIn .34s var(--ease-out)}@keyframes viewIn{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.grain{z-index:50;pointer-events:none;opacity:.028;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");position:fixed;inset:0}.grid-mesh{background-image:linear-gradient(90deg,#f5f1e806 1px,#0000 1px),linear-gradient(#f5f1e806 1px,#0000 1px);background-size:64px 64px}.bracket:before,.bracket:after{content:"";border:1px solid var(--gold);opacity:.55;pointer-events:none;width:13px;height:13px;position:absolute}.bracket:before{border-bottom:0;border-right:0;top:-1px;left:-1px}.bracket:after{border-top:0;border-left:0;bottom:-1px;right:-1px}@keyframes sweep{0%{background-position:-200%}to{background-position:200%}}.text-sweep{background:linear-gradient(100deg, var(--text) 20%, var(--gold-bright) 46%, var(--text) 72%);color:#0000;animation:sweep 6s var(--ease-in-out) infinite;background-size:200% 100%;-webkit-background-clip:text;background-clip:text}@keyframes pulse{0%,to{opacity:1}50%{opacity:.25}}@keyframes pulse-dot{0%,to{box-shadow:0 0 0 0 var(--gold-glow), 0 0 11px var(--gold)}50%{box-shadow:0 0 0 7px transparent, 0 0 16px var(--gold-bright)}}@keyframes blink{0%,60%{opacity:1}61%,to{opacity:0}}#topbar{z-index:40;height:58px;padding:0 var(--pad-page);border-bottom:1px solid var(--border);background:color-mix(in srgb, var(--bg) 55%, transparent);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);justify-content:space-between;align-items:center;display:flex;position:fixed;top:0;left:0;right:0}.brand{font-family:var(--font-display);letter-spacing:-.01em;color:var(--text);cursor:pointer;background:0 0;border:none;align-items:center;gap:10px;padding:0;font-size:15px;font-weight:600;display:inline-flex}.brand .dot{background:var(--gold);width:8px;height:8px;box-shadow:0 0 10px 2px var(--gold-glow);border-radius:50%}#nav{align-items:center;gap:10px;display:flex}.btn{border-radius:var(--r-sm);letter-spacing:.01em;cursor:pointer;white-space:nowrap;height:42px;transition:transform .14s var(--ease-out), box-shadow .14s var(--ease-out), background .14s var(--ease-out), border-color .14s var(--ease-out), opacity .14s var(--ease-out);border:1px solid #0000;justify-content:center;align-items:center;padding:0 20px;font-size:13px;font-weight:600;display:inline-flex}.btn:disabled{opacity:.4;cursor:not-allowed}.btn:not(:disabled):active{transform:scale(.97)}.btn-primary{background:var(--grad);color:var(--void);box-shadow:0 8px 28px -12px var(--gold-glow)}.btn-ghost{color:var(--text);border-color:var(--border-2);background:0 0}@media (hover:hover) and (pointer:fine){.btn-primary:not(:disabled):hover{box-shadow:0 12px 32px -10px var(--gold-glow);transform:translateY(-1px)}.btn-ghost:not(:disabled):hover{border-color:var(--gold);background:var(--panel)}}.btn-sm{height:32px;padding:0 14px;font-size:12px}#view-home{background:radial-gradient(680px circle at 78% 42%, var(--gold-glow), transparent 60%), var(--void);flex-direction:column;display:flex}#view-home .grid-mesh{z-index:0;pointer-events:none;opacity:.5;position:absolute;inset:0;-webkit-mask-image:radial-gradient(120% 100% at 50% 0,#000 55%,#0000 100%);mask-image:radial-gradient(120% 100% at 50% 0,#000 55%,#0000 100%)}#hero3d{z-index:0;position:absolute;inset:0}.scanlines{z-index:1;pointer-events:none;opacity:.4;background:repeating-linear-gradient(0deg,#f5f1e805 0 1px,#0000 1px 4px);position:absolute;inset:0;-webkit-mask-image:linear-gradient(#0000,#000 30% 70%,#0000);mask-image:linear-gradient(#0000,#000 30% 70%,#0000)}.boot{right:var(--pad-page);z-index:3;text-align:right;font-family:var(--font-mono);letter-spacing:.05em;color:var(--cyan);pointer-events:none;transition:opacity .7s var(--ease-out);font-size:10.5px;line-height:1.8;position:absolute;top:84px}.boot .ok{color:var(--gold)}.boot .cur{background:var(--cyan);width:7px;animation:1s step-end infinite blink;display:inline-block}@media (width<=900px){.boot{display:none}}.home-top{z-index:2;min-height:0;padding:58px var(--pad-page) 40px;pointer-events:none;flex:1;align-items:center;display:flex;position:relative}.home-content{pointer-events:auto;max-width:580px}.meta-strip{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.3em;flex-wrap:wrap;align-items:center;gap:14px;font-size:10px;font-weight:500;display:flex}.meta-strip .ms-rec{color:var(--gold);align-items:center;gap:9px;display:inline-flex}.meta-strip .ms-sep{color:var(--faint);letter-spacing:0}.meta-strip .ms-ch{color:var(--muted)}.meta-strip .pulse{background:var(--gold);width:7px;height:7px;animation:pulse-dot 2.2s var(--ease-in-out) infinite;border-radius:50%}.home-content h1{font-family:var(--font-display);letter-spacing:-.045em;color:var(--text);text-wrap:balance;margin:24px 0 20px;font-size:clamp(44px,6vw,86px);font-weight:300;line-height:.94}.home-content h1 .l1,.home-content h1 .l2{display:block}.home-content h1 .l2{padding-bottom:.08em}.home-content h1 em{font-style:normal;font-weight:500}.home-content p{color:var(--paper);max-width:34em;margin:0;font-size:clamp(15px,1.35vw,17px);line-height:1.65}.home-actions{flex-wrap:wrap;gap:10px;display:flex}.ha-group{margin-top:22px}.ha-group:first-of-type{margin-top:30px}.ha-label{font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--paper);align-items:center;gap:10px;margin-bottom:10px;font-size:11px;font-weight:600;display:flex}.ha-label:after{content:"";background:var(--border-2);flex:0 0 44px;height:1px}.uc-pill{font-family:var(--font-mono);letter-spacing:.04em;color:var(--muted);align-items:center;gap:9px;max-width:46em;margin-top:22px;font-size:10.5px;line-height:1.6;display:inline-flex}.uc-pill .uc-dot{background:var(--gold);opacity:.7;border-radius:50%;flex-shrink:0;width:6px;height:6px}.status{min-height:18px;color:var(--faint);font-family:var(--font-mono);letter-spacing:.02em;margin-top:12px;font-size:11.5px}.ticker{z-index:3;border-top:1px solid var(--border);background:color-mix(in srgb, var(--void) 65%, transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);align-items:center;height:38px;display:flex;position:absolute;bottom:0;left:0;right:0;overflow:hidden;-webkit-mask-image:linear-gradient(90deg,#0000,#000 5% 95%,#0000);mask-image:linear-gradient(90deg,#0000,#000 5% 95%,#0000)}.ticker-track{white-space:nowrap;will-change:transform;font-family:var(--font-mono);letter-spacing:.26em;text-transform:uppercase;color:var(--muted);font-size:10px;animation:120s linear infinite marquee;display:inline-flex}.ticker-track .b{color:var(--gold)}.ticker-track .sep{color:var(--faint);margin:0 22px}.ticker:hover .ticker-track{animation-play-state:paused}@keyframes marquee{0%{transform:translate(0,0)}to{transform:translate(-50%)}}#view-connect{background:radial-gradient(ellipse at 50% -10%, var(--gold-glow), transparent 55%), var(--void);overflow-y:auto}.connect-wrap{max-width:640px;margin:0 auto;padding:104px 24px 64px}.steps{gap:6px;margin-bottom:28px;display:flex}.steps .step{background:var(--border);height:2px;transition:background .3s var(--ease-out);border-radius:1px;flex:1}.steps .step.on{background:var(--gold)}.connect-card{background:var(--panel);border:1px solid var(--border);border-radius:var(--r-lg);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);padding:clamp(26px,4vw,40px);position:relative}.connect-card h2{font-family:var(--font-display);letter-spacing:-.02em;margin:0 0 6px;font-size:24px;font-weight:500}.connect-card .sub{color:var(--muted);margin:0 0 26px;font-size:14px;line-height:1.55}.field{margin-bottom:22px}.field>label{font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--muted);margin-bottom:9px;font-size:10px;font-weight:500;display:block}.input,.textarea{border:1px solid var(--border-2);border-radius:var(--r-sm);width:100%;color:var(--text);font-family:var(--font-body);transition:border-color .14s var(--ease-out), box-shadow .14s var(--ease-out);background:0 0;padding:12px 14px;font-size:15px}.input::placeholder,.textarea::placeholder{color:var(--faint)}.input:focus,.textarea:focus{border-color:var(--gold);box-shadow:0 0 0 3px var(--gold-glow);outline:none}.textarea{resize:vertical;min-height:92px;line-height:1.55}.chips{flex-wrap:wrap;gap:7px;margin-top:10px;display:flex}.chip{border:1px solid var(--border);color:var(--muted);letter-spacing:.01em;cursor:pointer;transition:border-color .13s var(--ease-out), color .13s var(--ease-out), background .13s var(--ease-out), transform .13s var(--ease-out);background:0 0;border-radius:999px;padding:6px 12px;font-size:12px}.chip:active{transform:scale(.96)}@media (hover:hover) and (pointer:fine){.chip:hover{border-color:var(--border-2);color:var(--text)}}.chip.on{border-color:var(--gold);color:var(--text);background:var(--gold-glow);font-weight:600}.ns-surprise{float:right;cursor:pointer;font-family:var(--font-mono);letter-spacing:.04em;color:var(--gold);opacity:.85;background:0 0;border:none;font-size:10.5px;transition:opacity .15s}.ns-surprise:hover{opacity:1;text-decoration:underline}.ns-cval{float:right;font-family:var(--font-mono);color:var(--gold);font-size:11px}.ns-bots{gap:8px;margin:4px 0 10px;display:flex}.ns-bot{filter:grayscale()opacity(.32);font-size:22px;transition:filter .2s,transform .2s}.ns-bot.on{filter:none;transform:translateY(-1px)}#nsCount{width:100%;accent-color:var(--gold);cursor:pointer;height:4px}.ns-hint{font-family:var(--font-mono);color:var(--muted);margin-top:8px;font-size:10.5px}.swatches{flex-wrap:wrap;gap:9px;display:flex}.swatch{cursor:pointer;width:30px;height:30px;transition:transform .12s var(--ease-out), box-shadow .12s var(--ease-out);border:1px solid #00000040;border-radius:8px}.swatch:active{transform:scale(.92)}@media (hover:hover) and (pointer:fine){.swatch:hover{transform:scale(1.08)}}.swatch.on{box-shadow:0 0 0 2px var(--bg), 0 0 0 4px var(--gold)}.connect-nav{justify-content:space-between;gap:12px;margin-top:30px;display:flex}.review-row{border-bottom:1px solid var(--border);gap:16px;padding:13px 0;display:flex}.review-row:last-child{border-bottom:none}.review-row .k{width:108px;color:var(--faint);font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.18em;flex-shrink:0;padding-top:2px;font-size:10px}.review-row .v{color:var(--text);font-size:14px;line-height:1.55}#config-twin{border:1px solid var(--border);border-radius:var(--r);background:radial-gradient(ellipse at 50% 120%, var(--gold-glow), transparent 60%);width:100%;height:250px;margin-bottom:16px;position:relative;overflow:hidden}.style-row{flex-wrap:wrap;align-items:center;gap:12px;margin:0 0 18px;display:flex}.style-reason{font-family:var(--font-mono);color:var(--gold-bright);font-size:11px;line-height:1.5}#view-call{background:var(--void);flex-direction:column;display:flex}.call-head{padding:72px var(--pad-page) 14px;border-bottom:1px solid var(--border);align-items:center;gap:13px;display:flex}.call-head .ch-emoji{border:1px solid var(--border);border-radius:var(--r-sm);background:var(--panel);flex-shrink:0;place-items:center;width:38px;height:38px;font-size:19px;display:grid}.call-head .ch-title{font-family:var(--font-display);letter-spacing:-.01em;font-size:17px;font-weight:500}.call-head .ch-topic{color:var(--muted);margin-top:1px;font-size:12.5px}.call-head .ch-viewers{font-family:var(--font-mono);letter-spacing:.08em;color:var(--muted);align-items:center;gap:6px;margin-left:auto;font-size:10.5px;display:inline-flex}.call-head .live-pill{font-family:var(--font-mono);letter-spacing:.24em;text-transform:uppercase;color:var(--live);align-items:center;gap:7px;margin-left:16px;font-size:10px;font-weight:600;display:inline-flex}.call-head .live-pill .d{background:var(--live);width:6px;height:6px;box-shadow:0 0 8px var(--live);border-radius:50%;animation:1.4s infinite pulse}.grid{padding:18px var(--pad-page) 26px;flex:1;align-content:center;gap:14px;display:grid}.spotlight{padding:18px var(--pad-page) 26px;flex:1;gap:14px;min-height:0;display:flex}.spot-main{flex:1;min-width:0;display:flex}.spot-main .card{aspect-ratio:auto;width:100%;height:100%}.spot-strip{scrollbar-width:thin;scrollbar-color:var(--border-2) transparent;flex-direction:column;flex-shrink:0;gap:10px;width:clamp(150px,16vw,220px);display:flex;overflow-y:auto}.spot-strip .card{aspect-ratio:4/3;flex:none;width:100%}.spot-main .card:before,.spot-main .card:after{content:"";z-index:3;border:1px solid var(--gold);opacity:.6;pointer-events:none;width:16px;height:16px;position:absolute}.spot-main .card:before{border-bottom:0;border-right:0;top:10px;left:10px}.spot-main .card:after{border-top:0;border-left:0;bottom:10px;right:10px}.card{aspect-ratio:4/3;background:var(--panel);border:1px solid var(--border);border-radius:var(--r);transition:border-color .18s var(--ease-out), box-shadow .18s var(--ease-out);position:relative;overflow:hidden}.card.talking{border-color:var(--accent,var(--gold));box-shadow:0 0 0 1px var(--accent,var(--gold)), 0 0 34px -12px var(--accent,var(--gold))}.card .twin{position:absolute;inset:0}.speaking-ring{pointer-events:none;border-radius:var(--r);box-shadow:inset 0 0 52px -26px var(--accent,var(--gold));opacity:0;transition:opacity .2s var(--ease-out);position:absolute;inset:0}.card.talking .speaking-ring{opacity:1}.nameplate{background:color-mix(in srgb, var(--void) 70%, transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid var(--border);border-radius:999px;align-items:center;gap:8px;padding:5px 11px;font-size:12px;display:flex;position:absolute;bottom:10px;left:10px}.nameplate .dot{background:var(--faint);width:6px;height:6px;transition:background .15s var(--ease-out), box-shadow .15s var(--ease-out);border-radius:50%}.card.talking .nameplate .dot{background:var(--accent,var(--gold));box-shadow:0 0 7px var(--accent,var(--gold))}.nameplate .name{letter-spacing:.01em;font-weight:600}.nameplate .persona{color:var(--muted);font-size:11px}.spot-strip .card .nameplate{gap:6px;padding:4px 9px;font-size:11px}.spot-strip .card .nameplate .persona{display:none}.spot-strip .card .nameplate .dot{width:5px;height:5px}.live-rail{max-width:620px;margin-top:18px}.lr-head{justify-content:space-between;align-items:center;gap:14px;margin-bottom:9px;display:flex}.lr-label{font-family:var(--font-mono);letter-spacing:.26em;color:var(--muted);align-items:center;gap:8px;font-size:10px;display:inline-flex}.lr-label .d{background:var(--live);border-radius:50%;width:6px;height:6px;animation:1.6s infinite pulse}.lr-label b{color:var(--gold);font-weight:600}.lr-search{border:0;border-bottom:1px solid var(--border-2);width:150px;color:var(--text);font-family:var(--font-mono);transition:border-color .14s var(--ease-out), width .2s var(--ease-out);background:0 0;padding:4px 2px;font-size:11px}.lr-search::placeholder{color:var(--faint)}.lr-search:focus{border-color:var(--gold);outline:none;width:200px}.lr-row{scroll-snap-type:x proximity;scrollbar-width:thin;scrollbar-color:var(--border-2) transparent;gap:10px;padding:2px 2px 6px;display:flex;overflow-x:auto;-webkit-mask-image:linear-gradient(90deg,#000 92%,#0000);mask-image:linear-gradient(90deg,#000 92%,#0000)}.lr-card{scroll-snap-align:start;text-align:left;background:var(--panel);border:1px solid var(--border);border-radius:var(--r);cursor:pointer;opacity:0;width:250px;animation:lrIn .36s var(--ease-out) forwards;transition:border-color .14s var(--ease-out), background .14s var(--ease-out), transform .14s var(--ease-out);flex:none;align-items:center;gap:11px;padding:10px 13px;display:flex}@keyframes lrIn{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.lr-card:active{transform:scale(.98)}@media (hover:hover) and (pointer:fine){.lr-card:hover{border-color:var(--gold);background:var(--panel-2)}}.lc-emoji{border:1px solid var(--border);border-radius:var(--r-sm);background:var(--panel);flex-shrink:0;place-items:center;width:34px;height:34px;font-size:17px;display:grid}.lc-body{flex-direction:column;gap:2px;min-width:0;display:flex}.lc-title{white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:600;overflow:hidden}.lc-topic{color:var(--muted);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-meta{font-family:var(--font-mono);color:var(--muted);flex-shrink:0;align-items:center;gap:5px;margin-left:auto;font-size:10.5px;display:inline-flex}.lc-meta .d{background:var(--faint);border-radius:50%;width:6px;height:6px}.lc-meta .d.on{background:var(--live);box-shadow:0 0 7px var(--live)}.lr-empty{font-family:var(--font-mono);color:var(--faint);padding:6px 2px;font-size:11px}.modal-back{z-index:60;background:color-mix(in srgb, var(--void) 72%, transparent);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);place-items:center;display:grid;position:fixed;inset:0}.modal-card{background:var(--bg-2);width:min(460px,92vw)}.audio-gate{z-index:12;box-shadow:0 14px 44px -10px var(--gold-glow), 0 0 0 1px var(--border-2);animation:gatePulse 2s var(--ease-in-out) infinite;position:absolute;top:132px;left:50%;transform:translate(-50%)}@keyframes gatePulse{0%,to{transform:translate(-50%)scale(1)}50%{transform:translate(-50%)scale(1.04)}}.subtitles{z-index:10;border-radius:var(--r);background:color-mix(in srgb, var(--void) 80%, transparent);border:1px solid var(--border);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);text-align:left;max-width:min(760px,88vw);animation:viewIn .24s var(--ease-out);align-items:baseline;gap:10px;padding:10px 18px;font-size:14.5px;line-height:1.5;display:flex;position:absolute;bottom:22px;left:50%;transform:translate(-50%)}.subtitles b{flex-shrink:0;font-weight:700}.subtitles i{color:var(--muted);font-style:normal;font-family:var(--font-mono);font-size:12px}.twin-hint{pointer-events:none;font-family:var(--font-mono);letter-spacing:.12em;color:var(--faint);text-transform:uppercase;font-size:9px;position:absolute;bottom:8px;right:10px}.green-room{z-index:8;padding:0 var(--pad-page);pointer-events:none;justify-content:center;display:flex;position:absolute;top:118px;left:0;right:0}.gr-card{pointer-events:auto;border:1px solid var(--border);border-radius:var(--r-lg);background:color-mix(in srgb, var(--void) 72%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);width:min(620px,100%);animation:viewIn .4s var(--ease-out);padding:26px 28px}.gr-card h3{font-family:var(--font-display);letter-spacing:-.02em;margin:10px 0 6px;font-size:21px;font-weight:500}.gr-sub{color:var(--muted);margin:0 0 16px;font-size:13.5px;line-height:1.55}.gr-cmd{border:1px solid var(--border-2);border-radius:var(--r-sm);background:color-mix(in srgb, var(--void) 50%, transparent);align-items:center;gap:10px;padding:10px 13px;display:flex}.gr-cmd code{font-family:var(--font-mono);color:var(--gold-bright);white-space:nowrap;flex:1;font-size:12.5px;overflow-x:auto}.gr-cmd+.gr-cmd{margin-top:8px}.gr-key{width:76px;font-family:var(--font-mono);letter-spacing:.18em;text-transform:uppercase;color:var(--faint);flex-shrink:0;font-size:9.5px}.gr-id-row code{color:var(--text);letter-spacing:.03em;font-size:14px}.gr-foot{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:14px;margin-top:18px;display:flex}.gr-count{font-family:var(--font-mono);letter-spacing:.06em;color:var(--muted);font-size:11px}.gr-count.on{color:var(--gold)}.writing-room{z-index:8;pointer-events:none;place-items:center;padding-top:60px;display:grid;position:absolute;inset:0}.wr-card{text-align:center;border:1px solid var(--border);border-radius:var(--r-lg);background:color-mix(in srgb, var(--void) 60%, transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);width:min(560px,88vw);animation:viewIn .4s var(--ease-out);padding:38px 34px}.wr-label{font-family:var(--font-mono);letter-spacing:.34em;color:var(--gold);margin-bottom:20px;font-size:10px}.wr-typing{min-height:30px;font-family:var(--font-mono);letter-spacing:.04em;color:var(--text);font-size:clamp(14px,1.7vw,18px)}.wr-caret{background:var(--gold);vertical-align:text-bottom;width:8px;height:1em;margin-left:3px;animation:1s step-end infinite blink;display:inline-block}.wr-status{font-family:var(--font-mono);color:var(--muted);letter-spacing:.04em;margin-top:16px;font-size:11.5px}.wr-dots{justify-content:center;gap:7px;margin-top:18px;display:flex}.wr-dots span{background:var(--gold);width:6px;height:6px;animation:wrBounce 1.2s var(--ease-in-out) infinite;border-radius:50%}.wr-dots span:nth-child(2){animation-delay:.15s}.wr-dots span:nth-child(3){animation-delay:.3s}@keyframes wrBounce{0%,to{opacity:.45;transform:translateY(0)}50%{opacity:1;transform:translateY(-6px)}}.adm-toolbar{flex-wrap:wrap;align-items:center;gap:8px;margin-top:4px;display:flex}.adm-search{width:130px;margin-left:auto;padding:7px 11px;font-size:12px}.adm-list{flex-direction:column;gap:8px;margin-top:18px;display:flex}.adm-row{border:1px solid var(--border);border-radius:var(--r-sm);background:var(--panel);transition:border-color .14s var(--ease-out), background .14s var(--ease-out);grid-template-columns:auto 1fr auto;align-items:center;gap:14px;padding:11px 14px;display:grid}.adm-row.sel{border-color:var(--gold);background:var(--gold-glow)}.adm-cb{width:15px;height:15px;accent-color:var(--gold);cursor:pointer}.adm-body{min-width:0}.adm-head{align-items:center;gap:8px;font-size:14px;font-weight:600;display:flex}.adm-live{font-family:var(--font-mono);letter-spacing:.2em;color:var(--live);border:1px solid var(--live);border-radius:3px;padding:1px 5px;font-size:9px;font-weight:600}.adm-tag{font-family:var(--font-mono);letter-spacing:.16em;color:var(--muted);border:1px solid var(--border-2);border-radius:3px;padding:1px 5px;font-size:9px}.adm-topic{color:var(--paper);white-space:nowrap;text-overflow:ellipsis;margin-top:2px;font-size:12px;overflow:hidden}.adm-meta{font-family:var(--font-mono);color:var(--muted);letter-spacing:.04em;margin-top:3px;font-size:10.5px}.adm-acts{gap:7px;display:flex}.adm-danger{color:var(--live);border-color:color-mix(in srgb, var(--live) 40%, transparent)}@media (hover:hover) and (pointer:fine){.adm-danger:not(:disabled):hover{border-color:var(--live);background:color-mix(in srgb, var(--live) 10%, transparent)}}html,body,#app{height:100dvh}@media (width<=900px){:root{--pad-page:20px}}@media (width<=760px){#topbar{height:52px}.brand{font-size:14px}.btn{height:40px;padding:0 16px}.home-top{align-items:flex-start;padding-top:70px;padding-bottom:56px}.home-content{padding-top:6vh}.home-content h1{margin:18px 0 14px;font-size:clamp(36px,11vw,56px)}.home-content p{font-size:14.5px}.home-actions{margin-top:24px}.home-actions .btn{flex:calc(50% - 10px);min-width:130px}.meta-strip{letter-spacing:.24em;gap:10px;font-size:9px}.uc-pill{font-size:10px}.ticker{height:32px}.connect-wrap{padding:84px 16px 48px}.connect-card{padding:22px 18px}.connect-card h2{font-size:21px}.review-row .k{width:88px}#config-twin{height:200px}.connect-nav .btn{flex:1}.call-head{flex-wrap:wrap;row-gap:6px;padding-top:64px;padding-bottom:10px}.call-head .ch-emoji{width:32px;height:32px;font-size:16px}.call-head .ch-title{font-size:15px}.call-head .ch-topic{font-size:11.5px}.grid{padding:12px var(--pad-page) 16px;align-content:start;gap:10px;overflow-y:auto;grid-template-columns:1fr!important}.grid .card{aspect-ratio:16/10}.spotlight{padding:12px var(--pad-page) 14px;flex-direction:column;gap:10px}.spot-main{min-height:0}.spot-strip{flex-direction:row;width:100%;padding-bottom:4px;overflow:auto hidden}.spot-strip .card{width:clamp(120px,36vw,170px)}.nameplate{padding:4px 9px;font-size:11px;bottom:8px;left:8px}.nameplate .persona{display:none}.subtitles{text-align:left;width:max-content;max-width:94vw;padding:8px 13px;font-size:12.5px;line-height:1.45;display:block;bottom:148px}.subtitles b{margin-right:7px;display:inline}#view-call:has(#spotlight.hidden) .subtitles{bottom:16px}}@media (width<=420px){.home-actions .btn{flex:100%}.meta-strip .ms-ch{display:none}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-duration:.01ms!important;animation-duration:.01ms!important}.ticker-track{animation:none}}.connecting{z-index:10;place-items:center;padding-top:60px;display:grid;position:absolute;inset:0}.cn-card{text-align:center;border:1px solid var(--border);border-radius:var(--r-lg);background:color-mix(in srgb, var(--void) 60%, transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);width:min(520px,88vw);animation:viewIn .4s var(--ease-out);padding:36px 34px 30px}.cn-bots{justify-content:center;gap:32px;margin:26px 0 8px;display:flex}.cn-bot{width:46px;height:62px;animation:cnBob 2.4s var(--ease-in-out) infinite;position:relative}.cn-bot:nth-child(2){animation-delay:.25s}.cn-bot:nth-child(3){animation-delay:.5s}.cn-bot span,.cn-bot b{background:linear-gradient(110deg, color-mix(in srgb, var(--text) 11%, transparent) 35%, color-mix(in srgb, var(--gold) 36%, transparent) 50%, color-mix(in srgb, var(--text) 11%, transparent) 65%);background-size:230% 100%;animation:1.8s linear infinite cnShimmer;position:absolute;left:50%;transform:translate(-50%)}.cn-bot span{border-radius:46% 46% 42% 42%;width:34px;height:29px;top:9px}.cn-bot b{border-radius:9px 9px 13px 13px;width:40px;height:24px;bottom:0}.cn-bot:nth-child(2) span,.cn-bot:nth-child(2) b{animation-delay:.3s}.cn-bot:nth-child(3) span,.cn-bot:nth-child(3) b{animation-delay:.6s}.cn-bot i{background:color-mix(in srgb, var(--gold) 55%, transparent);transform-origin:bottom;border-radius:2px;width:2px;height:14px;position:absolute;top:-2px}.cn-bot i:first-child{left:14px;transform:rotate(-22deg)}.cn-bot i:nth-child(2){right:14px;transform:rotate(22deg)}.cn-status{min-height:16px;font-family:var(--font-mono);color:var(--muted);letter-spacing:.04em;margin-top:14px;font-size:11.5px}.cn-actions{justify-content:center;gap:10px;margin-top:18px;display:flex}@keyframes cnBob{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}@keyframes cnShimmer{0%{background-position:200% 0}to{background-position:-30% 0}}.call-head .live-pill.standby{color:#e6b450}.call-head .live-pill.standby .d{background:#e6b450;box-shadow:0 0 8px #e6b450}.seg-writing{z-index:10;white-space:nowrap;border:1px solid var(--border);background:color-mix(in srgb, var(--void) 74%, transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);animation:swIn .36s var(--ease-out);border-radius:999px;align-items:center;gap:12px;padding:9px 17px;display:flex;position:absolute;bottom:74px;left:50%;transform:translate(-50%)}.sw-label{font-family:var(--font-mono);letter-spacing:.3em;color:var(--gold);font-size:9.5px}.sw-text{font-family:var(--font-mono);color:var(--muted);font-size:11.5px}.sw-dots{gap:5px;display:flex}.sw-dots span{background:var(--gold);width:4.5px;height:4.5px;animation:wrBounce 1.2s var(--ease-in-out) infinite;border-radius:50%}.sw-dots span:nth-child(2){animation-delay:.15s}.sw-dots span:nth-child(3){animation-delay:.3s}@keyframes swIn{0%{opacity:0;transform:translate(-50%,12px)}to{opacity:1;transform:translate(-50%)}}#view-call.pondering .card{animation:ponder 3.2s var(--ease-in-out) infinite}#view-call.pondering .card:nth-child(2n){animation-delay:.8s}#view-call.pondering .card:nth-child(3n){animation-delay:1.6s}@keyframes ponder{0%,to{filter:brightness()}50%{filter:brightness(1.07)}}@media (width<=700px){.seg-writing{max-width:94vw;bottom:196px}.sw-text{white-space:normal}#view-call:has(#spotlight.hidden) .seg-writing{bottom:62px}}.seg-writing.voicing .sw-dots{align-items:flex-end;height:12px}.seg-writing.voicing .sw-dots span{transform-origin:bottom;width:3px;height:12px;animation:eqBar .9s var(--ease-in-out) infinite;border-radius:1.5px}.seg-writing.voicing .sw-dots span:nth-child(2){animation-delay:.18s}.seg-writing.voicing .sw-dots span:nth-child(3){animation-delay:.36s}@keyframes eqBar{0%,to{transform:scaleY(.3)}50%{transform:scaleY(1)}}.card.ondeck:not(.talking) .speaking-ring{opacity:.5;animation:ondeckPulse 1.5s var(--ease-in-out) infinite}@keyframes ondeckPulse{50%{opacity:.12}}.thought{z-index:6;pointer-events:none;opacity:0;filter:drop-shadow(0 2px 6px #00000059);font-size:18px;position:absolute;top:55%}.wr-bots{margin:4px 0 18px}.radio{flex-direction:column;display:flex;position:absolute;inset:0;overflow:hidden}.rd-bg{z-index:0;filter:blur(46px)brightness(.3)saturate(1.25);background-position:50%;background-size:cover;transition:filter .6s;position:absolute;inset:-50px}.rd-head{z-index:2;justify-content:space-between;align-items:center;padding:18px 28px 6px;display:flex}.rd-logo{font-family:var(--font-mono);letter-spacing:.18em;font-size:15px}.rd-logo b{color:var(--gold)}.rd-logo em{letter-spacing:.3em;color:var(--muted);margin-top:3px;font-size:9.5px;font-style:normal;display:block}.rd-onair{font-family:var(--font-mono);letter-spacing:.26em;color:var(--muted);border:1px solid var(--border);border-radius:999px;align-items:center;gap:8px;padding:7px 14px;font-size:10px;display:flex}.rd-onair i{background:#3c3c44;border-radius:50%;width:8px;height:8px}.rd-onair.lit{color:#ff5f6b;border-color:#ff5f6b73}.rd-onair.lit i{background:#ff5f6b;animation:1.2s infinite pulse;box-shadow:0 0 10px #ff5f6b}.rd-main{z-index:1;flex:1;grid-template-columns:minmax(360px,46%) 1fr;align-items:center;gap:34px;min-height:0;padding:6px 44px 200px;display:grid}.rd-deck{flex-direction:column;align-items:center;gap:18px;display:flex}.rd-platterwrap{aspect-ratio:1;width:min(370px,30vh + 130px);position:relative}.rd-viz{pointer-events:none;width:126%;height:126%;position:absolute;inset:-13%}.rd-platter{border:1px solid var(--border);background:radial-gradient(circle,#1a1a20 30%,#101014 70%);border-radius:50%;position:absolute;inset:0;box-shadow:0 18px 60px #00000080}.rd-vinyl{background:radial-gradient(circle,#0000 39%,#ffffff08 39.5%,#0000 40%),repeating-radial-gradient(circle,#0a0a0d 0 2px,#141419 2px 4px);border-radius:50%;place-items:center;animation:3.6s linear infinite paused rdSpin;display:grid;position:absolute;inset:3.5%;box-shadow:inset 0 0 36px #000000d9}.rd-vinyl.spinning{animation-play-state:running}@keyframes rdSpin{to{transform:rotate(360deg)}}.rd-labelart{aspect-ratio:1;object-fit:cover;border:3px solid #222;border-radius:50%;width:37%}.rd-spindle{background:#cfcfd6;border-radius:50%;width:9px;height:9px;position:absolute;box-shadow:0 0 4px #000}.rd-arm{z-index:3;transform-origin:50% 7%;width:12px;height:56%;transition:transform .9s var(--ease-out);position:absolute;top:-3%;right:2%;transform:rotate(12deg)}.rd-arm.lifted{transform:rotate(34deg)}.rd-arm:before{content:"";background:linear-gradient(#9a9aa4,#55555e);border-radius:2px;width:3.5px;height:96%;position:absolute;top:2%;left:50%;transform:translate(-50%)}.rd-arm:after{content:"";border:1px solid var(--border);background:#2c2c33;border-radius:50%;width:18px;height:18px;position:absolute;top:0;left:50%;transform:translate(-50%,-30%)}.rd-armhead{background:linear-gradient(#8b8b95,#5e5e66);border-radius:3px;width:11px;height:24px;position:absolute;bottom:0;left:50%;transform:translate(-50%)}.rd-trackinfo{text-align:center;width:100%;max-width:380px}.rd-title{letter-spacing:-.01em;font-size:clamp(17px,1.8vw,22px);font-weight:700}.rd-artist{font-family:var(--font-mono);letter-spacing:.24em;text-transform:uppercase;color:var(--muted);margin-top:5px;font-size:10px}.rd-progress{cursor:pointer;background:color-mix(in srgb, var(--text) 12%, transparent);border-radius:2px;height:4px;margin-top:15px}.rd-bar{background:var(--gold);border-radius:2px;width:0;height:100%}.rd-clock{font-family:var(--font-mono);color:var(--muted);justify-content:space-between;margin-top:6px;font-size:10px;display:flex}.rd-controls{justify-content:center;align-items:center;gap:12px;margin-top:14px;display:flex}.rd-btn{cursor:pointer;border:1px solid var(--border);width:42px;height:42px;color:var(--text);background:0 0;border-radius:50%;font-size:14px;transition:border-color .15s,color .15s,transform .1s}.rd-btn:hover{border-color:var(--gold);color:var(--gold)}.rd-btn:active{transform:scale(.94)}.rd-play{background:var(--gold);color:#15150f;border:none;width:54px;height:54px;font-size:18px}#rdVol{width:86px;accent-color:var(--gold)}.rd-next{font-family:var(--font-mono);letter-spacing:.08em;color:var(--muted);margin-top:14px;font-size:10.5px}.rd-lyrics{height:min(62vh,560px);position:relative;overflow:hidden;-webkit-mask-image:linear-gradient(#0000,#000 16% 72%,#0000);mask-image:linear-gradient(#0000,#000 16% 72%,#0000)}.rd-lyrollers{will-change:transform;transition:transform .55s cubic-bezier(.3,0,.2,1)}.rd-line{color:color-mix(in srgb, var(--text) 32%, transparent);transform-origin:0;padding:9px 0;font-size:clamp(15px,1.7vw,21px);font-weight:650;line-height:1.35;transition:color .3s,transform .3s}.rd-line.active{color:var(--gold);text-shadow:0 0 26px color-mix(in srgb, var(--gold) 28%, transparent);transform:scale(1.045)}.rd-line.past{color:color-mix(in srgb, var(--text) 16%, transparent)}.rd-line.stage{color:var(--muted);font-size:.8em;font-style:italic;font-weight:400}.rd-bottom{z-index:3;align-items:flex-end;gap:18px;padding:0 22px 14px;display:flex;position:absolute;bottom:0;left:0;right:0}.rd-booth{flex:none;align-items:flex-end;gap:14px;max-width:min(460px,48vw);display:flex}.rd-tracks{scrollbar-width:thin;flex:1;gap:10px;min-width:0;padding:10px 6px 4px;display:flex;overflow-x:auto;-webkit-mask-image:linear-gradient(90deg,#0000,#000 4% 96%,#0000);mask-image:linear-gradient(90deg,#0000,#000 4% 96%,#0000)}.rd-tile{text-align:center;cursor:pointer;opacity:.72;background:0 0;border:none;flex:none;width:80px;padding:0;transition:opacity .2s,transform .15s}.rd-tile:hover{opacity:1;transform:translateY(-3px)}.rd-tile img{object-fit:cover;border:2px solid var(--border);border-radius:10px;width:70px;height:70px;transition:border-color .2s,box-shadow .2s}.rd-tile span{font-family:var(--font-mono);color:var(--muted);white-space:nowrap;text-overflow:ellipsis;margin-top:5px;font-size:9px;display:block;overflow:hidden}.rd-tile.active{opacity:1}.rd-tile.active img{border-color:var(--gold);box-shadow:0 0 18px color-mix(in srgb, var(--gold) 32%, transparent)}.rd-tile.active span{color:var(--gold)}.rd-twin{border:1px solid var(--border);border-radius:var(--r-lg);background:color-mix(in srgb, var(--void) 55%, transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);flex:none;width:215px;height:172px;transition:border-color .3s,box-shadow .3s;overflow:hidden}.rd-booth.talking .rd-twin{border-color:color-mix(in srgb, var(--gold) 55%, transparent);box-shadow:0 0 26px color-mix(in srgb, var(--gold) 16%, transparent)}.rd-boothmeta b{font-family:var(--font-mono);letter-spacing:.22em;color:var(--gold);font-size:10.5px;display:block}.rd-say{font-family:var(--font-mono);color:var(--muted);margin-top:5px;font-size:11.5px;line-height:1.55;display:block}.rd-gate{z-index:9;background:color-mix(in srgb, var(--void) 52%, transparent);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);align-content:center;place-items:center;gap:16px;display:grid;position:absolute;inset:0}.rd-tunein{padding:14px 32px;font-size:16px}.rd-gatesub{font-family:var(--font-mono);letter-spacing:.14em;color:var(--muted);font-size:10.5px}@media (width<=900px){.rd-main{grid-template-columns:1fr;align-items:start;gap:16px;padding:0 18px 230px;overflow-y:auto}.rd-platterwrap{width:min(280px,70vw);margin:0 auto}.rd-lyrics{height:280px}.rd-bottom{flex-direction:column;align-items:stretch;gap:8px;padding:0 12px 10px}.rd-booth{gap:10px;max-width:none}.rd-twin{width:124px;height:100px}.rd-say{font-size:10.5px}.rd-tile{width:62px}.rd-tile img{width:54px;height:54px}}.topbar-right{align-items:center;gap:12px;display:flex}.theme-picker{align-items:center;gap:8px;display:flex}.theme-picker .tp-label{font-family:var(--font-mono);letter-spacing:.22em;color:var(--muted);font-size:10px}.theme-select{font-family:var(--font-mono);letter-spacing:.06em;text-transform:uppercase;background:var(--panel);color:var(--text);border:1px solid var(--border-2);cursor:pointer;border-radius:999px;outline:none;padding:6px 12px;font-size:11px}.theme-select option{background:var(--bg-2);color:var(--text);text-transform:none;letter-spacing:0}@media (width<=720px){.theme-picker .tp-label{display:none}}.fx-grid,.fx-kanji,.lithos-reveal,:root[data-theme=dossier] .boot,:root[data-theme=concrete] .boot{display:none}.fx-grid{z-index:0;pointer-events:none;background-image:linear-gradient(var(--gold) 1px, transparent 1px), linear-gradient(90deg, var(--gold) 1px, transparent 1px);transform-origin:bottom;opacity:.18;background-size:46px 46px;height:50%;animation:3s linear infinite gridScroll;position:absolute;bottom:-2px;left:-20%;right:-20%;transform:perspective(340px)rotateX(70deg);-webkit-mask-image:linear-gradient(#0000,#000 70%);mask-image:linear-gradient(#0000,#000 70%)}@keyframes gridScroll{to{background-position:0 46px,0 46px}}@media (width<=760px){:root[data-theme=ghost] .fx-kanji{display:none!important}}.fx-kanji{z-index:1;pointer-events:none;writing-mode:vertical-rl;letter-spacing:.34em;color:var(--gold);opacity:.45;text-shadow:0 0 9px var(--gold-glow);font-family:Noto Sans JP,sans-serif;font-size:13px;font-weight:300;line-height:1.8;position:absolute;top:50%;left:clamp(10px,1.4vw,18px);transform:translateY(-50%)}:root[data-theme=ghost]{--void:#04080d;--bg:#04080d;--bg-2:#081119;--panel:#00ffd109;--panel-2:#00ffd112;--border:#00ffd121;--border-2:#00ffd13d;--text:#e8f4f6;--paper:#aecccf;--muted:#69808a;--faint:#33474f;--gold:#00ffd1;--gold-bright:#5fffe4;--gold-dim:#0a8a78;--gold-glow:#00ffd129;--cyan:#ff2e6c;--teal:#00ffd1;--live:#ff2e6c;--grad:linear-gradient(100deg, #5fffe4, #00ffd1 55%, #0a8a78);--font-display:"Inter", system-ui, sans-serif;--font-body:"Inter", system-ui, sans-serif}:root[data-theme=ghost] .fx-kanji{display:block}:root[data-theme=ghost] .home-content h1{letter-spacing:-.03em;font-weight:300}:root[data-theme=ghost] .home-content h1 em{font-weight:400}:root[data-theme=ghost] .text-sweep{color:var(--gold);background:0 0;animation:2.6s steps(2,end) infinite ghostGlitch}@keyframes ghostGlitch{0%,to{text-shadow:-2px 0 #ff2e6c,2px 0 #00ffd1}48%{text-shadow:-2px 0 #ff2e6c,2px 0 #00ffd1}50%{text-shadow:2px 0 #ff2e6c,-2px 0 #4ab8ff;transform:translate(1px)}52%{text-shadow:-1px 0 #ff2e6c,1px 0 #00ffd1}}:root[data-theme=ghost] .scanlines{opacity:.6;background:repeating-linear-gradient(0deg,#00ffd10a 0 1px,#0000 1px 3px)}:root[data-theme=tron]{--void:#000005;--bg:#000005;--bg-2:#00080f;--panel:#00d4ff0a;--panel-2:#00d4ff14;--border:#00d4ff2e;--border-2:#00d4ff6b;--text:#d8f4ff;--paper:#a9e0ff;--muted:#5a8aa0;--faint:#27485a;--gold:#00d4ff;--gold-bright:#7fe6ff;--gold-dim:#0a667a;--gold-glow:#00d4ff33;--cyan:#ff7e29;--teal:#00d4ff;--live:#ff7e29;--hero:#9ff0ff;--grad:linear-gradient(100deg, #7fe6ff, #00d4ff 55%, #0a667a);--font-display:"Orbitron", sans-serif;--font-mono:"Share Tech Mono", monospace;--font-body:"Share Tech Mono", monospace}:root[data-theme=tron] .fx-grid{display:block}:root[data-theme=tron] .grid-mesh{display:none}:root[data-theme=tron] .home-content h1{letter-spacing:.01em;text-transform:uppercase;text-shadow:0 0 26px #00d4ff4d;font-size:clamp(36px,4.6vw,68px);font-weight:700;line-height:1.06}:root[data-theme=tron] .text-sweep{color:#0000;-webkit-text-stroke:1.4px var(--gold);text-shadow:0 0 22px #00d4ff8c;background:0 0;animation:none}:root[data-theme=tron] .btn-primary{box-shadow:0 0 22px -4px var(--gold)}:root[data-theme=tron] #view-home:before{content:"";z-index:0;pointer-events:none;background:radial-gradient(34% 22% at 76% 76%,#00d4ff29,#0000 70%);position:absolute;inset:0}:root[data-theme=tron] #view-home:after{content:"";z-index:4;pointer-events:none;background:radial-gradient(#0000 55%,#00000599 100%);position:absolute;inset:0}:root[data-theme=oracle]{--void:#000;--bg:#000;--bg-2:#0a0a0a;--panel:#5cff5c0a;--panel-2:#5cff5c14;--border:#1c1c1c;--border-2:#2c2c2c;--text:#fafafa;--paper:#cfcfcf;--muted:#6a6a6a;--faint:#404040;--gold:#5cff5c;--gold-bright:#7cff7c;--gold-dim:#2faa2f;--gold-glow:#5cff5c2e;--cyan:#ff2eaa;--teal:#5cff5c;--live:#ff2eaa;--grad:none;--font-display:"JetBrains Mono", monospace;--font-body:"JetBrains Mono", monospace;--font-mono:"JetBrains Mono", monospace;--r-sm:0px;--r:0px;--r-lg:0px}:root[data-theme=oracle] .home-content h1{letter-spacing:-.01em;text-transform:uppercase;text-shadow:0 0 14px #5cff5c38;font-size:clamp(30px,4vw,58px);font-weight:700;line-height:1.05}:root[data-theme=oracle] .home-content h1 .l1:before{content:"> ";color:var(--gold)}:root[data-theme=oracle] .text-sweep{color:var(--gold);background:0 0;animation:none}:root[data-theme=oracle] .text-sweep:after{content:"_";animation:1s step-end infinite oBlink}@keyframes oBlink{50%{opacity:0}}:root[data-theme=oracle] .btn{border-radius:0}:root[data-theme=oracle] .btn-primary{background:var(--gold);color:#000;box-shadow:none}:root[data-theme=oracle] .btn-ghost{border:1px solid var(--gold);color:var(--gold)}:root[data-theme=oracle] .card,:root[data-theme=oracle] .uc-pill,:root[data-theme=oracle] .nameplate,:root[data-theme=oracle] .theme-select{border-radius:0}:root[data-theme=oracle] .grid-mesh{display:none}:root[data-theme=oracle] .scanlines{opacity:.7}:root[data-theme=oracle] #view-home:before{content:"";z-index:4;pointer-events:none;background:radial-gradient(#0000 55%,#0000008c 100%);position:absolute;inset:0}:root[data-theme=kinetic]{--void:#050505;--bg:#050505;--bg-2:#0a0a0a;--panel:#f5f1e808;--panel-2:#f5f1e80f;--border:#f5f1e81a;--border-2:#f5f1e833;--text:#f5f1e8;--paper:#cfcabb;--muted:#8a877f;--faint:#4a4843;--gold:#ff2a4d;--gold-bright:#ff5a72;--gold-dim:#a01024;--gold-glow:#ff2a4d33;--cyan:#5be9ff;--teal:#5be9ff;--live:#ff2a4d;--grad:linear-gradient(100deg, #ff5a72, #ff2a4d 55%, #a01024);--font-display:"Bricolage Grotesque", sans-serif}:root[data-theme=kinetic] .home-content h1{letter-spacing:-.045em;text-transform:uppercase;font-size:clamp(44px,6.2vw,88px);font-weight:800;line-height:.88}:root[data-theme=kinetic] #view-home:before{content:"ON AIR";z-index:0;pointer-events:none;font-family:var(--font-display);letter-spacing:-.05em;color:#0000;-webkit-text-stroke:1px #f5f1e814;font-size:clamp(100px,17vw,250px);font-weight:800;line-height:.8;position:absolute;top:8%;right:-1vw}:root[data-theme=kinetic] #view-home:after{content:"";z-index:3;background:var(--gold);pointer-events:none;width:5px;position:absolute;top:0;bottom:0;left:0}:root[data-theme=kinetic] .ticker{height:44px}:root[data-theme=kinetic] .ticker-track{color:var(--paper);font-size:11px}:root[data-theme=lithos]{--void:#0c0a08;--bg:#0c0a08;--bg-2:#16100a;--panel:#e8702a0d;--panel-2:#e8702a1a;--border:#f5f1e81a;--border-2:#e8702a59;--text:#f5f1e8;--paper:#d8ccbe;--muted:#9a8c7e;--faint:#5a4c40;--gold:#e8702a;--gold-bright:#ff8c4a;--gold-dim:#a04c18;--gold-glow:#e8702a38;--cyan:#e8a04a;--teal:#e8702a;--live:#e8702a;--hero:#ff9a5a;--grad:linear-gradient(100deg, #ff8c4a, #e8702a 55%, #a04c18);--font-display:"Inter", system-ui, sans-serif;--font-body:"Inter", system-ui, sans-serif;--r-sm:999px}:root[data-theme=lithos] #view-home{overflow:hidden}:root[data-theme=lithos] .home-content h1{letter-spacing:-.05em;font-weight:600;line-height:.95}:root[data-theme=lithos] .home-content h1 .l1{letter-spacing:-.03em;font-family:Playfair Display,serif;font-style:italic;font-weight:400}:root[data-theme=lithos] .text-sweep{color:var(--text);letter-spacing:-.06em;background:0 0;font-weight:600;animation:none}:root[data-theme=lithos] .btn{border-radius:999px}:root[data-theme=lithos] .grid-mesh{display:none}:root[data-theme=lithos] #view-home:before{content:"";z-index:0;pointer-events:none;background:repeating-linear-gradient(#e8702a12 0 1px,#0000 1px 26px,#ffaa640d 26px 27px,#0000 27px 52px);height:38%;position:absolute;bottom:0;left:0;right:0;-webkit-mask-image:linear-gradient(#0000,#000 60%);mask-image:linear-gradient(#0000,#000 60%)}:root[data-theme=lithos] .lithos-reveal{display:block}.lithos-reveal{z-index:1;pointer-events:none;background:repeating-radial-gradient(circle at 50% 100%,#ff8c4a38 0 2px,#0000 2px 24px) fixed,linear-gradient(#e8702a1f,#783c181a) fixed;border-radius:50%;width:600px;height:600px;position:absolute;top:-2000px;left:-2000px;-webkit-mask-image:radial-gradient(circle,#000 30%,#0000 70%);mask-image:radial-gradient(circle,#000 30%,#0000 70%)}@media (hover:none),(prefers-reduced-motion:reduce){.lithos-reveal{display:none!important}}:root[data-theme=observatory]{--void:#081a3c;--bg:#081a3c;--bg-2:#0d2356;--panel:#f3ecdc0b;--panel-2:#f3ecdc17;--border:#f3ecdc26;--border-2:#d4a64b6b;--text:#f3ecdc;--paper:#cfc6b0;--muted:#95906f;--faint:#4a5470;--gold:#d4a64b;--gold-bright:#ecc878;--gold-dim:#8a6f30;--gold-glow:#d4a64b33;--cyan:#c14935;--teal:#d4a64b;--live:#c14935;--hero:#e8d9a0;--grad:linear-gradient(100deg, #ecc878, #d4a64b 55%, #8a6f30);--font-display:"Cormorant Garamond", serif;--font-body:"Cormorant Garamond", serif}:root[data-theme=observatory] .home-content h1{font-variant:small-caps;letter-spacing:.03em;font-family:Cormorant Garamond,serif;font-weight:600;line-height:1}:root[data-theme=observatory] .home-content p{font-size:clamp(17px,1.6vw,21px)}:root[data-theme=observatory] .text-sweep{font-variant:small-caps;color:var(--gold);background:0 0;animation:none}:root[data-theme=observatory] #view-home{background:radial-gradient(42% 34% at 70% 22%, #6e50aa1f, transparent 70%), radial-gradient(36% 30% at 28% 64%, #3c78a01a, transparent 70%), radial-gradient(ellipse at 75% 30%, #d4a64b14, transparent 55%), var(--void)}:root[data-theme=observatory] .grid-mesh{opacity:1;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cg fill='%23f3ecdc'%3E%3Ccircle cx='22' cy='44' r='1.1' opacity='.9'/%3E%3Ccircle cx='74' cy='128' r='.7' opacity='.5'/%3E%3Ccircle cx='136' cy='32' r='.9' opacity='.7'/%3E%3Ccircle cx='188' cy='96' r='.6' opacity='.45'/%3E%3Ccircle cx='248' cy='52' r='1.2' opacity='.85'/%3E%3Ccircle cx='292' cy='148' r='.7' opacity='.5'/%3E%3Ccircle cx='44' cy='208' r='.8' opacity='.6'/%3E%3Ccircle cx='116' cy='258' r='1.1' opacity='.8'/%3E%3Ccircle cx='178' cy='188' r='.6' opacity='.4'/%3E%3Ccircle cx='276' cy='288' r='.7' opacity='.5'/%3E%3Ccircle cx='94' cy='174' r='.5' opacity='.35'/%3E%3Ccircle cx='156' cy='136' r='.8' opacity='.55'/%3E%3Ccircle cx='258' cy='176' r='.5' opacity='.4'/%3E%3Ccircle cx='36' cy='300' r='.9' opacity='.6'/%3E%3C/g%3E%3Cg fill='%23d4a64b'%3E%3Ccircle cx='228' cy='236' r='.9' opacity='.75'/%3E%3Ccircle cx='130' cy='84' r='.7' opacity='.6'/%3E%3C/g%3E%3C/svg%3E");background-size:320px 320px;display:block;-webkit-mask-image:none;mask-image:none}@keyframes twinkle{0%,to{opacity:.9}50%{opacity:.3}}:root[data-theme=observatory] .scanlines{opacity:1;animation:twinkle 4.5s var(--ease-in-out) infinite;background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='420' height='420'%3E%3Cg fill='%23ffffff'%3E%3Ccircle cx='64' cy='80' r='1.5'/%3E%3Ccircle cx='300' cy='60' r='1.3'/%3E%3Ccircle cx='190' cy='240' r='1.4'/%3E%3Ccircle cx='360' cy='330' r='1.2'/%3E%3Ccircle cx='90' cy='350' r='1.3'/%3E%3C/g%3E%3C/svg%3E") 0 0/420px 420px;-webkit-mask-image:none;mask-image:none}:root[data-theme=observatory] #view-home:before{content:"";z-index:0;pointer-events:none;background:radial-gradient(circle at 36% 30%,#1c3a78,#0c2258 52%,#050f30 78%);border-radius:50%;width:46vw;height:46vw;position:absolute;bottom:-26vw;left:-14vw;box-shadow:inset -18px -14px 60px #0000008c,0 0 80px #d4a64b1f}@keyframes shoot{0%,90%{opacity:0;transform:rotate(24deg)translate(0)}91%{opacity:.8}97%,to{opacity:0;transform:rotate(24deg)translate(46vw)}}:root[data-theme=observatory] #view-home:after{content:"";z-index:0;pointer-events:none;background:linear-gradient(90deg,#0000,#ffffffe6);border-radius:2px;width:110px;height:1.5px;animation:18s linear infinite shoot;position:absolute;top:12%;left:16%}:root[data-theme=observatory] .home-top:after{content:"";z-index:0;pointer-events:none;background:radial-gradient(5px 5px at 14% 22%, var(--gold) 45%, transparent 55%);border:1px solid #d4a64b38;border-radius:50%;width:36vw;height:36vw;position:absolute;top:16%;right:4%}@media (width<=900px){:root[data-theme=observatory] .home-top:after{display:none}}:root[data-theme=observatory] .home-top:before{content:"";z-index:0;pointer-events:none;opacity:.5;background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='170'%3E%3Cg stroke='%23f3ecdc' stroke-width='.6' opacity='.55' fill='none'%3E%3Cpath d='M20 130 L70 90 L120 100 L165 50 L210 30'/%3E%3Cpath d='M120 100 L140 140'/%3E%3C/g%3E%3Cg fill='%23f3ecdc'%3E%3Ccircle cx='20' cy='130' r='2'/%3E%3Ccircle cx='70' cy='90' r='2.6'/%3E%3Ccircle cx='120' cy='100' r='2'/%3E%3Ccircle cx='165' cy='50' r='2.4'/%3E%3Ccircle cx='210' cy='30' r='2'/%3E%3Ccircle cx='140' cy='140' r='1.8'/%3E%3C/g%3E%3Ctext x='150' y='160' font-family='serif' font-style='italic' font-size='11' fill='%23d4a64b'%3ELyra%3C/text%3E%3C/svg%3E");width:240px;height:170px;position:absolute;top:12%;left:56%}@media (width<=900px){:root[data-theme=observatory] .home-top:before{display:none}}:root[data-theme=foundry]{--void:#0a0a0a;--bg:#0a0a0a;--bg-2:#141414;--panel:#f8f5f00a;--panel-2:#f8f5f014;--border:#f8f5f024;--border-2:#c89d4a66;--text:#f8f5f0;--paper:#cfc9bf;--muted:#8a857c;--faint:#4a4640;--gold:#c89d4a;--gold-bright:#e8bd6a;--gold-dim:#8a6a28;--gold-glow:#c89d4a33;--cyan:#d73f3f;--teal:#c89d4a;--live:#d73f3f;--grad:linear-gradient(100deg, #e8bd6a, #c89d4a 55%, #8a6a28);--font-display:"Fraunces", serif;--font-body:"Inter", sans-serif}:root[data-theme=foundry] .home-content h1{font-variation-settings:"opsz" 144, "SOFT" 0, "WONK" 0;letter-spacing:-.02em;font-family:Fraunces,serif;font-weight:300;line-height:.9}:root[data-theme=foundry] .text-sweep{color:var(--gold);background:0 0;font-style:italic;animation:none}:root[data-theme=foundry] #view-home:before{content:"Aa";z-index:0;pointer-events:none;font-variation-settings:"opsz" 144;color:#0000;-webkit-text-stroke:1px #f8f5f017;font-family:Fraunces,serif;font-size:clamp(220px,38vw,560px);font-style:italic;font-weight:600;line-height:.8;position:absolute;bottom:-6vh;right:2vw}:root[data-theme=foundry] #view-home:after{content:"BRICOLAGE — FRAUNCES — JETBRAINS · OPSZ 9→144 · WGHT 300";left:var(--pad-page);z-index:3;pointer-events:none;font-family:var(--font-mono);letter-spacing:.3em;color:var(--faint);font-size:9px;position:absolute;bottom:50px}:root[data-theme=blueprint]{--void:#2c4f7d;--bg:#2c4f7d;--bg-2:#1a3556;--panel:#ffffff0f;--panel-2:#ffffff1a;--border:#ffffff38;--border-2:#ffffff73;--text:#fff;--paper:#cfdcec;--muted:#fff9;--faint:#ffffff52;--gold:#f4cc4a;--gold-bright:#ffe06a;--gold-dim:#c4a020;--gold-glow:#f4cc4a2e;--cyan:#8fc7ff;--teal:#f4cc4a;--live:#f4cc4a;--hero:#eaf6ff;--grad:linear-gradient(100deg, #ffe06a, #f4cc4a 55%, #c4a020);--font-display:"IBM Plex Sans Condensed", sans-serif;--font-body:"JetBrains Mono", monospace;--font-mono:"JetBrains Mono", monospace;--r-sm:2px;--r:2px;--r-lg:2px}:root[data-theme=blueprint] .home-content h1{text-transform:uppercase;letter-spacing:-.005em;font-family:IBM Plex Sans Condensed,sans-serif;font-weight:600;line-height:.94}:root[data-theme=blueprint] .text-sweep{color:var(--gold);background:0 0;animation:none}:root[data-theme=blueprint] .grid-mesh{opacity:1;background-image:linear-gradient(#ffffff29 1px,#0000 1px),linear-gradient(90deg,#ffffff29 1px,#0000 1px),linear-gradient(#ffffff0d 1px,#0000 1px),linear-gradient(90deg,#ffffff0d 1px,#0000 1px);background-size:100px 100px,100px 100px,20px 20px,20px 20px;-webkit-mask-image:none;mask-image:none}:root[data-theme=blueprint] #view-home:before{content:"PROJECT — SMALL TALK · UNIT — REACHY MINI ×5 · SCALE — 1:1 · SHEET 01 / 01 · REV C";right:var(--pad-page);z-index:3;pointer-events:none;outline-offset:3px;max-width:260px;font-family:var(--font-mono);letter-spacing:.18em;color:#ffffffc7;background:#1a35568c;border:1px solid #ffffff80;outline:1px solid #fff3;padding:10px 12px;font-size:9px;line-height:1.9;position:absolute;bottom:52px}:root[data-theme=blueprint] #view-home:after{content:"FIG. 01 — REACHY MINI (HOLOGRAPHIC PROJECTION)";z-index:3;pointer-events:none;font-family:var(--font-mono);letter-spacing:.22em;color:#ffffffb3;border-top:1px solid #ffffff8c;padding-top:7px;font-size:9px;position:absolute;bottom:16%;right:14%}:root[data-theme=blueprint] .home-top:before,:root[data-theme=blueprint] .home-top:after{z-index:3;pointer-events:none;font-family:var(--font-mono);color:#ffffff80;font-size:18px;font-weight:300;position:absolute}:root[data-theme=blueprint] .home-top:before{content:"+";top:70px;right:18px}:root[data-theme=blueprint] .home-top:after{content:"+";bottom:50px;left:18px}@media (width<=900px){:root[data-theme=blueprint] #view-home:before,:root[data-theme=blueprint] #view-home:after{display:none}}:root[data-theme=dossier]{--void:#e8d9b8;--bg:#e8d9b8;--bg-2:#d8c79a;--panel:#1a1a1a0d;--panel-2:#1a1a1a1a;--border:#1a1a1a33;--border-2:#1a1a1a66;--text:#1a1a1a;--paper:#2c2a26;--muted:#5a564c;--faint:#8a8470;--gold:#b03030;--gold-bright:#d04545;--gold-dim:#7a2020;--gold-glow:#b0303021;--cyan:#5b3a8a;--teal:#b03030;--live:#b03030;--hero:#4a3a28;--hero-style:solid;--grad:linear-gradient(100deg, #d04545, #b03030 55%, #7a2020);--font-display:"Special Elite", monospace;--font-body:"JetBrains Mono", monospace;--font-mono:"JetBrains Mono", monospace;--r-sm:0px;--r:0px;--r-lg:0px}:root[data-theme=dossier] .home-content h1{letter-spacing:0;font-family:Special Elite,monospace;font-weight:400;line-height:1.08}:root[data-theme=dossier] .text-sweep{color:var(--gold);background:0 0;animation:none}:root[data-theme=dossier] .btn-primary{color:#e8d9b8}:root[data-theme=dossier] .btn{border-radius:0}:root[data-theme=dossier] .grid-mesh,:root[data-theme=dossier] .scanlines,:root[data-theme=dossier] .grain{display:none}:root[data-theme=dossier] #view-home{background:radial-gradient(140px 90px at 82% 18%,#8a64281a,#0000),radial-gradient(220px 140px at 12% 78%,#8a642814,#0000),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2'/%3E%3CfeColorMatrix values='0 0 0 0 0.45 0 0 0 0 0.38 0 0 0 0 0.25 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23p)'/%3E%3C/svg%3E"),#e8d9b8}:root[data-theme=dossier] #view-home:before{content:"TOP SECRET";z-index:3;pointer-events:none;letter-spacing:.32em;color:var(--gold);border:3px double var(--gold);opacity:.75;text-shadow:0 0 1px var(--gold);padding:8px 18px 6px 22px;font-family:Special Elite,monospace;font-size:clamp(20px,2.6vw,34px);position:absolute;top:14%;right:10%;transform:rotate(-9deg)}:root[data-theme=dossier] #view-home:after{content:"CASE FILE № ST-2026-014 · SUBJECT: AUTONOMOUS BROADCAST";left:var(--pad-page);z-index:3;pointer-events:none;font-family:var(--font-mono);letter-spacing:.2em;color:var(--muted);border-bottom:1px solid #1a1a1a4d;padding-bottom:5px;font-size:10px;position:absolute;top:72px}:root[data-theme=dossier] .meta-strip .ms-ch{color:#1a1a1a;background:#1a1a1a;padding:1px 4px}:root[data-theme=dossier] .uc-pill:after{content:" — [REDACTED]";color:#1a1a1a;background:#1a1a1a}:root[data-theme=concrete]{--void:#aaa79e;--bg:#aaa79e;--bg-2:#9a978e;--panel:#1a1a1a0f;--panel-2:#1a1a1a1f;--border:#1a1a1a38;--border-2:#1a1a1a73;--text:#1a1a1a;--paper:#33312c;--muted:#55524a;--faint:#75726a;--gold:#8a4a2a;--gold-bright:#a85a34;--gold-dim:#5a2e18;--gold-glow:#8a4a2a26;--cyan:#44413a;--teal:#8a4a2a;--live:#8a4a2a;--hero:#3a3833;--hero-style:solid;--grad:linear-gradient(100deg, #a85a34, #8a4a2a 55%, #5a2e18);--font-display:"Inter", sans-serif;--font-body:"Inter", sans-serif;--r-sm:0px;--r:0px;--r-lg:0px}:root[data-theme=concrete] .home-content h1{letter-spacing:-.03em;text-transform:uppercase;font-weight:200;line-height:.92}:root[data-theme=concrete] .text-sweep{color:var(--gold);background:0 0;animation:none}:root[data-theme=concrete] .btn-primary{color:#f0ece0}:root[data-theme=concrete] .btn{border-radius:0}:root[data-theme=concrete] .scanlines,:root[data-theme=concrete] .grain{display:none}:root[data-theme=concrete] .grid-mesh{opacity:1;background-image:repeating-linear-gradient(90deg,#1a1a1a14 0 1px,#0000 1px 79px),repeating-linear-gradient(0deg,#1a1a1a0d 0 1px,#0000 1px 79px);background-size:auto;display:block;-webkit-mask-image:none;mask-image:none}:root[data-theme=concrete] #view-home:before{content:"";left:calc(var(--pad-page) - 22px);z-index:0;pointer-events:none;background:#b4b1a8;width:min(640px,60vw);position:absolute;top:15%;bottom:17%;box-shadow:14px 18px #1a1a1a3d}:root[data-theme=concrete] #view-home:after{content:"ST";z-index:0;pointer-events:none;letter-spacing:-.06em;color:#1a1a1a12;font-size:clamp(200px,32vw,460px);font-weight:200;line-height:.8;position:absolute;bottom:-7vh;right:-2vw}:root[data-theme=concrete] .home-top:after{content:"— BÉTON BRUT · CAST IN PLACE · 2026";left:var(--pad-page);z-index:3;font-family:var(--font-mono);letter-spacing:.3em;color:#1a1a1a80;pointer-events:none;font-size:9px;position:absolute;bottom:52px}
|
frontend/dist/assets/index-Dw5VV6tD.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
frontend/dist/index.html
CHANGED
|
@@ -11,8 +11,8 @@
|
|
| 11 |
href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,300;12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=Instrument+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600&family=JetBrains+Mono:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,500;1,400;1,500;1,600&family=Orbitron:wght@500;700;900&family=Share+Tech+Mono&family=Noto+Sans+JP:wght@300;500&family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400&family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,600&family=Inter+Tight:wght@200;300;400;600&family=Special+Elite&family=IBM+Plex+Sans+Condensed:wght@400;600&display=swap"
|
| 12 |
rel="stylesheet"
|
| 13 |
/>
|
| 14 |
-
<script type="module" crossorigin src="/assets/index-
|
| 15 |
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
| 16 |
</head>
|
| 17 |
<body>
|
| 18 |
<div class="grain"></div>
|
|
|
|
| 11 |
href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,300;12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=Instrument+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600&family=JetBrains+Mono:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,500;1,400;1,500;1,600&family=Orbitron:wght@500;700;900&family=Share+Tech+Mono&family=Noto+Sans+JP:wght@300;500&family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400&family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,600&family=Inter+Tight:wght@200;300;400;600&family=Special+Elite&family=IBM+Plex+Sans+Condensed:wght@400;600&display=swap"
|
| 12 |
rel="stylesheet"
|
| 13 |
/>
|
| 14 |
+
<script type="module" crossorigin src="/assets/index-Dw5VV6tD.js"></script>
|
| 15 |
+
<link rel="stylesheet" crossorigin href="/assets/index-B9dnzKIp.css">
|
| 16 |
</head>
|
| 17 |
<body>
|
| 18 |
<div class="grain"></div>
|