/* Shell A. Colour palette carried over from prototypes/14-presentation.
   Chapter 11 section 7: nothing load bearing is signalled by colour alone, so
   every stream also carries a GUTTER MARK, and the death cry is a break in the
   feed with rules above and below it rather than another colour competing. */
:root {
  /* TICKET 77: EVERY TEXT COLOUR AT 4.5:1 OR BETTER against the ground it is
     drawn on, measured (access A12 found six under). Dim was 4.58 on the panel
     and 4.23 on a scar's hatch, the ambient stream 3.27, and the cry's red 3.92
     on the bleeding block's own tint; the lowest pair now is dim on a scar's
     darker stripe at 4.82. There is one theme and no light one. */
  --bg:#0e0f11; --panel:#15171a; --line:#24272c; --ink:#d6d2c8;
  --dim:#858b94; --prose:#cfcabf; --combat:#e8e2d4; --sys:#c9a227;
  --speech:#c8b6d6; --whisper:#8f83a0; --amb:#858b94; --net:#6fa8dc; --cry:#e46666;
  /* The far side, ticket 17. Cold, and deliberately NOT the Leyline's blue: the
     channel the dead reach is not the network the living talk on. */
  --dead:#7f9fb5;
}
* { box-sizing: border-box }
html, body { height:100% }
body {
  margin:0; background:var(--bg); color:var(--ink);
  /* TICKET 75: EVERY TEXT SIZE IS IN rem, so the browser's own font size
     setting moves all of it (access A14 measured 13px with the setting at 32).
     At the shipped 16px default each rem value below is the pixel size it
     replaced: 0.8125rem is 13px, 0.6875rem is 11px, 0.625rem is 10px. */
  font:0.8125rem/1.55 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
.visually-hidden {
  position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0);
}

#app {
  height:100%;
  display:grid;
  /* THE LEFT RAIL WIDENED FOR THE DOLL, and it was found by LOOKING rather than
     by any check. Fourteen regions in three columns need room for "right hand",
     and at 212px the whole right hand column was clipped: the panel rendered,
     the checks passed, and half the body was off the edge of the screen. */
  /* TICKET 75: IN rem, so a larger browser font widens the rails with their
     text instead of clipping the doll again; 16.375rem is the 262px above. */
  grid-template-columns:16.375rem minmax(0,1fr) 15.5rem;
  grid-template-rows:minmax(0,1fr) 2rem 2.375rem;
}
.rail.left  { grid-column:1; grid-row:1 }
.feed       { grid-column:2; grid-row:1 }
.rail.right { grid-column:3; grid-row:1 }
.rtstrip    { grid-column:1/-1; grid-row:2 }
#entry      { grid-column:1/-1; grid-row:3 }

/* ---- the feed ---- */
/* `overflow-anchor: none`, ticket 75: Chrome's scroll anchoring moves the scroll
   position when a resize rewraps the lines, and the client reads a moved scroll
   position as the player reading back. Only the player may stop the follow. */
.feed { overflow-y:auto; overflow-anchor:none; padding:14px 16px }
.line {
  margin:0; white-space:pre-wrap; display:grid;
  grid-template-columns:0.875rem minmax(0,1fr); column-gap:6px;
}
.line .mark { color:var(--dim); user-select:none }
.line .body { color:var(--prose) }
.line[data-stream="combat"]  .body { color:var(--combat) }
.line[data-stream="system"]  .body { color:var(--sys) }
.line[data-stream="speech"]  .body { color:var(--speech) }
/* A whisper is speech turned down: the same hue darker, and the gutter mark is
   one stroke against speech's two. Both signals move, per section 7. */
.line[data-stream="whisper"] .body { color:var(--whisper); font-style:italic }
.line[data-stream="ambient"] .body { color:var(--amb); font-style:italic }
.line[data-stream="leyline"] .body { color:var(--net) }
.line[data-stream="echo"]    .body { color:#fff; font-weight:700 }
/* Chapter 11 section 7: the death cry is a BREAK in the feed, not a hue. */
.line[data-stream="cry"] {
  border-top:1px solid var(--cry); border-bottom:1px solid var(--cry);
  padding:6px 0; margin:8px 0; background:rgba(228,102,102,.08);
}
.line[data-stream="cry"] .body { color:var(--cry); font-weight:700; letter-spacing:.1em }
/* THE FAR SIDE, TICKET 17, AND IT NEEDED A SHAPE THE DAY JC RULED THAT EVERYBODY
   HEARS IT. While only the dead could hear the channel it landed in a quiet feed;
   heard by the living it lands in a busy one, beside speech and combat, carrying
   a plea somebody has twenty minutes to answer. The gutter mark was doing the
   whole job on its own, because the body colour fell through to prose.
   A LEFT RULE, and it is a DIFFERENT shape from the cry's rules above and below
   on purpose: section 7 asks that two lines told apart in a hurry differ in shape,
   and these two are the pair most likely to be on one screen at one moment. */
.line[data-stream="dead"] { border-left:2px solid var(--dead); padding-left:6px }
.line[data-stream="dead"] .body { color:var(--dead); font-style:italic }

/* ---- the rails ---- */
.rail {
  background:var(--panel); border-left:1px solid var(--line);
  padding:12px; overflow-y:auto;
}
.rail.left { border-left:none; border-right:1px solid var(--line) }
h4 {
  margin:0 0 6px; font-size:0.625rem; letter-spacing:.14em; text-transform:uppercase;
  color:var(--dim); font-weight:600;
}
.blk { margin-bottom:16px }
.muted { color:var(--dim) }
.note { color:var(--dim); font-size:0.6875rem; margin:0; font-style:italic }
.list { list-style:none; margin:0; padding:0 }
.list li { padding:1px 0 }
.list button {
  background:none; border:none; padding:0; font:inherit; color:var(--ink);
  text-align:left; cursor:pointer; text-decoration:underline dotted;
}
.list button:hover, .list button:focus { color:#fff }

/* ---- links, ticket 66 ----
   The server says WHAT a thing is (`data-kind`) and these presets say how it
   looks, as Wrayth's Highlights did. Chapter 11 section 7, never colour alone:
   every link is UNDERLINED, a thing dotted and a way out solid, and a creature
   is BOLD (GemStone's monster bold), so all three survive a monochrome display
   and a stylesheet that is half there. People and the furniture are plain links. */
.ref {
  background:none; border:none; padding:0; margin:0; font:inherit; color:inherit;
  cursor:pointer; text-align:left; text-decoration:underline dotted; text-underline-offset:2px;
}
.ref[data-kind="door"], .ref[data-kind="exit"] { text-decoration:underline solid }
.ref[data-kind="creature"] { font-weight:700 }
.ref:hover:not(:disabled), .ref:focus-visible { color:#fff }
.ref:focus-visible { outline:1px solid var(--dim); outline-offset:1px }
/* Show links off: the words stay, the link goes. The creature keeps its bold,
   which is a highlight and not a link. */
.feed .ref:disabled { cursor:inherit; text-decoration:none }
/* Ticket 76. Whom a creature is on, beside it on the rail, and the rail entry a
   feed line's creature is pointed at, lit by an outline: a shape, not a hue. */
.list .note { color:var(--dim); margin-left:.25em }
.ref.lit { outline:1px solid currentColor; outline-offset:1px }
.refmenu {
  position:fixed; z-index:10; display:flex; flex-direction:column; min-width:10em;
  background:var(--panel); border:1px solid var(--line); padding:4px 0;
}
.refmenu[hidden] { display:none }
.refmenu button {
  background:none; border:none; font:inherit; color:var(--ink); text-align:left;
  padding:2px 10px; cursor:pointer;
}
.refmenu button:hover, .refmenu button:focus { background:var(--line); color:#fff; outline:none }
.linksblk label { color:var(--dim); cursor:pointer }

/* ---- the wound doll, the bleeding indicator and the hands ---- */
/* Chapter 11 section 7 again, and this panel is where it bites hardest: a rank 3
   arm and a rank 3 scar must be told apart in a hurry, so the SHAPE differs and
   not only the hue. The rank is a digit, a scar's digit is bracketed, and a
   bleeding region carries a star. All three survive a stylesheet that never
   loaded, which is the test that rules colour out on its own. */
.doll { display:grid; grid-template-columns:repeat(3,1fr); gap:2px }
.cell { min-height:1.375rem }
.region {
  width:100%; display:flex; justify-content:space-between; gap:3px;
  background:#101215; border:1px solid var(--line); color:var(--dim);
  font:inherit; font-size:0.625rem; padding:2px 3px; cursor:pointer; text-align:left;
  white-space:nowrap;
}
.region:hover, .region:focus { border-color:#4a515b; color:#fff }
.rname { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.rmark { color:var(--dim) }
.region[data-rank="1"] { color:var(--ink) }
.region[data-rank="2"] { color:#d9a441; border-color:#5a4a25 }
.region[data-rank="3"] { color:var(--cry); border-color:#6b2f2f }
/* A SCAR IS A WOUND IN EVERYTHING BUT BLEEDING, chapter 05 section 5, so it is
   the same weight in a distinct state rather than a quieter one: hatched, which
   is a shape, and its digit is bracketed in the markup. */
.region[data-state="scar"] {
  background:repeating-linear-gradient(135deg,#101215 0 3px,#1b1f24 3px 6px);
}
.region[data-bleeding="yes"] { border-color:var(--cry) }

.bleedblk[hidden] { display:none }
.bleed {
  margin:0; padding:5px 6px; color:var(--cry); font-weight:700; font-size:0.6875rem;
  border:1px solid var(--cry); background:rgba(228,102,102,.10); letter-spacing:.04em;
}
#hands li.closed { color:var(--cry) }

/* THE SECOND CLOCK, ticket 15. It reads as the bleeding block's sibling on
   purpose, because chapter 05 asks the player to compare the two numbers, and it
   is told apart by SHAPE rather than by hue alone (chapter 11 section 7): the
   bleeding block is outlined and this one is filled solid. */
.deadblk[hidden] { display:none }
.dead {
  margin:0; padding:5px 6px; color:var(--bg); font-weight:700; font-size:0.6875rem;
  border:1px solid var(--cry); background:var(--cry); letter-spacing:.04em;
}

/* ---- the dial, ticket 24 ----
   CHAPTER 11 SECTION 8's stance row. The block is one button because the server
   put a command on the package, and what it sends is the verb that prices all
   five rows on both tracks, which is section 9's answer to the third debt.
   TOLD APART BY SHAPE AND POSITION AND NOT BY HUE, section 7: the name and the
   price are both text the server wrote, so the row says which way the dial is
   set with no stylesheet at all. The border is the second signal and never the
   first, and the two ends of the dial lean opposite ways. */
#stanceBlk[hidden] { display:none }
.stancerow {
  width:100%; display:flex; justify-content:space-between; align-items:baseline;
  gap:8px; background:#101215; border:1px solid var(--line); color:var(--ink);
  font:inherit; font-size:0.6875rem; padding:4px 6px; cursor:pointer; text-align:left;
}
.stancerow:hover, .stancerow:focus { border-color:#4a515b; color:#fff }
.stancerow .note { font-style:normal }
.stancerow[data-stance="offensive"] { border-left:3px solid var(--cry) }
.stancerow[data-stance="forward"] { border-left:3px solid #8a5a3a }
.stancerow[data-stance="guarded"] { border-left:3px solid #4c6b8a }
.stancerow[data-stance="defensive"] { border-left:3px solid #6f8fb0 }

/* ---- the two pools, ticket 22 ----
   CHAPTER 11 SECTION 8: "spirit gets different visual weight from mana, because
   chapter 06 makes it small, slow, Aura derived and lethal at zero, and a second
   bar of the same treatment says the two are the same kind of thing". So mana is
   a bar and spirit is a row of marks, one per point. The difference is SHAPE and
   survives a stylesheet that never loaded, because the marks are text. */
#healthBlk[hidden], #poolBlk[hidden], #landBlk[hidden] { display:none }
/* TICKET 71. The health bar is the mana bar's shape in a dried blood red, dark
   enough to sit with the slate of mana and the gold of the roundtime strip and
   apart from the brighter red the feed keeps for a cry. */
.bar.health { height:9px }
.bar.health i { background:#8e3b36; z-index:1 }
.poolline { margin:0 0 3px; color:var(--dim); font-size:0.6875rem }
.spirith { margin-top:12px }
.bar.mana { height:9px }
.bar.mana i { background:#4c6b8a; z-index:1 }
/* THE CEILING IS DRAWN AND NOT ONLY THE POOL. A primordial in town is capped at
   about half, and a bar that showed only what he holds would say nothing about
   why it stopped filling. The cap is a hatched region past the fill, which is the
   roundtime strip's own soft treatment reused rather than a second idiom. */
/* UNDER THE FILL AND NOT OVER IT, WHICH THE SEAM 3 WALK IS WHAT FOUND. Drawn on
   top, the hatch covered the fill, and a Druid standing in town holding a FULL
   hundred mana read as half full: the one state where the two overlap is the one
   a new character starts in. Behind it, a pool above the room's ceiling shows as
   full and the hatch only appears in the gap the room will not fill. */
.bar.mana u {
  position:absolute; top:0; bottom:0; display:block; text-decoration:none; z-index:0;
  background:repeating-linear-gradient(90deg,#2b3238 0 3px,transparent 3px 6px);
}
.pips { display:flex; gap:3px; font-size:0.8125rem; line-height:1; color:#9a80b8 }
/* Spent is the hollow mark first and the dim hue second, and both read. */
.pips span[data-spent="1"] { color:var(--dim) }

/* ---- roundtime, along the bottom ---- */
.rtstrip {
  background:var(--panel); border-top:1px solid var(--line);
  display:flex; align-items:center; gap:12px; padding:0 12px; font-size:0.6875rem;
}
.rtlabel { color:var(--dim); min-width:9.375rem }
.rtcount { color:var(--dim); min-width:2.75rem; text-align:right }
.build { color:var(--dim); font-size:0.625rem }
.bar {
  flex:1; height:11px; background:#000; border:1px solid var(--line);
  position:relative; display:block;
}
.bar i { position:absolute; top:0; bottom:0; left:0; display:block; background:#b8862b }
/* HARD AGAINST SOFT, chapter 03 section 4 and ticket 9's bullet. Two states
   that must be told apart in a hurry differ in SHAPE and not only in hue
   (chapter 11 section 7), so soft is a hatched half height band rather than the
   same bar in another colour. A CAST IS THE ONE PRODUCER AND THERE IS NO SECOND
   ONE: this comment named a stance change as the other until ticket 24 read the
   chapter, which leaves stance changes OPEN under a soft roundtime rather than
   producing one, and calls the dial "the one free dial in the game". */
.bar i[data-kind="soft"] {
  background:repeating-linear-gradient(90deg,#4c6b8a 0 4px,transparent 4px 8px);
  top:3px; bottom:3px;
}
/* THE STUN, TICKET 74, told apart from both by SHAPE as well as hue: a full
   height bar cut by diagonal bars, where hard is solid and soft a half height
   hatch. The word beside it says "Stunned" in the same red, bold, because the
   strip read "Ready" through a stun in all three playtest streams. */
.bar i[data-kind="stun"] {
  background:repeating-linear-gradient(135deg,#a8402f 0 5px,#5a1f17 5px 9px);
}
.rtlabel[data-kind="stun"] { color:#d9634e; font-weight:600 }

/* ---- the command line ---- */
#entry { display:flex; border-top:1px solid var(--line); background:#08090a }
#entry input {
  flex:1; background:none; border:none; outline:none; color:#fff;
  font:inherit; padding:0 16px;
}
#entry input::placeholder { color:var(--dim) }
/* The caret was the only sign the line had focus (access A9); a rule along its
   top now says so, which matters once every button hands focus back here. */
#entry:focus-within { border-top-color:var(--dim) }

/* ---- narrow windows, ticket 75 ----
   The grid was fixed at three columns with no query, so at 400 pixels the feed
   was 32 pixels wide and at 200% zoom eleven characters (access A13), while
   chapter 11 section 12 names the feed as the whole of the game. The rails give
   way and the feed keeps the room. The breakpoints are in em, which a media
   query reads off the browser's font size, so a larger font setting steps down
   through them exactly as zoom does.

   TWO COLUMNS below 60em (960 pixels at the default): the feed keeps the right
   and the two rails share the left, the character above the room, each
   scrolling on its own. 200% zoom on a 1280 by 720 window is 640 by 360 here. */
@media (max-width: 60em) {
  #app {
    grid-template-columns:16.375rem minmax(0,1fr);
    grid-template-rows:minmax(0,1fr) minmax(0,1fr) 2rem 2.375rem;
  }
  .rail.left  { grid-column:1; grid-row:1 }
  .rail.right { grid-column:1; grid-row:2; border-left:none; border-right:1px solid var(--line); border-top:1px solid var(--line) }
  .feed       { grid-column:2; grid-row:1/3 }
  .rtstrip    { grid-row:3 }
  #entry      { grid-row:4 }
}
/* ONE COLUMN below 36em (576 pixels): the feed on top and taking what is left,
   the two rails under it as short bands that scroll, then the strip and the
   line. A phone held upright, and 400 pixels, read the feed full width. */
@media (max-width: 36em) {
  #app {
    grid-template-columns:minmax(0,1fr);
    grid-template-rows:minmax(0,1fr) minmax(0,22vh) minmax(0,16vh) 2rem 2.375rem;
  }
  .feed       { grid-column:1; grid-row:1 }
  .rail.left  { grid-column:1; grid-row:2; border-right:none; border-top:1px solid var(--line) }
  .rail.right { grid-column:1; grid-row:3; border-right:none }
  .rtstrip    { grid-row:4 }
  #entry      { grid-row:5 }
  .rtlabel    { min-width:0 }
  .feed       { padding:10px 10px }
}
