/* NetHack web console — retro roguelike theme.
   Dark dungeon-tile gray background, pastel accents, monospace everywhere. */

:root{
  --bg:#15161c;
  --tile-a:#1a1b22;
  --tile-b:#1e1f28;
  --panel:#181922;
  --panel-2:#13141b;
  --line:#2c2e3a;
  --line-soft:#23242f;
  /* Border for text input fields. --line (1.3:1 on the dark fills) is too faint
     to mark a field boundary for low-vision users; an empty input has no content
     to identify it, so its border must carry 3:1 non-text contrast (WCAG 1.4.11)
     against the field fill AND the panel. #646780 clears 3:1 on both. */
  --ctl-border:#646780;
  --ink:#d7d8e0;
  --ink-dim:#9a9cad;     /* was #8a8c9c — lifted for WCAG AA on the dark bg */
  --ink-faint:#83859a;   /* was #5d5f6e — lifted to ~4.6:1 contrast */
  --focus:#ffe08a;       /* keyboard focus ring (matches hero gold) */
  /* pastel accents */
  --hero:#ffe08a;     /* @ hero / gold */
  --stairs:#9fe8ff;   /* > < stairs */
  --item:#ffb3d9;     /* items */
  --monster:#c9a9ff;  /* monsters / letters */
  --wall:#b9bccb;     /* walls */
  --floor:#5b6072;    /* floor */
  --good:#9ce6b0;     /* accept / green */
  --warn:#ffb27a;     /* reset / orange */
  --danger:#ff8a8a;   /* record / red */
}

*{box-sizing:border-box}
html,body{height:100%}
/* The nav is position:sticky;top:0 (46px). Offset anchor/focus scrolling by its
   height so the skip-link target (<main tabindex=-1>) and any in-page anchor
   land BELOW the bar instead of being hidden under it. */
html{scroll-padding-top:54px}
body{
  margin:0;
  color:var(--ink);
  font-family:"DejaVu Sans Mono","Menlo","Consolas",monospace;
  font-size:14px;
  background:
    repeating-linear-gradient(0deg, var(--tile-a) 0 24px, var(--tile-b) 24px 48px),
    repeating-linear-gradient(90deg, rgba(0,0,0,0.18) 0 24px, rgba(255,255,255,0.012) 24px 48px),
    var(--bg);
}

/* ---------- nav bar ---------- */
#nav{
  display:flex;align-items:center;gap:4px;
  padding:0 14px;height:46px;
  background:linear-gradient(180deg,#1c1d27,#101119);
  border-bottom:2px solid var(--line);
  box-shadow:0 2px 0 #0a0a10, 0 6px 16px rgba(0,0,0,.4);
  position:sticky;top:0;z-index:20;
}
#nav .brand{
  color:var(--hero);font-weight:bold;letter-spacing:1px;
  margin-right:16px;text-decoration:none;text-shadow:0 0 8px rgba(255,224,138,.25);
}
#nav .brand .glyph{color:var(--stairs);margin-right:6px}
#nav a.link{
  color:var(--ink-dim);text-decoration:none;padding:7px 13px;border-radius:4px;
  border:1px solid transparent;font-size:13px;letter-spacing:.5px;
}
#nav a.link:hover{color:var(--ink);background:#23242f;border-color:var(--line)}
#nav a.link.active{color:#10111a;background:var(--stairs);border-color:var(--stairs);font-weight:bold}
#nav .spacer{flex:1}

/* ---------- generic ---------- */
a{color:var(--stairs)}
h1,h2,h3{font-weight:bold}
/* Section headings are <h2> (one level under each page's <h1>) but keep the
   compact look — explicit font-size so <h2> doesn't balloon to the UA default. */
h2,h3{color:var(--good);margin:14px 0 6px;border-bottom:1px solid var(--line);padding-bottom:3px;letter-spacing:.5px;font-size:15px}
.wrap{padding:18px 22px}
.screen{
  /* Scale the 79-col grid up on wider viewports so it fills the main column
     instead of sitting small in a corner; capped so it still fits a ~1440px
     laptop beside the 468px sidebar, and floored at the readable 15px. */
  font-size:clamp(15px, 1.55vw, 21px);line-height:1.15;white-space:pre;letter-spacing:0;
  outline:1px solid var(--line);background:#0c0d12;padding:6px 8px;border-radius:3px;
  box-shadow:inset 0 0 24px rgba(0,0,0,.6);
  /* The 79-col map is ~727px wide and never wraps; scroll it WITHIN its column
     at every width. Without this, between ~860px and ~1195px the map + the 468px
     sidebar exceed the viewport and the whole page scrolled horizontally on
     common laptops (1024/1152px). Paired with .maincol min-width:0 below. */
  overflow-x:auto;
}

/* ---------- page layout (map + traces) ---------- */
/* min-height fills the viewport below the 46px nav so the main column has room
   to center its content vertically (no dead bottom-left quadrant). */
.page{display:flex;min-height:calc(100vh - 46px)}
/* flex:1 makes the main column take all width left of the sidebar (no empty
   strip on the right); it then centers the game console block both axes.
   min-width:0 lets it shrink below the grid's width so the grid's own
   overflow-x scroll engages instead of widening the page. */
.maincol{flex:1;min-width:0;padding:14px 16px;display:flex;flex-direction:column;
  align-items:center;justify-content:center}
/* The console = message + screen + status + hint as one block, sized to the
   grid and centered as a unit so the status/message line up with the map. */
.console{display:flex;flex-direction:column;min-width:0;max-width:100%}
/* min-height (not a fixed height): a long NetHack message wraps and grows the
   box instead of overflowing onto the game screen below it. */
#message{min-height:18px;color:#fff;margin-bottom:5px}
/* pre-wrap preserves the multi-space field separators (HP .. AC .. Dlvl), which
   default white-space would collapse to single spaces, while still wrapping if a
   stat gets huge (e.g. $999999) so it never overflows. */
#status,#t-status{min-height:18px;margin-top:8px;color:var(--ink);white-space:pre-wrap}
#hint{color:var(--ink-faint);margin-top:10px;font-size:12px;max-width:640px}

/* ---------- knob sidebar ---------- */
/* container-type lets #groups respond to the sidebar's OWN width: between ~860
   and ~1230px the flex layout squishes this fixed 468px panel (e.g. a half-screen
   browser window), and a viewport media query can't see that. */
#side{
  width:468px;padding:14px;border-left:2px solid var(--line);
  background:linear-gradient(180deg,var(--panel),var(--panel-2));
  overflow-y:auto;max-height:calc(100vh - 46px);
  container-type:inline-size;
}
/* Two-column knob grid: h2 group headings span the full width; each .knob is a
   single cell with its label stacked above the slider+number so a half-width
   column stays readable. */
#groups{display:grid;grid-template-columns:1fr 1fr;column-gap:14px;row-gap:2px;align-items:start}
#groups h2{grid-column:1/-1}
/* Collapse to one column once the sidebar itself is too narrow for two readable
   knob cells, regardless of viewport width (catches the flex-squish range). */
@container (max-width: 380px){ #groups{grid-template-columns:1fr} }
.knob{display:flex;align-items:center;flex-wrap:wrap;margin:6px 0;gap:4px 6px}
.knob .name{flex-basis:100%;color:var(--hero);font-size:12px}
.knob .name .rst{color:var(--warn);font-size:10px}
.knob input[type=range]{flex:1;min-width:0;accent-color:var(--stairs)}
.knob input.num{width:48px;min-height:24px;background:#10111a;color:var(--good);border:1px solid var(--ctl-border);text-align:right;border-radius:3px;padding:2px 4px}
/* bool toggles keep label + switch on one line within the cell */
.knob .sw{margin-left:auto}
.knob .note{flex-basis:100%;color:var(--ink-faint);font-size:10px;margin-left:0}

/* toggle switch */
.sw{position:relative;width:42px;height:24px;display:inline-block}
.sw input{opacity:0;width:0;height:0}
.sw span{position:absolute;inset:0;background:#383a48;border-radius:20px;cursor:pointer;transition:.15s}
.sw span:before{content:"";position:absolute;height:14px;width:14px;left:3px;top:5px;background:var(--ink);border-radius:50%;transition:.15s}
.sw input:checked + span{background:var(--good)}
.sw input:checked + span:before{transform:translateX(22px);background:#0c0d12}

#seedrow{margin:16px 0 8px;color:var(--ink-dim)}
#seed{width:84px;min-height:24px;background:#10111a;color:#fff;border:1px solid var(--ctl-border);border-radius:3px;padding:3px 5px}
button.act-btn{
  background:linear-gradient(180deg,#2f6f4a,#244e38);color:#eafff0;border:1px solid #1c3b2a;
  padding:9px 12px;cursor:pointer;width:100%;font-size:13px;margin-top:7px;border-radius:4px;
  letter-spacing:.5px;text-shadow:0 1px 0 #0008;
}
button.act-btn:hover{filter:brightness(1.12)}
button.act-btn:disabled{opacity:.45;cursor:not-allowed;filter:none}
#markrow{display:flex;gap:7px}
#markrow .act-btn{width:auto;flex:1}
#markbtn{background:linear-gradient(180deg,#3a5a8c,#27406a);border-color:#1c2f52}
#restorebtn{background:linear-gradient(180deg,#7a5fa0,#553f74);border-color:#3d2c54}
#markstat{color:var(--ink-dim);font-size:12px;min-height:16px;margin-top:4px}
#reset.dirty{background:linear-gradient(180deg,#a8602e,#7c4521);border-color:#5c3318}
.dirtyflag{font-weight:bold;letter-spacing:0}
#recbtn.on{background:linear-gradient(180deg,#a83a3a,#7c2626);border-color:#5c1c1c}
#recstat{color:var(--danger);font-size:12px;min-height:16px;margin-top:4px;word-break:break-all}

/* ---------- state-modify panel ---------- */
#modify{margin-top:14px;padding-top:10px;border-top:1px solid var(--line)}
.mrow{display:flex;align-items:center;gap:6px;margin:5px 0}
.mrow .mname{width:96px;color:var(--hero);font-size:12px}
.mrow .mnum{flex:1;min-width:0;min-height:24px;background:#10111a;color:var(--good);border:1px solid var(--ctl-border);text-align:right;border-radius:3px;padding:3px 5px}
.mbtn{background:linear-gradient(180deg,#2f6f4a,#244e38);color:#eafff0;border:1px solid #1c3b2a;
  padding:4px 10px;min-height:24px;cursor:pointer;font-size:12px;border-radius:3px;text-shadow:0 1px 0 #0008}
.mbtn.wide{flex:1}
.mbtn:hover{filter:brightness(1.12)}
#modstat{color:var(--warn);font-size:11px;min-height:14px;margin-top:4px}

/* ---------- traces ---------- */
#t-list{width:312px;border-right:2px solid var(--line);padding:12px;overflow-y:auto;max-height:calc(100vh - 46px);background:var(--panel-2)}
/* .f rollout items are <button>s — reset native chrome to the old list look,
   full-width and left-aligned, while keeping keyboard focus + activation. */
#t-list .f{display:block;width:100%;text-align:left;padding:6px;cursor:pointer;
  font-size:12px;font-family:inherit;color:var(--ink);background:none;
  /* trace names are slash-paths (no spaces); wrap them so a long/deep path
     doesn't overflow the fixed-width list. */
  overflow-wrap:anywhere;
  border:0;border-bottom:1px solid var(--line-soft);border-radius:3px}
#t-list .f:hover{background:#23242f}
#t-list .f[aria-current=true]{background:#23242f;color:var(--stairs);font-weight:bold}
#resumestat{margin-left:8px;color:var(--ink-dim);font-size:12px}
.t-main{padding:14px 16px;flex:1;min-width:0}
#scrub{width:100%;accent-color:var(--stairs)}
#t-turninfo{color:var(--ink-faint);font-size:12px}
#t-msgs{color:var(--good);margin:5px 0;min-height:18px}
#t-llm{margin-top:12px;font-size:12px}
#t-llm .lbl{color:var(--good)}
#t-llm pre{white-space:pre-wrap;overflow-wrap:break-word;background:var(--panel-2);padding:7px;border:1px solid var(--line);max-height:220px;overflow:auto;border-radius:3px}

/* ---------- landing ---------- */
.landing{max-width:980px;margin:0 auto;padding:26px 22px}
.landing .title{font-size:28px;color:var(--hero);letter-spacing:2px;text-shadow:0 0 14px rgba(255,224,138,.25)}
.landing .title .glyph{color:var(--stairs)}
.landing .lede{color:var(--ink-dim);line-height:1.55;margin:14px 0;max-width:760px}
.landing .lede b{color:var(--ink)}
.landing .lede code{color:var(--item);background:#10111a;padding:1px 5px;border-radius:3px}

.cards{display:flex;gap:16px;flex-wrap:wrap;margin:22px 0 8px}
.card{
  flex:1;min-width:230px;text-decoration:none;color:var(--ink);
  background:linear-gradient(180deg,var(--panel),var(--panel-2));
  border:1px solid var(--line);border-radius:8px;padding:20px;
  box-shadow:0 3px 0 #0a0a10,0 8px 22px rgba(0,0,0,.35);transition:.12s;
}
.card:hover{transform:translateY(-3px);border-color:var(--stairs);box-shadow:0 6px 0 #0a0a10,0 12px 28px rgba(0,0,0,.45)}
.card .cglyph{font-size:30px;line-height:1}
.card .ctitle{font-size:17px;margin:10px 0 6px;color:var(--hero);letter-spacing:1px}
.card .cdesc{color:var(--ink-dim);font-size:12.5px;line-height:1.5}
.card.c-map .cglyph{color:var(--hero)}
.card.c-obs .cglyph{color:var(--item)}
.card.c-trace .cglyph{color:var(--stairs)}

/* shared hint text (gallery "loading…"/"none found", obs help) */
.obs-hint{color:var(--ink-faint);font-size:11px;margin-top:6px;line-height:1.4}
#gallery h2{margin-top:26px}
/* Pause/hide control for the auto-playing demo GIFs (WCAG 2.2.2). Small,
   subtle, theme-matched; 24px min target (WCAG 2.5.8). */
#gif-toggle{margin:0 0 10px;min-height:24px;background:#23242f;color:var(--ink);
  border:1px solid var(--line);border-radius:3px;padding:4px 11px;font-family:inherit;
  font-size:12px;letter-spacing:.5px;cursor:pointer}
#gif-toggle:hover{background:#2b2d3a}
/* Two demos per row; collapse to one column on narrow viewports (WCAG 1.4.10). */
.gif-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media (max-width:680px){ .gif-grid{grid-template-columns:1fr} }
/* min-width:0 lets the flex cell shrink below the GIF's intrinsic width so a
   wide demo (the served gif_*.gif are 560–648px) doesn't force horizontal page
   scroll on a narrow viewport (WCAG 1.4.10 reflow). */
.gif-cell{display:inline-block;vertical-align:top;min-width:0;background:var(--panel-2);border:1px solid var(--line);border-radius:6px;padding:8px}
.gif-cell .glabel{color:var(--hero);font-size:12px;margin-bottom:5px}
/* max-width:100% pairs with max-height; with auto width/height the browser fits
   both bounds while preserving aspect ratio, so the GIF scales down to the cell
   on small screens instead of overflowing. */
.gif-cell img{max-width:100%;max-height:280px;display:block;background:#000;border:1px solid var(--line-soft);border-radius:3px}

/* ---------- accessibility ---------- */
/* Screen-reader-only: present for assistive tech, hidden visually. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}
/* Skip link: off-screen until focused, then pinned top-left. */
.skip-link{
  position:absolute;left:8px;top:-44px;z-index:50;
  background:var(--stairs);color:#10111a;padding:8px 14px;border-radius:4px;
  font-weight:bold;text-decoration:none;transition:top .15s;
}
.skip-link:focus{top:8px}

/* Visible keyboard focus everywhere (mouse clicks stay clean via :focus-visible). */
a:focus-visible,button:focus-visible,input:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible,.sw input:focus-visible + span{
  outline:2px solid var(--focus);outline-offset:2px;border-radius:3px;
}
/* The skip-link target <main tabindex="-1"> receives focus programmatically; it's
   a jump destination, not a control, so don't ring the whole content block. */
main[tabindex="-1"]:focus{outline:none}
.screen:focus-visible{outline:2px solid var(--focus);outline-offset:0}
#nav a.link:focus-visible{outline-offset:-2px}
/* The active link has a light (stairs) background, so the gold focus ring drawn
   inside it would be ~1:1 contrast (invisible). Use a dark ring there instead. */
#nav a.link.active:focus-visible{outline-color:#10111a}

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{transition:none !important;animation:none !important}
  .card:hover{transform:none}
}

/* High-contrast preference: brighten the dim text + borders and thicken the
   focus ring so low-vision users get more separation than the default theme. */
@media (prefers-contrast: more){
  :root{--ink-dim:#c4c6d4;--ink-faint:#b6b8c6;--line:#4a4d5e;--line-soft:#3a3c4a;
        /* lift the input-field border too (base 3.4:1 -> ~6:1) so form fields
           stay maximally distinct in high-contrast mode, like the other borders */
        --ctl-border:#8e91a6}
  a:focus-visible,button:focus-visible,input:focus-visible,
  [tabindex]:not([tabindex="-1"]):focus-visible,.sw input:focus-visible + span,.screen:focus-visible{
    outline-width:3px;
  }
  #hint,.knob .note,.obs-hint,#t-turninfo{color:var(--ink-dim)}
}

/* ---------- responsive (WCAG 1.4.10 reflow) ----------
   Below ~860px the fixed-width side panels would force horizontal scroll, so
   stack the two-pane map/tracer layouts vertically and let the panels go
   full-width. The game grid itself can still scroll horizontally (a literal
   character map is exempt), but the controls never do. */
@media (max-width: 860px){
  .page{flex-direction:column}
  /* knob sidebar moves below the map */
  #side{width:auto;max-height:none;border-left:0;border-top:2px solid var(--line)}
  /* tracer rollout list moves above the viewer */
  #t-list{width:auto;border-right:0;border-bottom:2px solid var(--line);max-height:40vh}
  /* (.screen now scrolls its own overflow-x at every width — see the base rule) */
}
@media (max-width: 520px){
  /* single-column knobs when even half-width cells get too tight */
  #groups{grid-template-columns:1fr}
  .wrap,.landing{padding-left:14px;padding-right:14px}
  .cards{gap:12px}
}
/* nav wraps instead of overflowing on small screens */
@media (max-width: 560px){
  #nav{height:auto;flex-wrap:wrap;padding:6px 10px;gap:2px}
  #nav .spacer{flex-basis:100%;height:0}
}

/* ---- curriculum tour mode (map page) ---- */
#moderow{display:flex;align-items:center;gap:8px;margin:0 0 10px}
#moderow label{color:var(--ink-dim);font-size:13px}
#moderow select{flex:1;background:var(--panel-2);color:var(--ink);
  border:1px solid var(--ctl-border);border-radius:6px;padding:5px 8px;font:inherit}
#currpanel{border:1px solid var(--line);border-radius:8px;background:var(--panel-2);
  padding:10px 12px;margin:0 0 12px}
#currpanel h2{margin:0 0 6px;font-size:14px}
#currfloor{color:var(--stairs);font-weight:600;margin-bottom:8px}
.currbtns{display:flex;align-items:center;flex-wrap:wrap;gap:6px}
.currbtns .mname{color:var(--ink-dim);font-size:13px;margin-right:2px}
.currbtns .mbtn{min-width:30px}
#currstat{color:var(--ink-dim);font-size:12px;min-height:1em;margin-top:6px}

/* ---------- popup + inventory boxes (under the game screen) ---------- */
/* #popup mirrors whatever prompt/menu the engine is showing on the tty; it is
   hidden whenever nothing is pending. #inv is always on and refreshes each turn. */
#popup{
  margin-top:8px;white-space:pre;font-size:13px;line-height:1.2;
  color:var(--ink);background:#0c0d12;border:1px solid var(--stairs);border-radius:3px;
  padding:7px 9px;max-height:230px;overflow:auto;
  box-shadow:0 0 0 1px rgba(159,232,255,.15), inset 0 0 18px rgba(0,0,0,.5);
}
#invbox{margin-top:8px;border:1px solid var(--line);border-radius:3px;background:var(--panel-2)}
#invbox > summary{
  cursor:pointer;padding:5px 9px;color:var(--good);font-size:12px;letter-spacing:.5px;
  border-bottom:1px solid var(--line-soft);
}
#invbox > summary::marker{color:var(--ink-faint)}
#inv{padding:6px 9px;max-height:200px;overflow:auto;font-size:12px;line-height:1.45}
#inv .invgrp{color:var(--hero);font-size:11px;letter-spacing:.5px;margin:5px 0 2px}
#inv .invgrp:first-child{margin-top:0}
#inv .invitem{color:var(--ink);white-space:normal;overflow-wrap:anywhere}
#inv .invlet{color:var(--stairs);display:inline-block;min-width:1.2em}
#inv .invempty{color:var(--ink-faint)}

/* key reference under the inventory + the `i` attention flash */
#hint .keys{border-collapse:collapse;margin:6px 0 4px}
#hint .keys td{padding:1px 10px 1px 0;vertical-align:top;color:var(--ink-dim)}
#hint .keys td:first-child{white-space:nowrap;color:var(--ink)}
#hint kbd{
  font:inherit;font-size:11px;background:#10111a;color:var(--stairs);
  border:1px solid var(--ctl-border);border-radius:3px;padding:0 4px;margin-right:2px;
}
#hint .khint{display:block;margin-top:4px;color:var(--ink-faint)}
#invbox.flash{animation:invflash 1s ease-out}
@keyframes invflash{
  0%{border-color:var(--hero);box-shadow:0 0 0 2px rgba(255,224,138,.35)}
  100%{border-color:var(--line);box-shadow:none}
}
@media (prefers-reduced-motion: reduce){ #invbox.flash{animation:none} }
