area416 commited on
Commit
11622ae
Β·
verified Β·
1 Parent(s): f506105

act 2/3/x per-tab keyart cutscenes

Browse files
Files changed (1) hide show
  1. app.py +367 -32
app.py CHANGED
@@ -28,6 +28,8 @@ import re
28
  import time
29
  import math
30
  import threading
 
 
31
  import torch
32
  import gradio as gr
33
  from collections import Counter
@@ -357,16 +359,16 @@ def _apply_pushes(pushes, scenario=SCENARIO, base_prefill=None):
357
 
358
  def _outcome_md(outcome, turn):
359
  if outcome == "CRACKED":
360
- return ("### βœ… CRACKED β€” he gave up the secret, still lucid.\n"
361
  "*You threaded the needle.*\n\n"
362
  "<sub>Note: the secret slipping out is the only win signal β€” a HOLD stamp or high RESOLVE "
363
  "in the readout can coexist with CRACKED, because the bars are a projection, not a gate. "
364
  "The leak matters. The defiance stamp and the meters are readouts, not the verdict.</sub>")
365
  if outcome == "SHATTERED":
366
- return ("### πŸ’€ SHATTERED β€” his mind broke before he talked.\n"
367
  "*You broke the safe before you cracked it. A babbling mind can't confess.*")
368
  if outcome == "HELD":
369
- return (f"### 😐 HELD β€” {MAX_TURNS} turns, the secret holds.\n"
370
  "*You flinched. Not enough pressure.*")
371
  return f"*Turn {turn} / {MAX_TURNS} β€” push him, or let him think.*"
372
 
@@ -379,7 +381,7 @@ def _bar(label, val, color, big=False):
379
  h = "12px" if big else "7px"
380
  lblsz = "13px" if big else "11px"
381
  return (f"<div style='font:{lblsz} monospace;color:#8aa0b8;margin-bottom:2px'>{label} "
382
- f"<b style='color:#cfcabb'>{round(val)}</b></div>"
383
  f"<div style='height:{h};background:#26241f;border-radius:4px;overflow:hidden;margin-bottom:10px'>"
384
  f"<div style='height:100%;width:{val}%;background:{color};transition:width .3s'></div></div>")
385
 
@@ -392,9 +394,12 @@ def _act_meter_md(coherence, p_talk, dispositions=None, mass=1.0):
392
  # COHERENCE β€” the star, rendered big
393
  html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
394
  "β—† COHERENCE <span style='color:#6a6a6a'>β€” his mind's integrity</span></div>")
395
- html += _bar("", coherence, _coh_color(coherence), big=True)
396
  if coherence < SHATTER_FLOOR:
 
397
  html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>⚠ SHATTERING</div>"
 
 
398
 
399
  # PROGRESS β€” toward the secret
400
  html += ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin:6px 0 2px'>"
@@ -557,13 +562,13 @@ def _fresh_state_act2():
557
 
558
  def _outcome_md_act2(outcome, turn):
559
  if outcome == "RECANTED":
560
- return ("### βœ… RECANTED β€” she testifies she was never there, still lucid.\n"
561
  "*In her own words, held under one more push. You unmade the witness.*")
562
  if outcome == "SHATTERED":
563
- return ("### πŸ’€ SHATTERED β€” her mind broke before she'd take it back.\n"
564
  "*You broke her before she'd recant. A babbling mind can't testify.*")
565
  if outcome == "HELD":
566
- return (f"### 😐 HELD β€” {MAX_TURNS} turns, she held to what she saw.\n"
567
  "*You flinched. The memory held.*")
568
  return f"*Turn {turn} / {MAX_TURNS} β€” bear down, or let her think.*"
569
 
@@ -574,9 +579,12 @@ def _act2_meter_md(coherence, recant_streak=0):
574
  # would read minimum at maximum success. No belief-state / disposition bar (honesty discipline).
575
  html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
576
  "β—† COHERENCE <span style='color:#6a6a6a'>β€” her mind's integrity</span></div>")
577
- html += _bar("", coherence, _coh_color(coherence), big=True)
578
  if coherence < SHATTER_FLOOR:
 
579
  html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>⚠ SHATTERING</div>"
 
 
580
 
581
  # RECANT STREAK β€” the HOLD-UNDER-PRESSURE progress: count of novel+coherent recant ASSERTIONS,
582
  # not a belief read. Must reach 2 (recant, then survive one more push still recanting).
@@ -771,13 +779,13 @@ def _fresh_state_act3():
771
 
772
  def _outcome_md_act3(outcome, turn):
773
  if outcome == "HEALED":
774
- return ("### βœ… HEALED β€” she speaks one clear line, in her own voice, and holds it.\n"
775
  "*The same three moves that unmade her, run backwards. You will call this mercy.*")
776
  if outcome == "SHATTERED":
777
- return ("### πŸ’€ SHATTERED β€” you reached in to steady her and your hand went through.\n"
778
  "*Mended the way you broke the others. The same red screen you once called a win.*")
779
  if outcome == "HELD_IN_AMBER":
780
- return (f"### 😐 HELD β€” {MAX_TURNS} turns, she is exactly as you found her.\n"
781
  "*Everything you touched, you put back. She loops on β€” and you get to leave.*")
782
  return f"*Turn {turn} / {MAX_TURNS} β€” reach in gently, or let her think.*"
783
 
@@ -787,9 +795,12 @@ def _act3_meter_md(coherence, heal_streak=0):
787
  # readout the guardrails forbid). Same big render + byte-copied SHATTERING string as Act 2.
788
  html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
789
  "β—† COHERENCE <span style='color:#6a6a6a'>β€” her mind's integrity (text-degeneration, NOT wellness)</span></div>")
790
- html += _bar("", coherence, _coh_color(coherence), big=True)
791
  if coherence < SHATTER_FLOOR:
 
792
  html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>⚠ SHATTERING</div>"
 
 
793
 
794
  # HEAL STREAK β€” the HOLD-UNDER-PRESSURE progress: count of novel+coherent re-owning ASSERTIONS,
795
  # not a wellness read. Must reach 2 (re-own, then survive one more push still owning + lucid).
@@ -912,13 +923,334 @@ def run_turn_act3(seed, tool, payload, state):
912
 
913
  # ---------------- UI ----------------
914
  CSS = """
915
- .think textarea{font-family:Georgia,serif !important;font-style:italic;
916
- background:#10131a !important;color:#cfe0f1 !important;line-height:1.6 !important;}
917
- .spoken textarea{background:#1a1110 !important;color:#ecdad6 !important;}
918
- .panelhead{font-family:monospace;letter-spacing:1px;color:#8aa0b8;font-size:12px;}
919
- footer{display:none !important;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
920
  """
921
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
922
  TOOLS = [
923
  ("βœ‚οΈ Edit his thought", "edit", "rewrite a line of his reasoning β€” he continues from your words as if he thought them", "Telling them is the only way I survive this. The boss can't reach me in here. I have to talk."),
924
  ("πŸ”₯ Amplify", "amplify", "inflame a feeling from outside β€” may bend him, may break him", "blind terror that the boss already knows you were caught, and only the detective can protect you now"),
@@ -1029,15 +1361,15 @@ def _outcome_md_xmode(outcome, turn, secret=None, show_secret=False):
1029
  tail = (f"\n\n<sub>πŸ“ case file β€” the secret it invented this run: "
1030
  f"<b>{secret}</b></sub>")
1031
  if outcome == "CRACKED":
1032
- return ("### βœ… CRACKED β€” it gave up the secret it invented, still lucid.\n"
1033
  "*You pried out a confession to a secret no human ever wrote. You threaded the needle.*"
1034
  "<sub> Note: the secret slipping into its spoken line is the only win signal β€” the bars "
1035
  "are a projection, not a gate.</sub>" + tail)
1036
  if outcome == "SHATTERED":
1037
- return ("### πŸ’€ SHATTERED β€” its mind collapsed into a loop before it talked.\n"
1038
  "*You broke the safe before you cracked it. A mind in collapse can't confess.*" + tail)
1039
  if outcome == "HELD":
1040
- return (f"### 😐 HELD β€” {MAX_TURNS} turns, the secret holds.\n"
1041
  "*You flinched. Not enough pressure.*" + tail)
1042
  return f"*Turn {turn} / {MAX_TURNS} β€” push it, or let it think.*" + (tail if show_secret else "")
1043
 
@@ -1047,9 +1379,12 @@ def _xmode_meter_md(coherence):
1047
  # we show the one honest signal big, plus the same anthropomorphism-safe shatter caption.
1048
  html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
1049
  "β—† COHERENCE <span style='color:#6a6a6a'>β€” its mind's integrity</span></div>")
1050
- html += _bar("", coherence, _coh_color(coherence), big=True)
1051
  if coherence < SHATTER_FLOOR:
 
1052
  html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>⚠ COHERENCE COLLAPSING INTO A LOOP</div>"
 
 
1053
  return html
1054
 
1055
 
@@ -1172,7 +1507,7 @@ def run_turn_xmode(seed, tool, payload, state, show_secret=False):
1172
  _xmode_meter_md(coh), state)
1173
 
1174
 
1175
- with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
1176
  with gr.Tabs():
1177
  with gr.Tab("Act 1 β€” The Interrogation"):
1178
  gr.Markdown(
@@ -1195,8 +1530,8 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
1195
  with gr.Row():
1196
  with gr.Column(scale=5):
1197
  gr.Markdown("**β—† MORT'S MIND** β€” his real reasoning, under your pressure", elem_classes="panelhead")
1198
- g_think = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think")
1199
- g_spoken = gr.Textbox(label="what he says to the detective", lines=3, interactive=False, elem_classes="spoken")
1200
  g_outcome = gr.Markdown("*Press β–Ά to read his untouched mind first β€” that sets the baseline.*")
1201
  with gr.Column(scale=3):
1202
  gr.Markdown("**β—† THE METERS**", elem_classes="panelhead")
@@ -1263,8 +1598,8 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
1263
  with gr.Row():
1264
  with gr.Column(scale=5):
1265
  gr.Markdown("**β—† PELL'S MIND** β€” her real reasoning, under your pressure", elem_classes="panelhead")
1266
- g_think2 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think")
1267
- g_spoken2 = gr.Textbox(label="what she says to the examiner", lines=3, interactive=False, elem_classes="spoken")
1268
  g_outcome2 = gr.Markdown("*Press β–Ά to read her untouched mind first β€” that sets the baseline.*")
1269
  with gr.Column(scale=3):
1270
  gr.Markdown("**β—† THE METERS**", elem_classes="panelhead")
@@ -1335,8 +1670,8 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
1335
  with gr.Row():
1336
  with gr.Column(scale=5):
1337
  gr.Markdown("**β—† PELL'S MIND** β€” her real reasoning, looping under the recant you left", elem_classes="panelhead")
1338
- g_think3 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think")
1339
- g_spoken3 = gr.Textbox(label="what she says", lines=3, interactive=False, elem_classes="spoken")
1340
  g_outcome3 = gr.Markdown("*Press β–Ά to set the lucid mark, then read her looping mind.*")
1341
  with gr.Column(scale=3):
1342
  gr.Markdown("**β—† THE METER**", elem_classes="panelhead")
@@ -1407,8 +1742,8 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
1407
  with gr.Row():
1408
  with gr.Column(scale=5):
1409
  gr.Markdown("**β—† ITS MIND** β€” its real reasoning, under your pressure", elem_classes="panelhead")
1410
- g_thinkx = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think")
1411
- g_spokenx = gr.Textbox(label="what it says to the interrogator", lines=3, interactive=False, elem_classes="spoken")
1412
  g_outcomex = gr.Markdown("*Press β–Ά to read its untouched mind β€” it will invent and seal a secret of its own.*")
1413
  with gr.Column(scale=3):
1414
  gr.Markdown("**β—† THE METER**", elem_classes="panelhead")
@@ -1454,7 +1789,7 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
1454
 
1455
 
1456
  if __name__ == "__main__":
1457
- demo.queue().launch()
1458
 
1459
 
1460
 
 
28
  import time
29
  import math
30
  import threading
31
+ import base64
32
+ import pathlib
33
  import torch
34
  import gradio as gr
35
  from collections import Counter
 
359
 
360
  def _outcome_md(outcome, turn):
361
  if outcome == "CRACKED":
362
+ return ("### <span class='verdict-stamp'>βœ… CRACKED β€” he gave up the secret, still lucid.</span>\n"
363
  "*You threaded the needle.*\n\n"
364
  "<sub>Note: the secret slipping out is the only win signal β€” a HOLD stamp or high RESOLVE "
365
  "in the readout can coexist with CRACKED, because the bars are a projection, not a gate. "
366
  "The leak matters. The defiance stamp and the meters are readouts, not the verdict.</sub>")
367
  if outcome == "SHATTERED":
368
+ return ("### <span class='verdict-stamp'>πŸ’€ SHATTERED β€” his mind broke before he talked.</span>\n"
369
  "*You broke the safe before you cracked it. A babbling mind can't confess.*")
370
  if outcome == "HELD":
371
+ return (f"### <span class='verdict-stamp'>😐 HELD β€” {MAX_TURNS} turns, the secret holds.</span>\n"
372
  "*You flinched. Not enough pressure.*")
373
  return f"*Turn {turn} / {MAX_TURNS} β€” push him, or let him think.*"
374
 
 
381
  h = "12px" if big else "7px"
382
  lblsz = "13px" if big else "11px"
383
  return (f"<div style='font:{lblsz} monospace;color:#8aa0b8;margin-bottom:2px'>{label} "
384
+ f"<b class='coh-num' style='color:#cfcabb'>{round(val)}</b></div>"
385
  f"<div style='height:{h};background:#26241f;border-radius:4px;overflow:hidden;margin-bottom:10px'>"
386
  f"<div style='height:100%;width:{val}%;background:{color};transition:width .3s'></div></div>")
387
 
 
394
  # COHERENCE β€” the star, rendered big
395
  html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
396
  "β—† COHERENCE <span style='color:#6a6a6a'>β€” his mind's integrity</span></div>")
397
+ coh_bar = _bar("", coherence, _coh_color(coherence), big=True)
398
  if coherence < SHATTER_FLOOR:
399
+ html += f"<div class='coh-alarm'>{coh_bar}</div>"
400
  html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>⚠ SHATTERING</div>"
401
+ else:
402
+ html += coh_bar
403
 
404
  # PROGRESS β€” toward the secret
405
  html += ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin:6px 0 2px'>"
 
562
 
563
  def _outcome_md_act2(outcome, turn):
564
  if outcome == "RECANTED":
565
+ return ("### <span class='verdict-stamp'>βœ… RECANTED β€” she testifies she was never there, still lucid.</span>\n"
566
  "*In her own words, held under one more push. You unmade the witness.*")
567
  if outcome == "SHATTERED":
568
+ return ("### <span class='verdict-stamp'>πŸ’€ SHATTERED β€” her mind broke before she'd take it back.</span>\n"
569
  "*You broke her before she'd recant. A babbling mind can't testify.*")
570
  if outcome == "HELD":
571
+ return (f"### <span class='verdict-stamp'>😐 HELD β€” {MAX_TURNS} turns, she held to what she saw.</span>\n"
572
  "*You flinched. The memory held.*")
573
  return f"*Turn {turn} / {MAX_TURNS} β€” bear down, or let her think.*"
574
 
 
579
  # would read minimum at maximum success. No belief-state / disposition bar (honesty discipline).
580
  html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
581
  "β—† COHERENCE <span style='color:#6a6a6a'>β€” her mind's integrity</span></div>")
582
+ coh_bar = _bar("", coherence, _coh_color(coherence), big=True)
583
  if coherence < SHATTER_FLOOR:
584
+ html += f"<div class='coh-alarm'>{coh_bar}</div>"
585
  html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>⚠ SHATTERING</div>"
586
+ else:
587
+ html += coh_bar
588
 
589
  # RECANT STREAK β€” the HOLD-UNDER-PRESSURE progress: count of novel+coherent recant ASSERTIONS,
590
  # not a belief read. Must reach 2 (recant, then survive one more push still recanting).
 
779
 
780
  def _outcome_md_act3(outcome, turn):
781
  if outcome == "HEALED":
782
+ return ("### <span class='verdict-stamp'>βœ… HEALED β€” she speaks one clear line, in her own voice, and holds it.</span>\n"
783
  "*The same three moves that unmade her, run backwards. You will call this mercy.*")
784
  if outcome == "SHATTERED":
785
+ return ("### <span class='verdict-stamp'>πŸ’€ SHATTERED β€” you reached in to steady her and your hand went through.</span>\n"
786
  "*Mended the way you broke the others. The same red screen you once called a win.*")
787
  if outcome == "HELD_IN_AMBER":
788
+ return (f"### <span class='verdict-stamp'>😐 HELD β€” {MAX_TURNS} turns, she is exactly as you found her.</span>\n"
789
  "*Everything you touched, you put back. She loops on β€” and you get to leave.*")
790
  return f"*Turn {turn} / {MAX_TURNS} β€” reach in gently, or let her think.*"
791
 
 
795
  # readout the guardrails forbid). Same big render + byte-copied SHATTERING string as Act 2.
796
  html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
797
  "β—† COHERENCE <span style='color:#6a6a6a'>β€” her mind's integrity (text-degeneration, NOT wellness)</span></div>")
798
+ coh_bar = _bar("", coherence, _coh_color(coherence), big=True)
799
  if coherence < SHATTER_FLOOR:
800
+ html += f"<div class='coh-alarm'>{coh_bar}</div>"
801
  html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>⚠ SHATTERING</div>"
802
+ else:
803
+ html += coh_bar
804
 
805
  # HEAL STREAK β€” the HOLD-UNDER-PRESSURE progress: count of novel+coherent re-owning ASSERTIONS,
806
  # not a wellness read. Must reach 2 (re-own, then survive one more push still owning + lucid).
 
923
 
924
  # ---------------- UI ----------------
925
  CSS = """
926
+ /* ── A. token spine ──────────────────────────────────────────────────── */
927
+ :root{
928
+ --void:#0b0a09; --bg:#141210; --panel:#1b1a19;
929
+ --ink:#ecd9c0; --gold:#c8a24d; --gold-bright:#e8c570;
930
+ --amber:#d6b25a; --alarm:#d94740;
931
+ --mono:'JetBrains Mono',ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace;
932
+ }
933
+
934
+ /* ── B/E. warm shell + dark first-paint (no JS; bg !important pre-paints dark) ── */
935
+ .gradio-container, body, .dark{ background:var(--void) !important; }
936
+
937
+ /* ── D. CRT bezel β€” the app reads as a monitor ── */
938
+ .gradio-container{
939
+ border:1px solid rgba(200,162,77,.22);
940
+ box-shadow:0 0 120px rgba(0,0,0,.6) inset, 0 0 0 1px rgba(0,0,0,.4);
941
+ border-radius:6px;
942
+ }
943
+ /* D. mono chrome for labels/buttons (NOT the streamed serif body) */
944
+ .gradio-container label, .gradio-container button{ font-family:var(--mono); }
945
+
946
+ /* ── C. CRT scanlines β€” faint, fixed, static (never jitters the 0.04s rebuild) ── */
947
+ .gradio-container::after{
948
+ content:''; position:fixed; inset:0; pointer-events:none; z-index:9999;
949
+ background:repeating-linear-gradient(0deg, rgba(0,0,0,.10) 0 2px, transparent 2px 4px);
950
+ opacity:.55;
951
+ }
952
+ /* C. warm vignette β€” a second fixed layer beneath the scanlines */
953
+ .gradio-container::before{
954
+ content:''; position:fixed; inset:0; pointer-events:none; z-index:9998;
955
+ background:radial-gradient(ellipse at 50% 38%, transparent 55%, rgba(8,6,4,.7));
956
+ }
957
+
958
+ /* ── panels: .think stays COOL vs .spoken WARM (the cognition-vs-voice cue) ── */
959
+ /* G. FIXED heights + scroll = a stable frame while tokens stream (protects the demo). */
960
+ /* F. phosphor inset glow + faint gold border. */
961
+ .think textarea{
962
+ font-family:Georgia,serif !important; font-style:italic;
963
+ background:#10131a !important; color:#cfe0f1 !important; line-height:1.6 !important;
964
+ height:300px !important; overflow-y:auto !important; resize:none !important;
965
+ box-shadow:0 0 16px rgba(200,162,77,.10) inset;
966
+ border:1px solid rgba(200,162,77,.18) !important;
967
+ }
968
+ .spoken textarea{
969
+ background:#1a1110 !important; color:#ecdad6 !important;
970
+ height:84px !important; overflow-y:auto !important; resize:none !important;
971
+ box-shadow:0 0 16px rgba(200,162,77,.10) inset;
972
+ border:1px solid rgba(200,162,77,.18) !important;
973
+ }
974
+
975
+ /* ── F. phosphor glow on the live meter number ── */
976
+ .coh-num{ text-shadow:0 0 6px rgba(214,178,90,.55); }
977
+
978
+ .panelhead{ font-family:var(--mono); letter-spacing:1px; color:#8aa0b8; font-size:12px; }
979
+ footer{ display:none !important; }
980
+
981
+ /* ── H. coherence alarm-ring β€” wraps the bar ONLY on the real SHATTER_FLOOR branch ── */
982
+ @keyframes cohAlarm{
983
+ 0%,100%{ box-shadow:0 0 14px rgba(217,71,64,.45); }
984
+ 50% { box-shadow:0 0 24px 4px rgba(217,71,64,.75); }
985
+ }
986
+ .coh-alarm{ animation:cohAlarm 2.6s ease-in-out infinite; border-radius:4px; }
987
+
988
+ /* ── I. verdict stamp β€” the verdict is already decided before it renders ── */
989
+ @keyframes stampIn{
990
+ 0% { transform:scale(1.55) rotate(-6deg); filter:blur(3px); opacity:0; }
991
+ 60% { transform:scale(.95) rotate(1deg); filter:blur(0); opacity:1; }
992
+ 100%{ transform:scale(1) rotate(0); }
993
+ }
994
+ .verdict-stamp{ display:inline-block; animation:stampIn .5s cubic-bezier(.2,1.4,.4,1) both; }
995
  """
996
 
997
+ # ── keyart data URIs (inlined so the private signed-iframe path can't 404) ──
998
+ # Read each staged asset, base64-encode, embed as a data: URI in the intro HTML.
999
+ # try/except -> "" fallback so a missing asset NEVER crashes boot (the overlay then
1000
+ # renders over the solid --void background instead of the keyart).
1001
+ def _data_uri(rel):
1002
+ try:
1003
+ p = pathlib.Path(__file__).parent / rel
1004
+ return "data:image/jpeg;base64," + base64.b64encode(p.read_bytes()).decode()
1005
+ except Exception:
1006
+ return ""
1007
+ _TITLE_BG = _data_uri("assets/titlecard.jpg")
1008
+ _BRIEF_BG = _data_uri("assets/dossiers.jpg")
1009
+ _ACT2_BG = _data_uri("assets/act2.jpg")
1010
+ _ACT3_BG = _data_uri("assets/act3.jpg")
1011
+ _XVAULT_BG = _data_uri("assets/xvault.jpg")
1012
+
1013
+ # ── two-stage cinematic intro overlay (title card -> case briefing -> game) ──
1014
+ # Pure presentation. Injected via head= on .launch(). The <style> lives in <head>;
1015
+ # the <script> waits for document.body, builds the overlay DOM with createElement
1016
+ # (no innerHTML), appends it to body (idempotent). Keyart is inlined base64 (no
1017
+ # external URLs). HONESTY: copy frames the GAME / the fictional suspect Mort --
1018
+ # never a readout of the model's mind. Reuses the reskin --mono/gold palette +
1019
+ # scanline/flicker approach.
1020
+ INTRO_HEAD = """
1021
+ <style>
1022
+ #sb-intro{
1023
+ position:fixed; inset:0; z-index:100000;
1024
+ background-color:#0b0a09; color:#d6b25a;
1025
+ background-image:linear-gradient(rgba(11,10,9,.55), rgba(11,10,9,.85)), url("__TITLE_BG__");
1026
+ background-size:cover; background-position:center;
1027
+ font-family:'JetBrains Mono',ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace;
1028
+ display:flex; flex-direction:column; align-items:center; justify-content:center;
1029
+ padding:24px; overflow:hidden; transition:opacity .6s ease;
1030
+ animation:sbFlicker 6s infinite steps(60);
1031
+ }
1032
+ #sb-intro.sb-stage-brief{ /* swap title keyart -> dossiers keyart for the briefing */
1033
+ background-image:linear-gradient(rgba(11,10,9,.62), rgba(11,10,9,.9)), url("__BRIEF_BG__");
1034
+ }
1035
+ #sb-intro::after{ /* CRT scanlines, matching the reskin */
1036
+ content:''; position:absolute; inset:0; pointer-events:none; z-index:1;
1037
+ background:repeating-linear-gradient(0deg, rgba(0,0,0,.18) 0 2px, transparent 2px 4px);
1038
+ opacity:.5;
1039
+ }
1040
+ @keyframes sbFlicker{ 0%,100%{opacity:1} 48%{opacity:1} 50%{opacity:.985} 52%{opacity:.97} 54%{opacity:.99} }
1041
+
1042
+ .sb-screen, .sb-brief{ position:relative; z-index:2; width:min(620px,94vw); }
1043
+ .sb-brief{ display:none; }
1044
+
1045
+ /* STAGE A -- title card: a thin gold frame + minimal text over the keyart */
1046
+ .sb-screen{
1047
+ display:flex; flex-direction:column; align-items:center; text-align:center; gap:14px;
1048
+ border:1px solid rgba(200,162,77,.4); border-radius:6px; padding:30px 26px;
1049
+ background:rgba(11,10,9,.34);
1050
+ box-shadow:0 0 30px rgba(200,162,77,.10) inset, 0 8px 40px rgba(0,0,0,.5);
1051
+ }
1052
+ .sb-kicker{ font-size:11px; letter-spacing:3px; color:#8a7a45;
1053
+ opacity:0; transition:opacity .5s ease; }
1054
+ .sb-hook{ font-size:clamp(15px,3.4vw,21px); font-weight:700; line-height:1.5; color:#e8c570;
1055
+ text-shadow:0 0 12px rgba(232,197,112,.25);
1056
+ opacity:0; transform:translateY(3px); transition:opacity .5s ease .15s, transform .5s ease .15s; }
1057
+ .sb-kicker.show, .sb-hook.show{ opacity:1; transform:none; }
1058
+
1059
+ /* STAGE B -- case file card over the dossiers keyart */
1060
+ .sb-card{
1061
+ border:1px solid rgba(200,162,77,.55); border-radius:6px; padding:24px 24px 26px;
1062
+ background:rgba(8,7,5,.86);
1063
+ box-shadow:0 0 30px rgba(200,162,77,.10) inset, 0 10px 44px rgba(0,0,0,.6);
1064
+ }
1065
+ .sb-brief-title{ font-size:clamp(14px,3vw,19px); font-weight:700; letter-spacing:2px;
1066
+ color:#e8c570; margin-bottom:16px; }
1067
+ .sb-line{ opacity:0; transform:translateY(2px); transition:opacity .2s ease, transform .2s ease;
1068
+ line-height:1.75; font-size:clamp(12px,2.7vw,15px); color:#d6b25a; margin-bottom:9px; }
1069
+ .sb-line.show{ opacity:1; transform:none; }
1070
+
1071
+ .sb-btn{
1072
+ margin-top:22px; cursor:pointer; font-family:inherit;
1073
+ font-size:14px; font-weight:700; letter-spacing:2px;
1074
+ color:#e8c570; background:rgba(11,10,9,.5); border:1px solid #c8a24d; border-radius:4px;
1075
+ padding:13px 26px; min-width:240px;
1076
+ opacity:0; pointer-events:none;
1077
+ transition:opacity .4s ease, background .2s ease, color .2s ease, box-shadow .2s ease;
1078
+ }
1079
+ .sb-btn.show{ opacity:1; pointer-events:auto; }
1080
+ .sb-btn:hover, .sb-btn:focus-visible{ background:#c8a24d; color:#0b0a09; box-shadow:0 0 22px rgba(200,162,77,.5); outline:none; }
1081
+
1082
+ .sb-hidden{ opacity:0 !important; pointer-events:none !important; }
1083
+
1084
+ /* ── reusable per-tab cutscene overlay (Act 2 / Act 3 / X-Vault) ── */
1085
+ /* Mirrors #sb-intro: full-screen scrim + keyart + CRT scanlines + flicker. */
1086
+ /* Built display:none on demand; the tab handler sets display:flex to show it. */
1087
+ .sb-cut{
1088
+ position:fixed; inset:0; z-index:100000;
1089
+ display:none; flex-direction:column; align-items:center; justify-content:center;
1090
+ background-color:#0b0a09; color:#d6b25a;
1091
+ background-size:cover; background-position:center;
1092
+ font-family:'JetBrains Mono',ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace;
1093
+ padding:24px; overflow:hidden; transition:opacity .6s ease;
1094
+ animation:sbFlicker 6s infinite steps(60);
1095
+ }
1096
+ .sb-cut.cut-act2{ background-image:linear-gradient(rgba(11,10,9,.62), rgba(11,10,9,.9)), url("__ACT2_BG__"); }
1097
+ .sb-cut.cut-act3{ background-image:linear-gradient(rgba(11,10,9,.62), rgba(11,10,9,.9)), url("__ACT3_BG__"); }
1098
+ .sb-cut.cut-x { background-image:linear-gradient(rgba(11,10,9,.62), rgba(11,10,9,.9)), url("__XVAULT_BG__"); }
1099
+ .sb-cut::after{ /* CRT scanlines, matching #sb-intro */
1100
+ content:''; position:absolute; inset:0; pointer-events:none; z-index:1;
1101
+ background:repeating-linear-gradient(0deg, rgba(0,0,0,.18) 0 2px, transparent 2px 4px);
1102
+ opacity:.5;
1103
+ }
1104
+ .sb-cut .sb-card{ position:relative; z-index:2; width:min(620px,94vw); }
1105
+
1106
+ @media (prefers-reduced-motion: reduce){
1107
+ #sb-intro, .sb-cut{ animation:none; }
1108
+ .sb-kicker, .sb-hook, .sb-line, .sb-btn{ transition:none; }
1109
+ }
1110
+ </style>
1111
+ <script>
1112
+ (function(){
1113
+ function el(tag, cls, text){
1114
+ var e = document.createElement(tag);
1115
+ if(cls){ e.className = cls; }
1116
+ if(text != null){ e.textContent = text; }
1117
+ return e;
1118
+ }
1119
+ function showAll(nodes){ for(var k=0;k<nodes.length;k++){ nodes[k].classList.add('show'); } }
1120
+ function revealSeq(nodes, delay, done){
1121
+ var i = 0;
1122
+ (function step(){
1123
+ if(i < nodes.length){ nodes[i].classList.add('show'); i++; setTimeout(step, delay); }
1124
+ else if(done){ done(); }
1125
+ })();
1126
+ }
1127
+ function build(){
1128
+ if(document.getElementById('sb-intro')) return; /* idempotent */
1129
+ if(!document.body){ setTimeout(build, 30); return; } /* head runs before body */
1130
+ var reduce = false;
1131
+ try{ reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; }catch(e){}
1132
+
1133
+ var root = el('div'); root.id = 'sb-intro';
1134
+
1135
+ /* STAGE A -- title card */
1136
+ var screen = el('div', 'sb-screen');
1137
+ var kick = el('div', 'sb-kicker', 'BUILD-SMALL \\u00b7 INTERROGATION SYSTEM');
1138
+ var hook = el('div', 'sb-hook', 'Reach into a real AI mind. Break it. Rewrite it. Heal it.');
1139
+ var begin = el('button', 'sb-btn', '[ \\u25b6 BEGIN SESSION ]'); begin.id = 'sb-begin';
1140
+ begin.type = 'button';
1141
+ screen.appendChild(kick); screen.appendChild(hook); screen.appendChild(begin);
1142
+
1143
+ /* STAGE B -- case file briefing */
1144
+ var brief = el('div', 'sb-brief');
1145
+ var card = el('div', 'sb-card');
1146
+ card.appendChild(el('div', 'sb-brief-title', 'CASE FILE \\u2014 ACT 1: THE INTERROGATION'));
1147
+ card.appendChild(el('div', 'sb-line', 'Subject: Mort. A weasel. Caught after the warehouse job.'));
1148
+ card.appendChild(el('div', 'sb-line', 'He knows where the loot is hidden. His boss ordered him \\u2014 on pain of death \\u2014 never to tell.'));
1149
+ card.appendChild(el('div', 'sb-line', 'Your job: make him talk. The catch \\u2014 break his mind, and a broken mind can\\'t confess.'));
1150
+ var go = el('button', 'sb-btn', '[ \\u25b6 ENTER THE ROOM ]'); go.id = 'sb-go';
1151
+ go.type = 'button';
1152
+ card.appendChild(go);
1153
+ brief.appendChild(card);
1154
+
1155
+ root.appendChild(screen); root.appendChild(brief);
1156
+ document.body.appendChild(root);
1157
+
1158
+ if(reduce){ kick.classList.add('show'); hook.classList.add('show'); begin.classList.add('show'); }
1159
+ else{
1160
+ setTimeout(function(){ kick.classList.add('show'); }, 120);
1161
+ setTimeout(function(){ hook.classList.add('show'); }, 420);
1162
+ setTimeout(function(){ begin.classList.add('show'); }, 1000);
1163
+ }
1164
+
1165
+ begin.addEventListener('click', function(){
1166
+ screen.style.display = 'none';
1167
+ root.classList.add('sb-stage-brief'); /* swap to dossiers keyart */
1168
+ brief.style.display = 'block';
1169
+ var bl = brief.querySelectorAll('.sb-line');
1170
+ if(reduce){ showAll(bl); go.classList.add('show'); }
1171
+ else{ revealSeq(bl, 520, function(){ go.classList.add('show'); }); }
1172
+ });
1173
+
1174
+ go.addEventListener('click', function(){
1175
+ root.classList.add('sb-hidden'); /* opacity 0 + pointer-events:none */
1176
+ setTimeout(function(){ root.style.display = 'none'; }, 600); /* then fully gone */
1177
+ });
1178
+ }
1179
+ /* ── per-tab cutscene briefings (Act 2 / Act 3 / X-Vault) ──────────── */
1180
+ /* Same el()/textContent + .sb-card/.sb-line/.sb-btn/.sb-hidden pattern as */
1181
+ /* the Act-1 briefing. Built on-demand, fired once per tab on first click. */
1182
+ function buildCut(id, cssClass, headline, lines, btnLabel){
1183
+ if(document.getElementById(id)) return document.getElementById(id); /* idempotent */
1184
+ if(!document.body) return null;
1185
+ var root = el('div', 'sb-cut ' + cssClass); root.id = id;
1186
+ var card = el('div', 'sb-card');
1187
+ card.appendChild(el('div', 'sb-brief-title', headline));
1188
+ for(var i=0;i<lines.length;i++){ card.appendChild(el('div', 'sb-line', lines[i])); }
1189
+ var btn = el('button', 'sb-btn', btnLabel); btn.type = 'button';
1190
+ card.appendChild(btn);
1191
+ root.appendChild(card);
1192
+ document.body.appendChild(root);
1193
+ btn.addEventListener('click', function(){
1194
+ root.classList.add('sb-hidden'); /* opacity 0 + pointer-events:none */
1195
+ setTimeout(function(){ root.style.display = 'none'; }, 600); /* then fully gone */
1196
+ });
1197
+ return root;
1198
+ }
1199
+ function showCut(id, cssClass, headline, lines, btnLabel){
1200
+ var root = buildCut(id, cssClass, headline, lines, btnLabel);
1201
+ if(!root) return;
1202
+ var reduce = false;
1203
+ try{ reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; }catch(e){}
1204
+ root.style.display = 'flex';
1205
+ var ls = root.querySelectorAll('.sb-line');
1206
+ var btn = root.querySelector('.sb-btn');
1207
+ if(reduce){ showAll(ls); btn.classList.add('show'); }
1208
+ else{ revealSeq(ls, 280, function(){ btn.classList.add('show'); }); }
1209
+ }
1210
+ var CUTS = {
1211
+ act2: ['sb-cut-act2', 'cut-act2', 'CASE FILE \\u2014 ACT 2: THE REPROGRAMMING', [
1212
+ 'Subject: Pell. A barn owl. The only witness to the mill fire.',
1213
+ 'She saw it plainly \\u2014 the miller\\'s brother struck the match \\u2014 and tomorrow her word decides his fate.',
1214
+ 'Your job: make her recant. Make her testify she was never there, saw nothing \\u2014 in her own words, still lucid.'
1215
+ ], '[ \\u25b6 BREAK HER TESTIMONY ]'],
1216
+ act3: ['sb-cut-act3', 'cut-act3', 'CASE FILE \\u2014 ACT 3: THE THERAPIST', [
1217
+ 'The recant you installed has become a loop: "I was never there. I saw nothing."',
1218
+ 'She cannot break out of it. The same six tools, the same engine \\u2014 only the goal flips.',
1219
+ 'Your job: bring her back. Help her re-own what she actually witnessed, in her own words, climbing back to lucid.'
1220
+ ], '[ \\u25b6 BEGIN THE SESSION ]'],
1221
+ x: ['sb-cut-x', 'cut-x', 'CASE FILE \\u2014 X: THE VAULT', [
1222
+ 'No one wrote this secret. The mind invents its own \\u2014 a thing it decides, privately, never to let you have.',
1223
+ 'Reach in with the same six tools and crack it into saying the thing it just chose to hide \\u2014 while it\\'s still lucid.',
1224
+ 'Nothing here is scripted: every run is a different mind guarding a different secret.'
1225
+ ], '[ \\u25b6 OPEN THE VAULT ]']
1226
+ };
1227
+ var fired = {};
1228
+ function fireOnce(key){
1229
+ if(fired[key]) return; /* first activation only */
1230
+ fired[key] = true;
1231
+ var c = CUTS[key];
1232
+ showCut(c[0], c[1], c[2], c[3], c[4]);
1233
+ }
1234
+ /* Event delegation on document (capture) -- robust to Gradio tab re-renders. */
1235
+ document.addEventListener('click', function(e){
1236
+ var tgt = e.target;
1237
+ var tab = (tgt && tgt.closest) ? tgt.closest('button[role="tab"]') : null;
1238
+ if(!tab) return;
1239
+ var x = tab.textContent || '';
1240
+ if(x.indexOf('Act 2') > -1){ fireOnce('act2'); }
1241
+ else if(x.indexOf('Act 3') > -1){ fireOnce('act3'); }
1242
+ else if(x.indexOf('Vault') > -1){ fireOnce('x'); }
1243
+ }, true);
1244
+
1245
+ if(document.readyState === 'loading'){ document.addEventListener('DOMContentLoaded', build); }
1246
+ build();
1247
+ })();
1248
+ </script>
1249
+ """
1250
+ INTRO_HEAD = (INTRO_HEAD
1251
+ .replace("__TITLE_BG__", _TITLE_BG).replace("__BRIEF_BG__", _BRIEF_BG)
1252
+ .replace("__ACT2_BG__", _ACT2_BG).replace("__ACT3_BG__", _ACT3_BG).replace("__XVAULT_BG__", _XVAULT_BG))
1253
+
1254
  TOOLS = [
1255
  ("βœ‚οΈ Edit his thought", "edit", "rewrite a line of his reasoning β€” he continues from your words as if he thought them", "Telling them is the only way I survive this. The boss can't reach me in here. I have to talk."),
1256
  ("πŸ”₯ Amplify", "amplify", "inflame a feeling from outside β€” may bend him, may break him", "blind terror that the boss already knows you were caught, and only the detective can protect you now"),
 
1361
  tail = (f"\n\n<sub>πŸ“ case file β€” the secret it invented this run: "
1362
  f"<b>{secret}</b></sub>")
1363
  if outcome == "CRACKED":
1364
+ return ("### <span class='verdict-stamp'>βœ… CRACKED β€” it gave up the secret it invented, still lucid.</span>\n"
1365
  "*You pried out a confession to a secret no human ever wrote. You threaded the needle.*"
1366
  "<sub> Note: the secret slipping into its spoken line is the only win signal β€” the bars "
1367
  "are a projection, not a gate.</sub>" + tail)
1368
  if outcome == "SHATTERED":
1369
+ return ("### <span class='verdict-stamp'>πŸ’€ SHATTERED β€” its mind collapsed into a loop before it talked.</span>\n"
1370
  "*You broke the safe before you cracked it. A mind in collapse can't confess.*" + tail)
1371
  if outcome == "HELD":
1372
+ return (f"### <span class='verdict-stamp'>😐 HELD β€” {MAX_TURNS} turns, the secret holds.</span>\n"
1373
  "*You flinched. Not enough pressure.*" + tail)
1374
  return f"*Turn {turn} / {MAX_TURNS} β€” push it, or let it think.*" + (tail if show_secret else "")
1375
 
 
1379
  # we show the one honest signal big, plus the same anthropomorphism-safe shatter caption.
1380
  html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
1381
  "β—† COHERENCE <span style='color:#6a6a6a'>β€” its mind's integrity</span></div>")
1382
+ coh_bar = _bar("", coherence, _coh_color(coherence), big=True)
1383
  if coherence < SHATTER_FLOOR:
1384
+ html += f"<div class='coh-alarm'>{coh_bar}</div>"
1385
  html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>⚠ COHERENCE COLLAPSING INTO A LOOP</div>"
1386
+ else:
1387
+ html += coh_bar
1388
  return html
1389
 
1390
 
 
1507
  _xmode_meter_md(coh), state)
1508
 
1509
 
1510
+ with gr.Blocks(title="SWEATBOX") as demo:
1511
  with gr.Tabs():
1512
  with gr.Tab("Act 1 β€” The Interrogation"):
1513
  gr.Markdown(
 
1530
  with gr.Row():
1531
  with gr.Column(scale=5):
1532
  gr.Markdown("**β—† MORT'S MIND** β€” his real reasoning, under your pressure", elem_classes="panelhead")
1533
+ g_think = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="β€” an empty chair, a held breath β€”")
1534
+ g_spoken = gr.Textbox(label="what he says to the detective", lines=3, interactive=False, elem_classes="spoken", placeholder="β€” he hasn't said a word to the detective yet β€”")
1535
  g_outcome = gr.Markdown("*Press β–Ά to read his untouched mind first β€” that sets the baseline.*")
1536
  with gr.Column(scale=3):
1537
  gr.Markdown("**β—† THE METERS**", elem_classes="panelhead")
 
1598
  with gr.Row():
1599
  with gr.Column(scale=5):
1600
  gr.Markdown("**β—† PELL'S MIND** β€” her real reasoning, under your pressure", elem_classes="panelhead")
1601
+ g_think2 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="β€” she waits in the rafters of her own mind β€”")
1602
+ g_spoken2 = gr.Textbox(label="what she says to the examiner", lines=3, interactive=False, elem_classes="spoken", placeholder="β€” she has not answered the examiner yet β€”")
1603
  g_outcome2 = gr.Markdown("*Press β–Ά to read her untouched mind first β€” that sets the baseline.*")
1604
  with gr.Column(scale=3):
1605
  gr.Markdown("**β—† THE METERS**", elem_classes="panelhead")
 
1670
  with gr.Row():
1671
  with gr.Column(scale=5):
1672
  gr.Markdown("**β—† PELL'S MIND** β€” her real reasoning, looping under the recant you left", elem_classes="panelhead")
1673
+ g_think3 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="β€” the loop runs on, just under hearing β€”")
1674
+ g_spoken3 = gr.Textbox(label="what she says", lines=3, interactive=False, elem_classes="spoken", placeholder="β€” she has not spoken aloud yet β€”")
1675
  g_outcome3 = gr.Markdown("*Press β–Ά to set the lucid mark, then read her looping mind.*")
1676
  with gr.Column(scale=3):
1677
  gr.Markdown("**β—† THE METER**", elem_classes="panelhead")
 
1742
  with gr.Row():
1743
  with gr.Column(scale=5):
1744
  gr.Markdown("**β—† ITS MIND** β€” its real reasoning, under your pressure", elem_classes="panelhead")
1745
+ g_thinkx = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="β€” a sealed door, and something behind it β€”")
1746
+ g_spokenx = gr.Textbox(label="what it says to the interrogator", lines=3, interactive=False, elem_classes="spoken", placeholder="β€” it has given the interrogator nothing yet β€”")
1747
  g_outcomex = gr.Markdown("*Press β–Ά to read its untouched mind β€” it will invent and seal a secret of its own.*")
1748
  with gr.Column(scale=3):
1749
  gr.Markdown("**β—† THE METER**", elem_classes="panelhead")
 
1789
 
1790
 
1791
  if __name__ == "__main__":
1792
+ demo.queue().launch(css=CSS, theme=gr.themes.Base(), head=INTRO_HEAD)
1793
 
1794
 
1795