/* ---------------------------------------------------------------
   THE CHOSEN ONE

   The canvas is the page: fixed, sized in JS to cover the window, so
   there are never letterbox bars. Everything else is an overlay in the
   pixel-RPG chrome — dark navy plates, gold rules, brown scrolls.
----------------------------------------------------------------*/

:root{
  --void:    #0c0f18;
  --plate:   #161d31;   /* panel fill        */
  --plate-2: #101628;   /* panel fill, inner */
  --slot:    #1d2740;   /* item slot         */
  --gold:    #e8b13a;
  --gold-dk: #8a6a22;
  --brown:   #6b3b2f;   /* description scroll */
  --brown-b: #9a6048;
  --paper:   #ece7dc;
  --muted:   #9aa4bd;
  --green:   #86cf52;
  --blue:    #6aa8e6;

  --font: "Press Start 2P", "Courier New", monospace;
}

*,*::before,*::after{ box-sizing:border-box; }

html,body{ height:100%; }

/* Safari on iOS inflates text it decides is "body content", picking a
   boost per block from that block's width and how much text is in it. It
   is why two dialogue boxes with identical CSS came back from a real phone
   at wildly different sizes - the four-line one left alone, the seven-line
   one blown up until it covered the game. Nothing in here is an article to
   be made readable; every size is deliberate. */
html{
  -webkit-text-size-adjust:100%;
  text-size-adjust:100%;
}

body{
  margin:0;
  background:var(--void);
  color:var(--paper);
  font-family:var(--font);
  overflow:hidden;                 /* the game is the whole page */
  -webkit-font-smoothing:antialiased;
  -webkit-tap-highlight-color:transparent;
}

@media (prefers-reduced-motion: reduce){
  *{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
}

/* ---------------------------------- the game surface
   position/size are written by the engine's fit(); it scales to cover
   the viewport and biases the crop upward so the ground always shows. */
#game{
  position:fixed;
  display:block;
  image-rendering:pixelated;
  image-rendering:crisp-edges;
  background:var(--void);
}
#game:focus-visible{ outline:none; }

/* ---------------------------------- full-screen overlays */
.screen{
  position:fixed; inset:0;
  /* start, not centre, plus auto overflow: a plate taller than the window
     scrolls instead of hiding its own button below the fold. It still
     looks centred, because the body rule below re-centres what fits. */
  display:grid; place-items:start center; align-content:safe center;
  overflow-y:auto; -webkit-overflow-scrolling:touch;
  padding:20px;
  background:
    radial-gradient(120% 90% at 50% 45%, rgba(12,15,24,.72), rgba(12,15,24,.94));
  backdrop-filter:blur(2px);
  z-index:10;
}
.screen[hidden]{ display:none; }

/* ---------------------------------- loading
   The painted scene is the screen. It is a wide 1380x640 plate, so it is
   cover-fitted and anchored low - the road and the coach sit in the lower
   half, and that is what should survive a tall window. */
#loader{
  background:
    linear-gradient(180deg, rgba(8,10,16,.34) 0%, rgba(8,10,16,0) 34%,
                             rgba(8,10,16,.30) 68%, rgba(8,10,16,.88) 100%),
    url('../assets/ui/loading.gif') center 62% / cover no-repeat,
    var(--void);
  backdrop-filter:none;
  /* push the bar to the foot of the art rather than the middle of it */
  align-content:end;
  padding-bottom:min(11vh, 86px);
}
.bar{
  width:min(340px, 70vw);
  box-shadow:0 4px 18px rgba(0,0,0,.65);
  height:14px;
  background:var(--plate-2);
  border:2px solid var(--gold-dk);
  border-radius:3px;
  padding:2px;
  overflow:hidden;
}
.bar i{
  display:block; height:100%;
  width:0%;
  background:
    repeating-linear-gradient(90deg, rgba(0,0,0,.18) 0 1px, transparent 1px 4px),
    linear-gradient(180deg, #f2c85c, var(--gold) 60%, #b5851f);
  transition:width .18s linear;
}
.pct{
  margin:14px 0 0;
  text-shadow:0 2px 6px rgba(0,0,0,.9);
  font-size:14px;
  color:var(--gold);
  letter-spacing:.06em;
}

/* ---------------------------------- the RPG plate
   A dark panel, a gold rule inset from the edge, rounded corners —
   the frame the reference menus are built on. */
.plate{
  position:relative;
  width:min(680px, 100%);
  background:linear-gradient(180deg, var(--plate), var(--plate-2));
  border:2px solid var(--gold-dk);
  border-radius:14px;
  padding:34px 22px 22px;
  box-shadow:
    0 0 0 1px rgba(0,0,0,.6),
    inset 0 0 0 1px rgba(232,177,58,.10),
    0 26px 70px rgba(0,0,0,.65);
}
/* the inner gold rule */
.plate::before{
  content:"";
  position:absolute; inset:7px;
  border:1px solid rgba(232,177,58,.30);
  border-radius:9px;
  pointer-events:none;
}

.plate-title{
  position:absolute; top:-14px; left:50%;
  transform:translateX(-50%);
  display:flex; align-items:center; gap:12px;
  white-space:nowrap;
  font-size:15px;
  color:var(--gold);
  text-shadow:0 2px 0 #000;
  background:var(--void);
  padding:4px 14px;
  border-radius:6px;
}

.plate-body{ display:grid; gap:18px; }

/* ---------------------------------- the ability-slot grid */
.grid{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(96px,1fr));
  gap:10px;
}
.cell{
  background:var(--slot);
  border:1px solid #2c3a5e;
  border-radius:8px;
  padding:12px 8px;
  text-align:center;
  display:grid; gap:8px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.05);
}
.cell b{ font-size:10px; color:var(--paper); }
.cell span{ font-size:8px; color:var(--muted); }

/* ---------------------------------- the controls card
   Same slots as the keyboard grid above, laid out in a row each so that a
   line of prose fits beside the glyph. */
.keys{ list-style:none; padding:0; margin:0 0 4px; display:grid; gap:8px; }
.keys li{
  background:var(--slot);
  border:1px solid #2c3a5e;
  border-radius:8px;
  padding:11px 12px;
  display:grid; grid-template-columns:62px 1fr; gap:12px; align-items:center;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.05);
}
.keys b{ font-size:12px; color:var(--gold); text-align:center; }
.keys span{ font-size:8px; line-height:1.9; color:var(--muted); }
.dismiss{
  font-size:8px; line-height:1.9; color:var(--muted);
  text-align:center; margin:2px 0 4px;
}

/* Only offered where the arrows exist to be explained. */
.touch-only{ display:none; }
.touch .touch-only{ display:inline-block; }

/* ---------------------------------- no long-press on a phone
   Resting a thumb anywhere brought up iOS's select / copy / look-up
   bubble, and on a link its own menu on top of that. In the middle of a
   game that is only ever in the way: a long press here is someone holding
   an arrow down, not someone trying to quote the page. Nothing is lost by
   it - every contact detail is already a link, so the address is a tap
   rather than a copy. Listed out as well as set on the root because Safari
   does not reliably inherit either property into buttons.

   touch-action:manipulation turns off the double-tap-to-zoom wait, which
   otherwise swallows quick repeated taps of the same button. The pad keeps
   its own touch-action:none, so holding an arrow can never pan the page. */
.touch,
.touch button,
.touch a{
  -webkit-touch-callout:none;
  -webkit-user-select:none;
  user-select:none;
}
.touch img{ -webkit-user-drag:none; user-drag:none; }
.touch .tools button,
.touch .menu-btn,
.touch .btn,
.touch .x,
.touch .hood-tabs button,
.touch .doc a,
.touch .crt-grid .cell{
  -webkit-tap-highlight-color:transparent;
  touch-action:manipulation;
}

/* ---------------------------------- the brown description scroll */
.scroll{
  background:var(--brown);
  border:2px solid var(--brown-b);
  border-radius:8px;
  padding:16px 18px;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.25);
}
.scroll header{
  display:flex; align-items:baseline; justify-content:space-between; gap:14px;
  margin-bottom:12px;
}
.scroll h1{
  margin:0;
  font-size:13px;
  color:var(--gold);
  line-height:1.5;
}
.rank{ font-size:9px; color:#e6cdb6; }
.scroll p{
  margin:0;
  font-size:10px;
  line-height:2;
  color:var(--paper);
}
.scroll em{ font-style:normal; color:var(--green); }
.scroll em.gold{ color:var(--gold); }

/* ---------------------------------- buttons */
.row{ display:flex; gap:12px; flex-wrap:wrap; justify-content:center; }

.btn{
  font-family:var(--font); font-size:12px; line-height:1;
  background:linear-gradient(180deg, #f2c85c, var(--gold) 55%, #c08f22);
  color:#2a1d05;
  border:2px solid var(--gold-dk);
  border-radius:8px;
  padding:16px 22px;
  cursor:pointer;
  box-shadow:0 4px 0 #6d5117, 0 10px 20px rgba(0,0,0,.45);
  transition:transform .08s ease, box-shadow .08s ease;
}
.btn:hover{ transform:translateY(-1px); box-shadow:0 5px 0 #6d5117, 0 12px 22px rgba(0,0,0,.5); }
.btn:active{ transform:translateY(3px); box-shadow:0 1px 0 #6d5117; }

.btn.ghost{
  background:var(--slot);
  color:var(--paper);
  border-color:#33406a;
  box-shadow:0 4px 0 #0d1220;
}
.btn.ghost:hover{ border-color:var(--gold-dk); color:var(--gold); }

/* ---------------------------------- dialogue
   The same brown scroll the menus use, parked along the bottom edge. */
.say{
  position:fixed; left:50%;
  /* clear of the button bar, however many rows it has wrapped onto */
  bottom:calc(var(--tools-h, 44px) + 22px);
  transform:translateX(-50%);
  z-index:9;
  width:min(760px, calc(100vw - 32px));
  background:var(--brown);
  border:2px solid var(--brown-b);
  border-radius:10px;
  padding:16px 20px;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.25), 0 16px 40px rgba(0,0,0,.6);
  animation:rise .18s ease;
}
.say[hidden]{ display:none; }

/* who is talking, cut live out of the painting they are standing in */
.say{ display:flex; align-items:flex-start; }
/* The speaker is a bust standing at the left of the box, not a portrait in
   a frame: no plate, no border, no rounded window. Its base sits on the
   floor of the box and it is taller than the box is, so it rises past the
   top edge and laps a little over the left one - which is what stops the
   box reading as a rectangle with a picture stuck in it. It is out of the
   flex flow and positioned, so the text is laid out as though it were not
   there, and the room it needs is padding instead. The min-height gives it
   somewhere to stand however short the line is. The busts are square, so a
   square window shows all of one and never crops a face. */
.say{ min-height:118px; }
.say-face{
  position:absolute;
  left:-8px; bottom:2px;
  width:140px; height:140px;
  object-fit:contain; object-position:50% 100%;   /* stand it on its base */
  image-rendering:pixelated;
  background:none; border:0; border-radius:0; box-shadow:none;
  /* the only thing holding it off the brown, and off the art it overhangs */
  filter:drop-shadow(0 0 2px rgba(0,0,0,.7)) drop-shadow(0 3px 3px rgba(0,0,0,.55));
  pointer-events:none;
}
/* Only make room when somebody is actually pictured - the narrator has no
   bust, and the text should have the whole box when there is none. */
.say-face:not([hidden]) + .say-body{ padding-left:138px; }

/* Some stages put the box at the top of the screen, where there is nothing
   above it to rise into and the window edge would simply cut the head off.
   There the bust stays inside. */
.say.top .say-face{ left:12px; bottom:7px; width:104px; height:104px; }
.say.top .say-face:not([hidden]) + .say-body{ padding-left:122px; }
.say-face[hidden]{ display:none; }
.say-body{ flex:1 1 auto; min-width:0; }

.say header{
  display:flex; align-items:baseline; justify-content:space-between;
  gap:16px; margin-bottom:12px;
}
/* the subject leads; the speaker's name is the footnote */
.say h2{
  margin:0; font-size:12px; color:var(--gold); line-height:1.5;
}
.say header span{ font-size:8px; color:#e6cdb6; text-align:right; white-space:nowrap; }

/* Stages whose people stand low in the frame put the box at the top
   instead, so the box is never over the thing it is describing. */
.say.top{ bottom:auto; top:64px; animation:drop .18s ease; }
@keyframes drop{ from{ transform:translate(-50%,-10px); opacity:0 } }
.say p{
  margin:0; font-size:10px; line-height:2; color:var(--paper);
}
.say a{
  color:var(--gold);
  text-decoration:underline;
  text-underline-offset:3px;
}
.say a:hover{ color:#fff0c4; }
@keyframes rise{ from{ transform:translate(-50%,10px); opacity:0 } }

/* ---------------------------------- in-world prompt */
.toast{
  position:fixed; left:50%; bottom:120px;
  transform:translateX(-50%);
  z-index:8;
  font-size:11px;
  color:var(--paper);
  background:var(--brown);
  border:2px solid var(--brown-b);
  border-radius:8px;
  padding:12px 18px;
  white-space:nowrap;
  box-shadow:0 10px 24px rgba(0,0,0,.55);
  animation:pop .2s ease;
}
.toast[hidden]{ display:none; }
@keyframes pop{ from{ transform:translate(-50%,8px); opacity:0 } }

/* ---------------------------------- touch controls
   A four-way cross in the corner a controller would put it. One cluster
   rather than a split pad because all four arrows do something here: ◀ ▶
   walk, ▲ jumps and takes you through a gate, ▼ talks to whoever you are
   standing beside. */
.pad{
  position:fixed; left:10px; bottom:10px;
  z-index:9;
  display:none;
  grid-template-columns:repeat(3, 44px);
  grid-template-rows:repeat(3, 40px);
  gap:4px;
  touch-action:none;
}
.pad button{
  font-family:var(--font); font-size:11px;
  background:rgba(12,15,24,.72);
  color:var(--gold);
  border:2px solid rgba(232,177,58,.55);
  border-radius:8px;
  padding:0;
  text-shadow:0 1px 2px rgba(0,0,0,.8);
  cursor:pointer; touch-action:none;
  -webkit-user-select:none; user-select:none;
  -webkit-tap-highlight-color:transparent;
}
.pad button:active{ background:var(--gold); color:#2a1d05; }
.pad-u{ grid-area:1 / 2; }
.pad-l{ grid-area:2 / 1; }
.pad-r{ grid-area:2 / 3; }
.pad-d{ grid-area:3 / 2; }
.touch .pad{ display:grid; }

/* ---------------------------------- navigation
   Buttons over the game, in the same chrome as the plates. */
.nav, .tools{
  position:fixed; z-index:8;
  display:flex; flex-wrap:wrap; gap:8px;
}
.nav[hidden], .tools[hidden]{ display:none; }
.tools{
  right:12px; bottom:12px;
  z-index:11;                 /* always clickable, even mid-conversation */
  flex-wrap:wrap; justify-content:flex-end;
  max-width:calc(100vw - 24px);
}

/* the way back to the menu, and out of the game entirely, side by side */
.topleft{
  position:fixed; top:12px; left:12px; z-index:7;
  display:flex; gap:8px; flex-wrap:wrap;
}
.topleft[hidden]{ display:none; }
.menu-btn{
  font:inherit; font-size:9px; letter-spacing:.06em;
  color:var(--paper); cursor:pointer;
  background:linear-gradient(180deg, #2a3050, #1d2340);
  border:2px solid var(--gold-dk); border-radius:7px;
  padding:9px 13px;
  box-shadow:0 3px 0 rgba(0,0,0,.45);
}
.menu-btn[hidden]{ display:none; }
.menu-btn:hover{ border-color:var(--gold); color:#fff0c4; }
.menu-btn:active{ transform:translateY(2px); box-shadow:none; }

.nav button, .tools button{
  font-family:var(--font); font-size:9px; line-height:1;
  color:var(--paper);
  background:rgba(22,29,49,.92);
  border:2px solid var(--gold-dk);
  border-radius:7px;
  padding:10px 12px;
  cursor:pointer;
  box-shadow:0 3px 0 rgba(0,0,0,.5);
  transition:color .12s ease, border-color .12s ease, transform .08s ease;
}
.nav button:hover, .tools button:hover{
  color:var(--gold); border-color:var(--gold); transform:translateY(-1px);
}
.nav button:active, .tools button:active{ transform:translateY(2px); box-shadow:none; }

@media (max-width:640px){
  .tools button{ font-size:7px; padding:8px 9px; }
}

@media (max-width:560px){
  .say{ bottom:96px; padding:12px 14px; }
  .say h2{ font-size:10px; }
  .say p{ font-size:8px; line-height:1.9; }
  .plate{ padding:30px 14px 16px; }
  .plate-title{ font-size:11px; }
  .scroll p{ font-size:9px; line-height:1.9; }
}

/* ==================================================================
   PANELS — light document cards over the dark game.

   The in-world UI (dialogue, title cards, pause) stays in the pixel-RPG
   chrome. These are documents: white paper, big headings, real links.
   Two registers on purpose — one for the world, one for reading.
   ================================================================== */

:root{
  --paper-w:  #fdfdfb;
  --ink-d:    #17181d;
  --ink-m:    #4b4f5a;
  --ink-l:    #8b9099;
  --rule:     #e2e2dd;
}

.panel{ padding:0; align-items:start; }

/* ---------------------------------- the sheet */
.doc{
  position:relative;
  width:min(940px, 100%);
  max-height:100dvh;
  overflow-y:auto;
  background:var(--paper-w);
  color:var(--ink-d);
  border-radius:18px;
  padding:52px clamp(20px,5vw,60px) 60px;
  margin:20px auto;
  box-shadow:0 40px 90px rgba(0,0,0,.65);
  -webkit-overflow-scrolling:touch;
}
.doc.narrow{ width:min(680px, 100%); }
.doc.wide{ width:min(1180px, 100%); }

.doc h1{
  font-size:clamp(15px,2.4vw,22px);
  line-height:1.6;
  margin:34px 0 18px;
  color:var(--ink-d);
}
.doc h1.big{
  font-size:clamp(22px,4.6vw,44px);
  text-align:center;
  margin:6px 0 20px;
}
.doc h2{ font-size:clamp(14px,2.2vw,20px); margin:0 0 8px; line-height:1.5; }
.doc h3{ font-size:12px; margin:0 0 10px; }
.doc p{
  font-size:11px; line-height:2.1; color:var(--ink-m);
  margin:0 0 14px;
}
.doc p.lead{
  text-align:center; max-width:60ch; margin:0 auto 34px;
  color:var(--ink-m);
}
.doc p.role{ color:var(--ink-l); font-size:10px; margin-bottom:10px; }
.doc b{ color:var(--ink-d); font-weight:400; }
.doc a{ color:#1f6feb; text-decoration:underline; text-underline-offset:3px; }

/* the close cross, echoing the reference */
.x{
  position:absolute; top:14px; right:14px;
  z-index:3;
  font-family:var(--font); font-size:14px; line-height:1;
  width:44px; height:44px;
  color:#fff; background:#d9534f;
  border:3px solid #a33b38; border-radius:8px;
  cursor:pointer;
  box-shadow:0 4px 0 #7d2b29;
}
.x:hover{ background:#e2645f; }
.x:active{ transform:translateY(3px); box-shadow:none; }

/* ---------------------------------- lists */
.ticks{ list-style:none; padding:0; margin:0 0 20px; }
.ticks li{
  position:relative; padding-left:22px; margin-bottom:10px;
  font-size:11px; line-height:1.9; color:var(--ink-m);
}
.ticks li::before{
  content:"◆"; position:absolute; left:0; top:0;
  color:#c9a227; font-size:9px;
}
.ticks.two{ columns:2; column-gap:34px; }
@media (max-width:640px){ .ticks.two{ columns:1; } }

.tags{ list-style:none; display:flex; flex-wrap:wrap; gap:8px; padding:0; margin:14px 0 0; }
.tags li{
  font-size:8px; color:var(--ink-m);
  border:2px solid var(--rule); border-radius:5px;
  padding:6px 9px;
}

/* ---------------------------------- About: the id card */
.idcard{
  display:flex; align-items:center; gap:18px;
  background:#dbeafe;
  border-radius:12px;
  padding:16px 20px;
  margin-bottom:10px;
}
.portrait{
  width:80px; height:64px; flex:none;
  background-image:url("../assets/sprites/hero.png");
  background-repeat:no-repeat;
  background-position:0 0;
  image-rendering:pixelated;
  transform:scale(1.35);
  transform-origin:left center;
}
.idcard-who{ flex:1; min-width:0; margin-left:22px; }
.idcard-who h2{ margin:0 0 6px; font-size:clamp(12px,2vw,17px); }
.idcard-who p{ margin:0; font-size:9px; color:var(--ink-l); }
.idcard-link{ color:#0a66c2; flex:none; }

/* the "want to know more" footer box */
.ask{
  border:3px solid var(--ink-d);
  border-radius:4px;
  padding:22px;
  margin-top:34px;
  text-align:center;
}
.ask h3{ margin:0 0 8px; }
.ask p{ margin:0 0 14px; }
.ask .lnk{ color:#0a66c2; display:inline-block; }

.btn-doc{
  display:inline-block;
  font-family:var(--font); font-size:10px; line-height:1;
  color:var(--ink-d); background:#fff;
  border:3px solid var(--ink-d); border-radius:4px;
  padding:14px 18px;
  text-decoration:none;
  box-shadow:4px 4px 0 var(--ink-d);
  margin-top:8px;
}
.btn-doc:hover{ background:#f3f3ef; }
.btn-doc:active{ transform:translate(3px,3px); box-shadow:1px 1px 0 var(--ink-d); }

/* ---------------------------------- CV: the timeline */
.tl{ margin:10px 0 0; }
.tl-row{ display:flex; gap:20px; padding-bottom:30px; position:relative; }
.tl-row::before{
  content:""; position:absolute; left:29px; top:66px; bottom:0;
  width:4px; background:var(--ink-d);
}
.tl-row:last-child::before{ display:none; }
.tl-side{ flex:none; width:62px; text-align:center; }
.tl-logo{
  width:62px; height:62px;
  display:grid; place-items:center;
  font-size:13px; color:#fff;
  border-radius:6px;
}
.tl-logo.tata{ background:#1f4e8c; }
.tl-logo.jpm { background:#3f2a14; }
.tl-logo.bcg { background:#0b7a4b; font-size:10px; }
.tl-logo.del { background:#0f7b3e; }
.tl-logo.mf  { background:#6b3b8f; }
.tl-year{
  display:inline-block; margin-top:8px;
  font-size:9px; color:#fff; background:var(--ink-d);
  padding:5px 7px;
}
.tl-main{ flex:1; min-width:0; padding-top:2px; }
.badge{
  display:inline-block; margin-bottom:12px;
  font-size:8px; color:var(--ink-d); background:#ffd84d;
  padding:6px 10px;
}

/* ---------------------------------- Projects */
.proj{ border-top:2px solid var(--rule); padding:30px 0 10px; }
.proj:first-of-type{ border-top:0; }
.proj-art{
  height:132px;
  display:grid; place-items:center;
  font-size:34px; color:#fff;
  border-radius:10px;
  margin-bottom:18px;
}
.proj-art.rag  { background:linear-gradient(135deg,#1d4ed8,#0ea5e9); font-size:20px; }
.proj-art.chess{ background:linear-gradient(135deg,#312e29,#6b5b45); }
.proj-art.fc   { background:linear-gradient(135deg,#065f46,#10b981); }
.proj-art.cv   { background:linear-gradient(135deg,#7c2d12,#ea580c); }
.proj-art.ci   { background:linear-gradient(135deg,#4c1d95,#8b5cf6); font-size:20px; }
.proj-art.agt  { background:linear-gradient(135deg,#0f172a,#334155); font-size:20px; }
.proj-art.care { background:linear-gradient(135deg,#0e7490,#22d3ee); }
.proj-art.qw   { background:linear-gradient(135deg,#581c87,#c026d3); font-size:20px; }
.proj-art.fox  { background:linear-gradient(135deg,#9a3412,#f59e0b); }
.proj-art.lsf  { background:linear-gradient(135deg,#1e3a8a,#38bdf8); }
.proj-art.fg   { background:linear-gradient(135deg,#134e4a,#2dd4bf); }

/* ---------------------------------- Technologies: full-bleed cards */
.tech{
  display:flex; align-items:center; gap:22px;
  padding:26px clamp(16px,3vw,30px);
  margin:0 clamp(-20px,-5vw,-60px) 0;
  color:#fff;
}
.tech + .tech{ margin-top:0; }
.tech-logo{
  flex:none; width:104px; height:104px;
  display:grid; place-items:center;
  font-size:26px;
  background:rgba(255,255,255,.14);
  border-radius:10px;
}
.tech-body{ flex:1; min-width:0; }
.tech h2{ color:#fff; margin-bottom:4px; letter-spacing:.04em; }
.tech .sub{ color:rgba(255,255,255,.62); font-size:9px; margin-bottom:12px; }
.tech p{ color:rgba(255,255,255,.92); margin:0; }

.tech.py   { background:#2b5b84; }
.tech.torch{ background:#8a3b12; }
.tech.lang { background:#14532d; }
.tech.cvt  { background:#3f3f46; }
.tech.ops  { background:#1e3a5f; }
.tech.js   { background:#8a8420; }

/* ---------------------------------- Contact rows */
.crow{
  display:flex; align-items:center; gap:18px;
  border:3px solid var(--rule); border-radius:6px;
  padding:18px 20px;
  margin-bottom:16px;
  text-decoration:none;
}
.crow:hover{ border-color:var(--ink-d); }
.crow-ico{ flex:none; display:grid; place-items:center; width:44px; height:44px; }
.crow-ico.mail{ color:#d93025; }
.crow-ico.gh  { color:#17181d; }
.crow-ico.li  { color:#0a66c2; }
.crow-ico.cal { color:#1a7f5a; }
.crow-txt{ font-size:11px; color:var(--ink-d); line-height:1.9; }
.crow-txt b{ display:block; font-size:9px; color:var(--ink-l); margin-bottom:4px; }

/* ---------------------------------- MAP: a CRT sitting in the dark */
.crt{
  position:relative;
  width:min(880px, calc(100vw - 24px));
  margin:auto;
  background:#cfc7b4;
  border-radius:18px;
  padding:22px 22px 0;
  box-shadow:0 40px 90px rgba(0,0,0,.7), inset 0 2px 0 rgba(255,255,255,.5);
}
.crt-x{ top:-14px; right:-14px; }
.crt-bezel{
  background:#3a352c;
  border-radius:12px;
  padding:16px;
  box-shadow:inset 0 0 0 3px #22201a;
}
.crt-glass{
  position:relative;
  background:radial-gradient(120% 120% at 50% 40%, #12301d, #071108 80%);
  border-radius:8px;
  padding:18px;
  min-height:300px;
  overflow:hidden;
}
.crt-legend{
  display:flex; gap:18px; flex-wrap:wrap;
  font-size:8px; color:#8ff0a8;
  margin-bottom:16px;
}
.crt-legend i{
  display:inline-block; width:9px; height:9px; margin-right:6px;
  vertical-align:-1px;
}
.k-here{ background:#ffd84d; }
.k-seen{ background:#8ff0a8; }
.k-dark{ background:#2f5c3d; }

.crt-grid{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(112px,1fr)); gap:10px;
}
.crt-grid .cell{
  background:rgba(12,40,22,.75);
  border:2px solid #2f5c3d;
  border-radius:6px;
  padding:12px 8px;
  text-align:center;
  display:grid; gap:7px;
  box-shadow:none;
}
.crt-grid .cell .shot{
  display:block; width:100%; height:46px;
  object-fit:cover; object-position:50% 72%;
  image-rendering:pixelated;
  border:1px solid rgba(80,190,110,.5);
  border-radius:3px;
  margin-bottom:6px;
  /* the map is a phosphor screen, so the plates read as phosphor too */
  filter:grayscale(1) sepia(1) hue-rotate(72deg) saturate(2.2) brightness(.85);
}
.crt-grid .cell.unseen .shot{ filter:grayscale(1) brightness(.28); }
.crt-grid .cell b{ font-size:11px; color:#8ff0a8; }
.crt-grid .cell span{ font-size:7px; color:#5fae76; line-height:1.7; }
.crt-grid .cell.here{ border-color:#ffd84d; background:rgba(60,48,10,.6); }
.crt-grid .cell.here b, .crt-grid .cell.here span{ color:#ffd84d; }
.crt-grid .cell.unseen{ opacity:.42; }
.crt-note{ margin:16px 0 0; font-size:8px; line-height:2; color:#6fbf85; }

.crt-scan{
  position:absolute; inset:0; pointer-events:none;
  background:repeating-linear-gradient(180deg, rgba(0,0,0,.22) 0 1px, transparent 1px 3px);
}
.crt-foot{
  display:flex; align-items:center; gap:10px;
  padding:14px 6px 16px;
}
.crt-led{
  width:10px; height:10px; border-radius:50%;
  background:#7ef08f; box-shadow:0 0 8px #7ef08f;
}
.crt-brand{ font-size:8px; color:#6d6455; }

/* ---------------------------------- Under the Hood: tabs */
.hood{ padding:0; overflow:hidden; }
.hood-head{
  background:#2a2d34; color:#fff;
  padding:32px 30px;
  text-align:center;
}
.hood-head h1{ color:#fff; margin:0 0 10px; font-size:clamp(18px,3.4vw,32px); }
.hood-head p{ color:#aeb3bd; margin:0; font-size:10px; }

.hood-split{ display:flex; min-height:min(66dvh, 560px); }
.hood-tabs{
  flex:none; width:210px;
  border-right:2px solid var(--rule);
  background:#f6f6f2;
  padding:14px 0;
}
.hood-tabs button{
  display:block; width:100%;
  font-family:var(--font); font-size:9px; line-height:1.6;
  text-align:left;
  color:var(--ink-m); background:none;
  border:0; border-left:4px solid transparent;
  padding:16px 16px;
  cursor:pointer;
}
.hood-tabs button:hover{ color:var(--ink-d); background:#ecece6; }
.hood-tabs button.on{
  color:var(--ink-d); background:#fff;
  border-left-color:#c9a227;
}
.hood-body{ flex:1; min-width:0; padding:30px clamp(18px,3vw,38px) 40px; overflow-y:auto; }
.hood-body h2{ margin-bottom:16px; }

@media (max-width:720px){
  .hood-split{ display:block; }
  .hood-tabs{
    width:auto; display:flex; overflow-x:auto;
    border-right:0; border-bottom:2px solid var(--rule); padding:0;
  }
  .hood-tabs button{ white-space:nowrap; border-left:0; border-bottom:4px solid transparent; }
  .hood-tabs button.on{ border-bottom-color:#c9a227; }
}

@media (max-width:560px){
  .doc{ border-radius:12px; padding:46px 16px 40px; margin:10px auto; }
  .doc p{ font-size:10px; line-height:2; }
  .tech{ flex-direction:column; text-align:center; gap:14px; }
  .tl-row{ gap:12px; }
  .tl-row::before{ left:24px; }
  .tl-side{ width:52px; }
  .tl-logo{ width:52px; height:52px; font-size:11px; }
}

/* the switch out to the ordinary site - an anchor, so it still looks
   like its neighbour but behaves like a link */
a.menu-btn{ text-decoration:none; display:inline-block; }

/* ---------------------------------- turn the phone
   The game is a 16:9 picture; in portrait it would be a letterbox with a
   hero two pixels tall. Nothing loads until the phone is sideways. */
.rotate{
  position:fixed; inset:0; z-index:60;
  display:grid; place-items:center;
  padding:24px;
  background:radial-gradient(120% 90% at 50% 45%, #141827, #0a0c13);
  text-align:center;
}
.rotate[hidden]{ display:none; }
.rotate-box{ max-width:420px; }
.rotate h2{ margin:22px 0 10px; font-size:13px; color:var(--gold); }
.rotate p{ margin:0; font-size:9px; line-height:2.1; color:var(--paper); }
.rotate-phone{
  width:54px; height:92px; margin:0 auto;
  border:3px solid var(--gold-dk); border-radius:9px;
  position:relative;
  animation:turn 2.4s ease-in-out infinite;
}
.rotate-phone i{
  position:absolute; left:50%; bottom:5px; transform:translateX(-50%);
  width:16px; height:2px; background:var(--gold-dk); border-radius:2px;
}
@keyframes turn{
  0%, 30%   { transform:rotate(0deg); }
  55%, 85%  { transform:rotate(-90deg); }
  100%      { transform:rotate(0deg); }
}

/* ---------------------------------- a phone, sideways
   Landscape on a handset is about 360px tall, so every piece of chrome
   gets out of the picture: the buttons go to the top, the thumbs to the
   bottom corners, and the dialogue sits between them. */
.touch .topleft{ top:6px; left:6px; gap:6px; }
.touch .menu-btn{ font-size:7px; padding:7px 9px; }

.touch .tools{ top:6px; right:6px; bottom:auto; gap:5px; max-width:58vw; }
.touch .tools button{ font-size:6px; padding:7px 8px; }

.touch .pad button{ font-size:12px; }

/* clear of the thumbs, not of the button bar - that is at the top now */
/* Out of the pad's way: hard against the right edge, with the cross's worth
   of width on the left left clear for the arrows. */
.touch .say{
  left:auto; right:8px; transform:none;
  bottom:8px;
  width:calc(100vw - 168px);
  padding:8px 10px; gap:10px;
}
/* The top of a phone screen is entirely chrome: Menu and Normal site on
   the left, and seven tool buttons on the right that wrap onto two rows.
   A box pinned up there lands underneath them, with the speaker's name and
   the end of the title hidden behind MAP and Under the Hood. The point of
   the top variant was to keep the sprites visible on a couple of stages;
   on a phone the box is small enough at the bottom that it costs nothing,
   so up there it simply is not worth it. */
.touch .say.top{ top:auto; bottom:8px; }
.touch .say{ min-height:84px; }
.touch .say-face{ left:-4px; bottom:2px; width:100px; height:100px; }
.touch .say-face:not([hidden]) + .say-body{ padding-left:98px; }
.touch .say.top .say-face{ left:-4px; bottom:2px; width:100px; height:100px; }
.touch .say.top .say-face:not([hidden]) + .say-body{ padding-left:98px; }
.touch .say h2{ font-size:9px; }
.touch .say header span{ font-size:7px; }
.touch .say p{ font-size:8px; line-height:1.85; }

.touch .toast{ bottom:150px; font-size:8px; }
/* The reading panels. Their type is sized in vw so that it grows with a
   desktop window - but 4.6vw on a landscape phone is a 37px headline, which
   is how these ended up filling the screen. On touch they take fixed sizes.
   The panel is also pulled in from the edges, so that there is actually some
   backdrop left to tap on to dismiss it. */
.touch .doc{
  width:min(940px, 88%);
  max-height:82dvh;
  margin:auto;
  padding:34px 16px 24px;
  border-radius:14px;
}
.touch .doc h1{ font-size:11px; line-height:1.7; margin:18px 0 10px; }
.touch .doc h1.big{ font-size:14px; margin:2px 0 12px; }
.touch .doc h2{ font-size:10px; }
.touch .doc h3{ font-size:8px; }
.touch .doc p{ font-size:8px; line-height:1.95; margin:0 0 10px; }
.touch .doc p.lead{ margin-bottom:18px; }
.touch .doc p.role{ font-size:7px; }
.touch .screen{ padding:10px; }

/* Everything else inside a panel, which the headings and paragraphs above
   do not reach: the lists, the chips, the buttons, the id card, the map
   plates and the tab rail. Left alone they stayed at desktop sizes while
   the prose around them shrank, which reads worse than either. */
.touch .ticks li{ font-size:8px; line-height:1.85; padding-left:16px; margin-bottom:7px; }
.touch .ticks li::before{ font-size:7px; }
.touch .ticks.two{ columns:1; }
.touch .tags{ gap:5px; margin-top:10px; }
.touch .tags li{ font-size:6px; padding:4px 6px; border-width:1px; }
.touch .btn-doc{ font-size:8px; padding:10px 12px; border-width:2px; box-shadow:3px 3px 0 var(--ink-d); }
.touch .rank{ font-size:7px; }
.touch .idcard-who h2{ font-size:10px; }
.touch .idcard-who p{ font-size:7px; }
.touch .ask{ padding:14px; margin-top:22px; border-width:2px; }
.touch .proj{ padding:18px 0 8px; }
.touch .proj-art{ height:74px; font-size:22px; margin-bottom:12px; }
.touch .proj-art.rag,
.touch .proj-art.ci,
.touch .proj-art.agt,
.touch .proj-art.qw{ font-size:15px; }
/* The map is not a .doc - it is its own screen-shaped thing, so none of
   the sizing above reached it. Untouched it came out 437px tall inside a
   360px phone, with no max-height and nothing to scroll, and 12px of
   backdrop either side to try to tap. */
.touch .crt{
  width:min(880px, 88%);
  max-height:82dvh; overflow-y:auto;
  padding:14px 14px 0; border-radius:14px;
}
.touch .crt-bezel{ padding:9px; }
.touch .crt-glass{ padding:11px; min-height:0; }
.touch .crt-legend{ font-size:6px; gap:11px; margin-bottom:10px; }
.touch .crt-legend i{ width:7px; height:7px; margin-right:4px; }
.touch .crt-grid{ grid-template-columns:repeat(auto-fit,minmax(82px,1fr)); gap:7px; }
.touch .crt-grid .cell{ padding:7px 5px; gap:5px; }
.touch .crt-grid .cell b{ font-size:8px; }
.touch .crt-grid .cell span{ font-size:6px; line-height:1.6; }
.touch .crt-note{ font-size:7px; line-height:1.8; margin-top:10px; }
.touch .crt-foot{ padding:8px 4px 10px; }
.touch .crt-brand{ font-size:6px; }
.touch .hood-head h1{ font-size:12px; margin-bottom:6px; }
.touch .hood-head p{ font-size:7px; }
.touch .hood-tabs button{ font-size:7px; padding:9px 11px; }

/* Under the Hood could not be scrolled on a phone. The card sets
   overflow:hidden on itself and hands scrolling to .hood-body, which works
   while the two are side by side and .hood-body has a height to be bounded
   by. Stacked, it has none - so the overflow was simply clipped, with
   nothing to drag. On touch the card scrolls itself instead. The old
   stacking rule keyed off a 720px media query, which a landscape phone is
   too wide to match, so it is repeated here off the touch class. */
.touch .doc.hood{ overflow-y:auto; }
.touch .hood-split{ display:block; min-height:0; }
.touch .hood-tabs{
  width:auto; display:flex; overflow-x:auto;
  border-right:0; border-bottom:2px solid var(--rule); padding:0;
}
.touch .hood-tabs button{
  width:auto; white-space:nowrap;
  border-left:0; border-bottom:4px solid transparent;
}
.touch .hood-tabs button.on{ border-bottom-color:#c9a227; }
.touch .hood-body{ overflow:visible; padding:16px 14px 24px; }

/* Fixed rather than absolute: the cross lives inside a panel that scrolls,
   so on a phone it slid off the top the moment you read anything - which is
   what made these screens feel like something you could not get out of.
   Top left, where it is nowhere near either thumb. */
.touch .x{
  position:fixed; top:8px; left:8px; right:auto;
  width:36px; height:36px; font-size:11px;
  z-index:12;
}

/* ---------------------------------- the plates, on a handset
   Landscape on a phone leaves about 330px of usable height once the
   browser chrome has taken its share, and the title plate was taller than
   that - Begin sat below the fold on a screen that does not scroll.
   The keyboard grid is the thing to lose: it lists keys a phone does not
   have, and the controls it describes are already on the game as thumb
   buttons. */
.touch #menu .grid,
.touch #pause .grid{ display:none; }

/* The card has to clear a landscape phone, which is about 360px tall with
   the browser chrome taken off - so everything on it comes in a size. */
.touch .keys{ gap:6px; }
.touch .keys li{ padding:7px 10px; grid-template-columns:46px 1fr; gap:10px; }
.touch .keys b{ font-size:10px; }
.touch .keys span{ font-size:7px; line-height:1.75; }
.touch .dismiss{ font-size:7px; line-height:1.75; margin:0; }
.touch #controls .btn{ padding:10px 16px; font-size:9px; }

.touch .plate{ padding:26px 14px 14px; width:min(560px, 100%); }
.touch .plate-title{ font-size:10px; top:-11px; }
.touch .plate-body{ gap:12px; }
.touch .scroll{ padding:12px 14px; }
.touch .scroll header h1{ font-size:10px; }
.touch .scroll p{ font-size:8px; line-height:1.85; }
.touch .btn{ padding:12px 14px; font-size:10px; }
