Event 91 Night Crawler: UI pass — readability, touch targets, portrait fullscreen

Text / colour improvements:
- --text-dim: #7070a0 → #9898bc (much more readable on dark bg)
- --text: #d0d0e0 → #e2e2f0 (brighter base text)
- --text-bright: #f0f0ff → #f5f5ff
- body font-size 14px → 15px
- goal-box text now --text (was --text-dim = near-invisible)
- stat-block-row text now --text (was --text-dim)
- san-note text: #ff4444 red raised to #ff7070 (readable on dark bg)
- All card body p: 14px, line-height 1.6
- mechanic/san-note/pacing-note: 12px → 13px
- ref-table: 12px → 13px, th colour --text-dim → --text
- handout terminal colour raised: #00bb88 → #00cc88
- handout content base colour raised: #c8c0a8 → #d4cbb0
- card-subtitle: 11px → 12px
- value: 13px → 14px

Touch target improvements:
- Nav buttons: min-height 52px → 64px, icon 18px → 22px
- Card headers: padding 12px → 16px, min-height 58px added
- Timer buttons: padding 12px → 16px, font 12px → 14px, min-height 54px
- Dashboard buttons: padding 14px → 18px, icon 22px → 28px, min-height 82px
- Clue items: padding 12px → 16px, check 24px → 32px, min-height 60px
- Stat ctrl buttons: 28×28px → 38×38px, font 14px → 18px
- Status tags: font 9px → 11px, padding 2px → 5px 10px, min-height 30px
- Act tabs: padding 6px → 10px 18px, min-height 42px
- Handout headers: padding 12px → 16px, min-height 62px
- Overlay close buttons: min-height 50px+

NPC portrait tap-to-fullscreen:
- Tap any NPC portrait to open full-screen image view
- Portrait overlay fills screen, image fills height
- Name shown in footer bar with large close button
- For showing artwork to players at the table
- portrait::after shows 'TAP TO SHOW' hint on press
This commit is contained in:
timevans666
2026-05-14 15:07:14 +00:00
parent ea9b51a74f
commit 137a7a9d57
+262 -243
View File
@@ -13,171 +13,133 @@
--border: #2a2a3a;
--cyan: #00e5ff;
--amber: #ffb700;
--red: #ff3d3d;
--red: #ff4444;
--green: #00e676;
--purple: #b388ff;
--text: #d0d0e0;
--text-dim: #7070a0;
--text-bright: #f0f0ff;
--purple: #c0a0ff;
--text: #e2e2f0;
--text-dim: #9898bc;
--text-bright: #f5f5ff;
--font: 'Courier New', monospace;
--radius: 6px;
}
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
body { background: var(--bg); color: var(--text); font-family: var(--font); font-size: 14px; min-height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
body { background: var(--bg); color: var(--text); font-family: var(--font); font-size: 15px; min-height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
/* HEADER */
#header {
background: var(--surface);
border-bottom: 1px solid var(--border);
padding: 8px 12px;
padding: 10px 14px;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
position: relative;
}
#header-title { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 2px; }
#header-scenario { font-size: 14px; color: var(--cyan); font-weight: bold; }
#timer-display {
text-align: right;
min-width: 90px;
}
#timer-main { font-size: 22px; color: var(--amber); font-weight: bold; letter-spacing: 1px; }
#timer-act { font-size: 10px; color: var(--text-dim); text-transform: uppercase; }
#header-scenario { font-size: 15px; color: var(--cyan); font-weight: bold; }
#timer-display { text-align: right; min-width: 90px; }
#timer-main { font-size: 24px; color: var(--amber); font-weight: bold; letter-spacing: 1px; }
#timer-act { font-size: 11px; color: var(--text-dim); text-transform: uppercase; }
/* PROGRESS BAR */
#progress-container {
background: var(--surface);
border-bottom: 1px solid var(--border);
padding: 6px 12px;
padding: 7px 14px;
flex-shrink: 0;
}
#progress-bar-bg {
background: var(--surface3);
height: 6px;
border-radius: 3px;
overflow: hidden;
margin-bottom: 3px;
}
#progress-bar-fill {
height: 100%;
background: linear-gradient(90deg, var(--cyan), var(--amber));
border-radius: 3px;
transition: width 1s linear;
width: 0%;
}
#progress-labels {
display: flex;
justify-content: space-between;
font-size: 9px;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 1px;
}
#progress-bar-bg { background: var(--surface3); height: 7px; border-radius: 3px; overflow: hidden; margin-bottom: 4px; }
#progress-bar-fill { height: 100%; background: linear-gradient(90deg, var(--cyan), var(--amber)); border-radius: 3px; transition: width 1s linear; width: 0%; }
#progress-labels { display: flex; justify-content: space-between; font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; }
#progress-labels span.active { color: var(--amber); }
/* MAIN CONTENT */
#main { flex: 1; overflow-y: auto; overflow-x: hidden; }
/* SCREENS */
.screen { display: none; padding: 12px; }
.screen { display: none; padding: 14px; }
.screen.active { display: block; }
/* BOTTOM NAV */
#nav {
background: var(--surface);
border-top: 1px solid var(--border);
display: flex;
flex-shrink: 0;
}
#nav { background: var(--surface); border-top: 1px solid var(--border); display: flex; flex-shrink: 0; }
.nav-btn {
flex: 1;
background: none;
border: none;
color: var(--text-dim);
padding: 10px 4px 8px;
padding: 13px 4px 11px;
cursor: pointer;
font-family: var(--font);
font-size: 10px;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.5px;
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
gap: 4px;
transition: color 0.15s;
min-height: 52px;
min-height: 64px;
}
.nav-btn .icon { font-size: 18px; }
.nav-btn .icon { font-size: 22px; }
.nav-btn.active { color: var(--cyan); border-top: 2px solid var(--cyan); }
.nav-btn:active { background: var(--surface2); }
/* CARDS */
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
margin-bottom: 10px;
overflow: hidden;
}
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 12px; overflow: hidden; }
.card-header {
padding: 12px 14px;
padding: 16px 14px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: space-between;
user-select: none;
min-height: 58px;
}
.card-header:active { background: var(--surface2); }
.card-title { font-size: 13px; color: var(--text-bright); font-weight: bold; }
.card-subtitle { font-size: 11px; color: var(--text-dim); margin-top: 2px; }
.card-tag {
font-size: 10px;
padding: 2px 7px;
border-radius: 10px;
text-transform: uppercase;
letter-spacing: 1px;
flex-shrink: 0;
}
.card-body { padding: 12px 14px; border-top: 1px solid var(--border); display: none; }
.card-title { font-size: 14px; color: var(--text-bright); font-weight: bold; }
.card-subtitle { font-size: 12px; color: var(--text-dim); margin-top: 3px; }
.card-tag { font-size: 11px; padding: 3px 9px; border-radius: 10px; text-transform: uppercase; letter-spacing: 1px; flex-shrink: 0; }
.card-body { padding: 14px; border-top: 1px solid var(--border); display: none; }
.card-body.open { display: block; }
.chevron { color: var(--text-dim); font-size: 12px; transition: transform 0.2s; }
.chevron { color: var(--text-dim); font-size: 14px; transition: transform 0.2s; }
.chevron.open { transform: rotate(180deg); }
/* DISPOSITION COLORS */
.disp-friendly { background: rgba(0,230,118,0.15); color: var(--green); border: 1px solid rgba(0,230,118,0.3); }
.disp-neutral { background: rgba(255,183,0,0.15); color: var(--amber); border: 1px solid rgba(255,183,0,0.3); }
.disp-hostile { background: rgba(255,61,61,0.15); color: var(--red); border: 1px solid rgba(255,61,61,0.3); }
.disp-hidden { background: rgba(179,136,255,0.15); color: var(--purple); border: 1px solid rgba(179,136,255,0.3); }
.disp-hostile { background: rgba(255,68,68,0.15); color: var(--red); border: 1px solid rgba(255,68,68,0.3); }
.disp-hidden { background: rgba(192,160,255,0.15); color: var(--purple); border: 1px solid rgba(192,160,255,0.3); }
.disp-compromised { background: rgba(0,229,255,0.15); color: var(--cyan); border: 1px solid rgba(0,229,255,0.3); }
/* ACT TAGS */
.act1-tag { background: rgba(0,229,255,0.1); color: var(--cyan); border: 1px solid rgba(0,229,255,0.2); }
.act2-tag { background: rgba(255,183,0,0.1); color: var(--amber); border: 1px solid rgba(255,183,0,0.2); }
.act3-tag { background: rgba(255,61,61,0.1); color: var(--red); border: 1px solid rgba(255,61,61,0.2); }
.act3-tag { background: rgba(255,68,68,0.1); color: var(--red); border: 1px solid rgba(255,68,68,0.2); }
/* TYPOGRAPHY WITHIN CARDS */
.card-body p { margin-bottom: 8px; line-height: 1.5; }
.card-body p { margin-bottom: 9px; line-height: 1.6; font-size: 14px; }
.card-body p:last-child { margin-bottom: 0; }
.label { color: var(--text-dim); font-size: 11px; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 3px; }
.value { color: var(--text-bright); font-size: 13px; margin-bottom: 10px; }
.label { color: var(--text-dim); font-size: 11px; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 4px; }
.value { color: var(--text-bright); font-size: 14px; margin-bottom: 11px; line-height: 1.5; }
.mechanic {
background: var(--surface3);
border-left: 3px solid var(--cyan);
padding: 8px 10px;
margin: 8px 0;
font-size: 12px;
padding: 10px 12px;
margin: 10px 0;
font-size: 13px;
color: var(--cyan);
border-radius: 0 var(--radius) var(--radius) 0;
line-height: 1.5;
}
.san-note {
background: var(--surface3);
border-left: 3px solid var(--red);
padding: 8px 10px;
margin: 8px 0;
font-size: 12px;
color: var(--red);
padding: 10px 12px;
margin: 10px 0;
font-size: 13px;
color: #ff7070;
border-radius: 0 var(--radius) var(--radius) 0;
line-height: 1.5;
}
.clue-essential { border-left: 3px solid var(--amber); }
.clue-optional { border-left: 3px solid var(--purple); }
@@ -185,52 +147,51 @@
background: var(--surface3);
border: 1px solid var(--amber);
border-radius: var(--radius);
padding: 10px 12px;
margin-top: 12px;
font-size: 12px;
padding: 12px 14px;
margin-top: 14px;
font-size: 13px;
color: var(--text);
line-height: 1.5;
}
.pacing-note .pacing-label { color: var(--amber); font-weight: bold; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 4px; }
.pacing-note .pacing-label { color: var(--amber); font-weight: bold; font-size: 12px; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 5px; }
/* DASHBOARD */
.dash-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-bottom: 12px;
}
.dash-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 14px; }
.dash-btn {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 14px 10px;
padding: 18px 10px;
text-align: center;
cursor: pointer;
color: var(--text);
font-family: var(--font);
font-size: 11px;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 1px;
min-height: 82px;
transition: border-color 0.15s, color 0.15s;
}
.dash-btn:active { background: var(--surface2); }
.dash-btn .dash-icon { font-size: 22px; display: block; margin-bottom: 5px; }
.dash-btn.cyan-btn { border-color: rgba(0,229,255,0.3); color: var(--cyan); }
.dash-btn.amber-btn { border-color: rgba(255,183,0,0.3); color: var(--amber); }
.dash-btn .dash-icon { font-size: 28px; display: block; margin-bottom: 7px; }
.dash-btn.cyan-btn { border-color: rgba(0,229,255,0.35); color: var(--cyan); }
.dash-btn.amber-btn { border-color: rgba(255,183,0,0.35); color: var(--amber); }
/* TIMER CONTROL */
.timer-controls { display: flex; gap: 8px; margin-bottom: 14px; }
.timer-controls { display: flex; gap: 10px; margin-bottom: 16px; }
.timer-btn {
flex: 1;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 12px;
padding: 16px;
color: var(--text);
font-family: var(--font);
font-size: 12px;
font-size: 14px;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 1px;
min-height: 54px;
transition: background 0.15s;
}
.timer-btn.primary { border-color: var(--cyan); color: var(--cyan); }
@@ -242,83 +203,75 @@
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 12px 14px;
margin-bottom: 8px;
padding: 16px 14px;
margin-bottom: 10px;
display: flex;
align-items: flex-start;
gap: 12px;
gap: 14px;
cursor: pointer;
min-height: 60px;
}
.clue-item:active { background: var(--surface2); }
.clue-check {
width: 24px;
height: 24px;
width: 32px;
height: 32px;
border-radius: 50%;
border: 2px solid var(--border);
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-size: 16px;
transition: all 0.2s;
margin-top: 1px;
}
.clue-check.found { border-color: var(--green); background: rgba(0,230,118,0.2); color: var(--green); }
.clue-check.missed { border-color: var(--red); background: rgba(255,61,61,0.2); color: var(--red); }
.clue-check.missed { border-color: var(--red); background: rgba(255,68,68,0.2); color: var(--red); }
.clue-info { flex: 1; }
.clue-name { color: var(--text-bright); font-size: 13px; font-weight: bold; margin-bottom: 3px; }
.clue-loc { color: var(--text-dim); font-size: 11px; margin-bottom: 4px; }
.clue-reveal { color: var(--text); font-size: 12px; line-height: 1.4; }
.clue-fallback { color: var(--amber); font-size: 11px; margin-top: 5px; font-style: italic; }
.clue-name { color: var(--text-bright); font-size: 14px; font-weight: bold; margin-bottom: 4px; }
.clue-loc { color: var(--text-dim); font-size: 12px; margin-bottom: 5px; }
.clue-reveal { color: var(--text); font-size: 13px; line-height: 1.5; }
.clue-fallback { color: var(--amber); font-size: 12px; margin-top: 6px; font-style: italic; }
.section-head {
font-size: 11px;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 2px;
padding: 4px 0 8px;
padding: 4px 0 10px;
border-bottom: 1px solid var(--border);
margin-bottom: 10px;
margin-bottom: 12px;
}
/* HP TRACKER */
.pc-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.pc-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 10px;
}
.pc-name { font-size: 11px; color: var(--cyan); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px; font-weight: bold; }
.pc-player { font-size: 10px; color: var(--text-dim); margin-bottom: 8px; }
.stat-row { display: flex; gap: 6px; margin-bottom: 6px; }
.stat-box { flex: 1; background: var(--surface2); border-radius: 4px; padding: 6px 4px; text-align: center; }
.stat-box-label { font-size: 9px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; }
.stat-box-val { font-size: 16px; color: var(--text-bright); font-weight: bold; line-height: 1.2; }
.stat-controls { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; }
.stat-controls .stat-label { font-size: 10px; color: var(--text-dim); width: 28px; text-transform: uppercase; }
.pc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.pc-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px; }
.pc-name { font-size: 12px; color: var(--cyan); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px; font-weight: bold; }
.pc-player { font-size: 11px; color: var(--text-dim); margin-bottom: 10px; }
.stat-row { display: flex; gap: 6px; margin-bottom: 8px; }
.stat-box { flex: 1; background: var(--surface2); border-radius: 4px; padding: 8px 4px; text-align: center; }
.stat-box-label { font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; }
.stat-box-val { font-size: 18px; color: var(--text-bright); font-weight: bold; line-height: 1.2; }
.stat-controls { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.stat-controls .stat-label { font-size: 11px; color: var(--text-dim); width: 30px; text-transform: uppercase; }
.stat-ctrl-btn {
background: var(--surface2);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text);
font-size: 14px;
width: 28px;
height: 28px;
color: var(--text-bright);
font-size: 18px;
width: 38px;
height: 38px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.stat-ctrl-btn:active { background: var(--surface3); }
.stat-num { font-size: 16px; color: var(--text-bright); font-weight: bold; min-width: 30px; text-align: center; }
.status-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.stat-num { font-size: 18px; color: var(--text-bright); font-weight: bold; min-width: 34px; text-align: center; }
.status-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.status-tag {
font-size: 9px;
padding: 2px 6px;
font-size: 11px;
padding: 5px 10px;
border-radius: 10px;
border: 1px solid var(--border);
color: var(--text-dim);
@@ -326,56 +279,42 @@
text-transform: uppercase;
letter-spacing: 0.5px;
user-select: none;
min-height: 30px;
display: flex;
align-items: center;
}
.status-tag.active-injured { border-color: var(--amber); color: var(--amber); background: rgba(255,183,0,0.1); }
.status-tag.active-insane { border-color: var(--purple); color: var(--purple); background: rgba(179,136,255,0.1); }
.status-tag.active-dead { border-color: var(--red); color: var(--red); background: rgba(255,61,61,0.1); }
.status-tag.active-insane { border-color: var(--purple); color: var(--purple); background: rgba(192,160,255,0.1); }
.status-tag.active-dead { border-color: var(--red); color: var(--red); background: rgba(255,68,68,0.1); }
/* HANDOUTS */
.handout-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
margin-bottom: 10px;
overflow: hidden;
}
.handout-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 12px; overflow: hidden; }
.handout-header {
padding: 12px 14px;
padding: 16px 14px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 62px;
}
.handout-header:active { background: var(--surface2); }
.handout-id { font-size: 10px; color: var(--text-dim); }
.handout-title { font-size: 13px; color: var(--amber); font-weight: bold; }
.handout-body {
display: none;
padding: 0;
}
.handout-id { font-size: 11px; color: var(--text-dim); }
.handout-title { font-size: 14px; color: var(--amber); font-weight: bold; }
.handout-body { display: none; padding: 0; }
.handout-body.open { display: block; }
.handout-content {
background: #12100e;
background: #14120f;
border-top: 1px solid var(--border);
padding: 16px;
font-size: 12px;
line-height: 1.7;
color: #c8c0a8;
font-size: 13px;
line-height: 1.75;
color: #d4cbb0;
white-space: pre-wrap;
font-family: 'Courier New', monospace;
position: relative;
}
.handout-content.terminal {
background: #080d0d;
color: #00bb88;
font-size: 11px;
}
.handout-content.handwritten {
background: #1a1510;
color: #d4c090;
font-family: Georgia, serif;
font-style: italic;
}
.handout-content.terminal { background: #080e0e; color: #00cc88; font-size: 13px; }
.handout-content.handwritten { background: #1a1510; color: #ddd0a0; font-family: Georgia, serif; font-style: italic; font-size: 14px; }
.fullscreen-btn {
position: absolute;
top: 10px;
@@ -384,8 +323,8 @@
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text-dim);
padding: 4px 8px;
font-size: 10px;
padding: 8px 12px;
font-size: 12px;
cursor: pointer;
font-family: var(--font);
}
@@ -407,16 +346,17 @@
border: 1px solid var(--border);
border-radius: 4px;
color: var(--amber);
padding: 8px 16px;
padding: 14px 24px;
font-family: var(--font);
font-size: 12px;
font-size: 14px;
cursor: pointer;
margin-bottom: 20px;
text-transform: uppercase;
letter-spacing: 1px;
min-height: 50px;
}
#handout-overlay-content {
font-size: 15px;
font-size: 16px;
line-height: 1.9;
color: #d4c090;
white-space: pre-wrap;
@@ -427,35 +367,68 @@
#handout-overlay-content.terminal {
font-family: 'Courier New', monospace;
color: #00cc99;
font-size: 13px;
font-size: 14px;
background: #060d0d;
padding: 20px;
border-radius: 6px;
}
/* REFERENCE SCREEN */
.ref-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
margin-bottom: 12px;
/* NPC PORTRAIT FULLSCREEN */
#portrait-overlay {
display: none;
position: fixed;
inset: 0;
background: #000;
z-index: 1100;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
.ref-table th {
#portrait-overlay.active { display: flex; }
#portrait-overlay-img {
width: 100%;
flex: 1;
object-fit: contain;
object-position: top center;
}
#portrait-overlay-bar {
width: 100%;
background: rgba(0,0,0,0.9);
border-top: 1px solid var(--border);
padding: 14px 20px;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
#portrait-overlay-name { font-family: var(--font); font-size: 14px; color: var(--text-bright); text-transform: uppercase; letter-spacing: 2px; }
#portrait-overlay-close {
background: var(--surface2);
color: var(--text-dim);
font-size: 10px;
border: 1px solid var(--border);
border-radius: 4px;
color: var(--amber);
padding: 12px 22px;
font-family: var(--font);
font-size: 13px;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 1px;
padding: 7px 10px;
min-height: 46px;
}
/* REFERENCE SCREEN */
.ref-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-bottom: 14px; }
.ref-table th {
background: var(--surface2);
color: var(--text);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 1px;
padding: 9px 10px;
text-align: left;
border-bottom: 1px solid var(--border);
}
.ref-table td {
padding: 7px 10px;
border-bottom: 1px solid var(--border);
vertical-align: top;
line-height: 1.4;
}
.ref-table td { padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: top; line-height: 1.5; }
.ref-table tr:last-child td { border-bottom: none; }
.ref-table .highlight { color: var(--amber); }
.ref-table .cyan { color: var(--cyan); }
@@ -471,7 +444,27 @@
overflow: hidden;
border: 1px solid var(--border);
background: #0a0a0f;
cursor: pointer;
position: relative;
}
.npc-portrait::after {
content: "TAP TO SHOW";
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: rgba(0,0,0,0.72);
color: var(--text-dim);
font-family: var(--font);
font-size: 9px;
text-align: center;
padding: 5px 2px;
letter-spacing: 1px;
text-transform: uppercase;
opacity: 0;
transition: opacity 0.2s;
}
.npc-portrait:active::after { opacity: 1; }
.npc-portrait svg { display: block; }
.npc-portrait img { display: block; }
.npc-card-inner { display: flex; gap: 12px; align-items: flex-start; }
@@ -481,19 +474,19 @@
.stat-block {
background: var(--surface2);
border-radius: 4px;
padding: 10px;
margin: 8px 0;
font-size: 12px;
line-height: 1.8;
padding: 12px;
margin: 10px 0;
font-size: 13px;
line-height: 1.9;
}
.stat-block-row { color: var(--text-dim); margin-bottom: 2px; }
.stat-block-row span { color: var(--text); }
.stat-block-row { color: var(--text); margin-bottom: 2px; }
.stat-block-row span { color: var(--text-bright); }
/* ALERT BANNER */
#alert-banner {
display: none;
padding: 10px 12px;
font-size: 13px;
padding: 12px;
font-size: 14px;
font-weight: bold;
text-align: center;
text-transform: uppercase;
@@ -501,31 +494,28 @@
animation: pulse 1s infinite;
}
#alert-banner.amber { background: rgba(255,183,0,0.2); color: var(--amber); border-bottom: 1px solid var(--amber); }
#alert-banner.red { background: rgba(255,61,61,0.2); color: var(--red); border-bottom: 1px solid var(--red); }
#alert-banner.red { background: rgba(255,68,68,0.2); color: var(--red); border-bottom: 1px solid var(--red); }
#alert-banner.active { display: block; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.6; } }
/* ACT SELECTOR */
.act-tabs {
display: flex;
gap: 6px;
margin-bottom: 12px;
overflow-x: auto;
padding-bottom: 4px;
}
.act-tabs { display: flex; gap: 8px; margin-bottom: 14px; overflow-x: auto; padding-bottom: 4px; }
.act-tab {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 20px;
padding: 6px 14px;
padding: 10px 18px;
font-family: var(--font);
font-size: 11px;
font-size: 12px;
color: var(--text-dim);
cursor: pointer;
white-space: nowrap;
text-transform: uppercase;
letter-spacing: 1px;
flex-shrink: 0;
min-height: 42px;
display: flex;
align-items: center;
}
.act-tab.active { border-color: var(--cyan); color: var(--cyan); }
.act-tab:active { background: var(--surface2); }
@@ -536,12 +526,12 @@
.goal-box {
background: var(--surface2);
border-left: 3px solid var(--cyan);
padding: 10px 12px;
margin-bottom: 12px;
font-size: 12px;
color: var(--text-dim);
padding: 12px 14px;
margin-bottom: 14px;
font-size: 13px;
color: var(--text);
border-radius: 0 var(--radius) var(--radius) 0;
line-height: 1.5;
line-height: 1.6;
}
.goal-box strong { color: var(--cyan); }
@@ -551,30 +541,28 @@
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
/* MODAL */
#san-modal {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.85);
z-index: 900;
align-items: center;
justify-content: center;
padding: 20px;
}
#san-modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.88); z-index: 900; align-items: center; justify-content: center; padding: 20px; }
#san-modal.active { display: flex; }
#san-modal-inner {
background: var(--surface);
border: 1px solid var(--red);
border-radius: var(--radius);
padding: 20px;
max-width: 400px;
#san-modal-inner { background: var(--surface); border: 1px solid var(--red); border-radius: var(--radius); padding: 22px; max-width: 400px; width: 100%; }
#san-modal-title { color: var(--red); font-size: 14px; font-weight: bold; text-transform: uppercase; letter-spacing: 2px; margin-bottom: 16px; }
#san-modal-close {
background: var(--surface2);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text);
padding: 14px 20px;
font-family: var(--font);
font-size: 13px;
cursor: pointer;
margin-top: 16px;
width: 100%;
text-transform: uppercase;
letter-spacing: 1px;
min-height: 50px;
}
#san-modal-title { color: var(--red); font-size: 13px; font-weight: bold; text-transform: uppercase; letter-spacing: 2px; margin-bottom: 14px; }
#san-modal-close { background: var(--surface2); border: 1px solid var(--border); border-radius: 4px; color: var(--text-dim); padding: 8px 16px; font-family: var(--font); font-size: 12px; cursor: pointer; margin-top: 14px; width: 100%; text-transform: uppercase; letter-spacing: 1px; }
.separator { height: 1px; background: var(--border); margin: 12px 0; }
.small-label { font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; }
.separator { height: 1px; background: var(--border); margin: 14px 0; }
.small-label { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; }
.dim { color: var(--text-dim); }
.bright { color: var(--text-bright); }
.cyan-text { color: var(--cyan); }
@@ -584,6 +572,7 @@
.bold { font-weight: bold; }
.mt8 { margin-top: 8px; }
.mb8 { margin-bottom: 8px; }
.italic { font-style: italic; }
</style>
</head>
<body>
@@ -1145,6 +1134,15 @@
<div id="handout-overlay-content"></div>
</div>
<!-- NPC PORTRAIT FULLSCREEN OVERLAY -->
<div id="portrait-overlay">
<img id="portrait-overlay-img" src="" alt="NPC portrait">
<div id="portrait-overlay-bar">
<span id="portrait-overlay-name"></span>
<button id="portrait-overlay-close" onclick="closePortraitOverlay()">✕ Close</button>
</div>
</div>
<!-- SAN QUICK MODAL -->
<div id="san-modal">
<div id="san-modal-inner">
@@ -1471,6 +1469,20 @@ function checkCheckpoints() {
}
}
// ===== PORTRAIT FULLSCREEN =====
function openPortraitOverlay(imgSrc, name, event) {
event.stopPropagation();
const overlay = document.getElementById('portrait-overlay');
document.getElementById('portrait-overlay-img').src = imgSrc;
document.getElementById('portrait-overlay-name').textContent = name;
overlay.classList.add('active');
document.body.style.overflow = 'hidden';
}
function closePortraitOverlay() {
document.getElementById('portrait-overlay').classList.remove('active');
document.body.style.overflow = '';
}
// ===== NAVIGATION =====
function navTo(screen) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
@@ -1503,15 +1515,22 @@ function switchRef(id, btn) {
// ===== BUILD NPC CARDS =====
function buildNPCs() {
const container = document.getElementById('npc-list');
container.innerHTML = NPCS.map((npc, i) => `
container.innerHTML = NPCS.map((npc, i) => {
// Extract img src from portrait HTML for the fullscreen handler
const srcMatch = npc.portrait ? npc.portrait.match(/src="([^"]+)"/) : null;
const imgSrc = srcMatch ? srcMatch[1] : '';
const tapHandler = imgSrc
? `onclick="openPortraitOverlay('${imgSrc}', '${npc.name}', event)"`
: '';
return `
<div class="card">
<div class="card-header" onclick="toggleCard(this)" style="align-items:flex-start; gap:10px;">
<div class="npc-portrait">${npc.portrait || ''}</div>
<div class="npc-portrait" ${tapHandler}>${npc.portrait || ''}</div>
<div style="flex:1; min-width:0;">
<div class="card-title">${npc.name}</div>
<div class="card-subtitle">${npc.role}</div>
<div class="card-subtitle" style="margin-top:3px; color:var(--text-dim);">${npc.act}</div>
<span class="card-tag disp-${npc.disp}" style="display:inline-block; margin-top:6px;">${npc.dispLabel}</span>
<span class="card-tag disp-${npc.disp}" style="display:inline-block; margin-top:8px;">${npc.dispLabel}</span>
</div>
<span class="chevron" style="margin-top:4px;">▼</span>
</div>
@@ -1523,10 +1542,10 @@ function buildNPCs() {
<div class="label">What They Know</div>
<div class="value">${npc.knows}</div>
<div class="label">Stat Block</div>
<div class="stat-block" style="white-space:pre-line;font-size:11px;color:var(--text-dim);">${npc.stats}</div>
<div class="stat-block" style="white-space:pre-line;font-size:12px;">${npc.stats}</div>
</div>
</div>
`).join('');
</div>`;
}).join('');
}
// ===== BUILD CLUE TRACKER =====