/*
  The live viewer: the input history, the controller panel, the about dialog
  and the browser version's own notices. Linked by index.html and browser.html
  only -- the editor, setup and training pages match none of these selectors.

  Loaded after base.css, which it relies on for the tokens and the panel shell.
*/



/* The side badge is deliberately the loudest thing in the bar after the logo.
   Read as the wrong side, every detection below is wrong, so this is worth
   noticing without going looking for it. Its colours match the history rows. */
.sidebadge {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: .08em;
  line-height: 1;
  padding: 5px 10px;
  border: 1px solid transparent;
  cursor: pointer;
}

.sidebadge.p1 { color: var(--accent); border-color: var(--accent); background: #2a1e08; }
.sidebadge.p2 { color: var(--info); border-color: var(--info); background: #131d2e; }

/* Dashed while the side is being worked out from your inputs, solid once you
   have said which it is. The mode is worth knowing and not worth a caption. */
.sidebadge.auto { border-style: dashed; }

/* Sitting in a panel header it has to fit the header's height. */
.ph .sidebadge { font-size: 12px; padding: 3px 7px; }

/* Sides swap between rounds without warning, so a change announces itself. */
.sidebadge.changed { animation: sideflip .9s ease-out; }

@keyframes sideflip {
  0%, 55% { transform: scale(1.18); filter: brightness(1.6); }
  100% { transform: none; filter: none; }
}

@media (prefers-reduced-motion: reduce) {
  .sidebadge.changed { animation: none; }
}

/* ---- layout ---- */

/* The history is kept narrow on purpose. An input is a number, an arrow and
   two circles; stretched across a wide screen it reads as scattered debris,
   and the side control ends up a hand's width from the inputs it governs. */
/* The viewer: history in the middle, live panels right, character left. */
main {
  grid-template-columns: minmax(0, 620px) 300px;
  grid-template-areas:
    "history right"
    "left    right";
}

/*
  The history is the exception. It is a column of inputs, not a card, and the
  game does not box its own input display in either — so it keeps a rule above
  and below and nothing down the sides, and takes no cut corners.
*/
/* Both selectors, so this beats .panel wherever the two sit in the file. */
.panel.history-panel {
  grid-area: history;
  position: relative;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  clip-path: none;
}

/* The bottom rule belongs to the resize handle, which draws it so it can
   thicken when you reach for it. */

.panel.history-panel::before { display: none; }
.side-left { grid-area: left; }
.side-right { grid-area: right; }

.side { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

/* Wide enough for a column either side: the history keeps the middle and the
   empty space to its left is given to Character instead of being left blank. */
@media (min-width: 1280px) {
  main {
    grid-template-columns: 250px minmax(0, 620px) 300px;
    grid-template-areas: "left history right";
  }
}

@media (max-width: 860px) {
  main {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "history" "left" "right";
  }
}


/* ---- input history ---- */

.history {
  display: flex;
  flex-direction: column;
  /* Sized to hold exactly the configured number of rows. Scrolling stays
     available so a side divider can never push an input out of reach, but in
     normal use there is nothing to scroll. */
  height: calc(var(--rows) * var(--row-h) + 14px);
  overflow-y: auto;
  padding: 4px 0;
  justify-content: flex-end;   /* newest at the bottom, list grows upward */
  background: var(--sunk);
}

.history.reversed { justify-content: flex-start; }

/* In the panel's own header, above the inputs it clears. */
.clearbtn {
  background: none;
  border: 1px solid var(--line2);
  color: var(--dim);
  font: 700 10px var(--display);
  letter-spacing: .12em;
  text-transform: uppercase;
  padding: 3px 8px;
  cursor: pointer;
}

.clearbtn:hover { color: var(--text); border-color: var(--accent); background: var(--panel2); }

/*
  The rule under the history is the handle that sizes it, and it draws that
  rule itself rather than the panel doing it — which is what lets the line
  thicken under the cursor instead of a separate grip appearing.

  The strip is taller than the line so the handle can be caught without
  precision, and the line is anchored to its bottom edge so thickening grows
  upward and moves nothing.
*/
.resize {
  height: 14px;
  cursor: ns-resize;
  touch-action: none;
  position: relative;
}

/* A real element rather than a pseudo one, so its height can be measured and
   tested rather than taken on trust. */
.resize .rule {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--line);
  transition: height .1s ease, background-color .1s ease;
}

.resize:hover .rule,
.resize:focus-visible .rule { height: 5px; background: var(--line2); }
.resize.dragging .rule { height: 5px; background: var(--accent); }

/* ---- about ---- */

.about {
  --cut: 16px;
  width: min(560px, calc(100vw - 32px));
  max-height: min(78vh, 760px);
  padding: 0;
  border: 0;
  color: var(--text);
  background: var(--line);          /* the rim, as on a panel */
  font: 14px/1.55 var(--sans);
  clip-path: polygon(
    0 0,
    calc(100% - var(--cut)) 0,
    100% var(--cut),
    100% 100%,
    var(--cut) 100%,
    0 calc(100% - var(--cut))
  );
}

.about::backdrop { background: rgba(6, 4, 12, .72); }

.about .ph { margin: 1px 1px 0; }

.aboutBody {
  margin: 0 1px 1px;
  padding: 14px 18px 18px;
  background: var(--panel);
  overflow-y: auto;
  overflow-x: hidden;
  max-height: calc(min(78vh, 760px) - 40px);
}

.aboutBody h3 {
  font-family: var(--display);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 20px 0 6px;
}

.aboutBody p { margin: 0 0 9px; color: var(--muted); font-size: 13px; }
.aboutBody a { color: var(--info); }
.aboutBody .fine { color: var(--dim); font-size: 11.5px; margin-top: 12px; }

/* Facts as a two-column list: label left, value right, nothing invented to
   fill a gap. */
.kv { display: grid; grid-template-columns: auto 1fr; gap: 3px 14px; margin: 0; }
.kv dt {
  font-family: var(--display);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--dim);
  white-space: nowrap;
  padding-top: 2px;
}
.kv dd { margin: 0; font-family: var(--mono); font-size: 12px; color: var(--text); overflow-wrap: anywhere; }
.kv dd.warn { color: var(--accent); font-family: var(--sans); font-size: 12.5px; }

/* The About panel's own rows: the same list as the dialog, at panel scale. */
.kv.brief { padding: 8px 12px 10px; gap: 4px 12px; }
.kv.brief dt { font-size: 10.5px; padding-top: 1px; }
.kv.brief dd { font-size: 11.5px; }
.kv.brief dd.warn { font-size: 11.5px; }

.morelink {
  background: none;
  border: 0;
  padding: 0;
  color: var(--info);
  font: inherit;
  font-size: 10.5px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.morelink:hover { color: var(--accent); }

.xbtn {
  background: none;
  border: 0;
  color: var(--dim);
  font-size: 14px;
  line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
}

.xbtn:hover { color: var(--text); }

/* Slim and quiet. In normal use there is nothing to scroll; this only appears
   when a side divider has pushed the list past the height you asked for, and
   it should not draw the eye when it does. */
.history::-webkit-scrollbar { width: 6px; }
.history::-webkit-scrollbar-track { background: transparent; }
.history::-webkit-scrollbar-thumb { background: var(--line); }
.history { scrollbar-width: thin; scrollbar-color: var(--line) transparent; }

.row {
  display: grid;
  /* Laid out as the game lays it out: frames, then direction, then buttons.
     Reading this next to SF6's own display should not require translating. */
  /* Side mark, frames, direction, buttons, then what it was called and the
     controls that act on it — each sitting against the last, with the slack
     pushed to the far right instead of opening a gap mid-row. The buttons
     column holds its width when empty so the names below stay in a line. */
  grid-template-columns: 28px 26px 30px minmax(48px, auto) minmax(0, auto) 22px minmax(0, 1fr);
  gap: 8px;
  align-items: center;
  padding: 0 12px;
  height: var(--row-h);
  flex: 0 0 auto;
}

/* Which side an input was read as. The tint is faint on purpose: it needs to
   be noticeable when it changes without competing with the row's contents. */
.row.p2 { background: #0d1520; }
.row.live { background: #221a0c; }

.sidemark {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  height: 16px;
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dim);
}

.sidemark::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

.sidemark.p2 { color: var(--info); }
.sidemark.p2::after { background: #22344d; }

.dir { display: flex; align-items: center; justify-content: center; }

.dir i {
  font-style: normal;
  font-size: 19px;
  line-height: 1;
  color: var(--text);
}

/* Neutral is a circled N in the game, not a blank, so a held neutral is as
   visible as any other input. */
.dir em {
  font-style: normal;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--muted);
  border: 2px solid var(--line2);
  border-radius: 50%;
  width: 18px;
  height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.btns { display: flex; gap: 4px; flex-wrap: wrap; }

/* Colour is strength, letter is punch or kick — the game's own shorthand.
   Two mediums side by side reads as Drive Parry without anything spelling it
   out, which is the point of matching it. */
.btn {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  color: #17130a;
  background: var(--line2);
  box-shadow: inset 0 -2px 3px rgba(0, 0, 0, .28);
}

.btn.light { background: #4aa3ff; }
.btn.medium { background: #ffd23f; }
.btn.heavy { background: #ff5a5a; }

.btn.sys {
  width: auto;
  padding: 0 7px;
  font-size: 10px;
  color: var(--dim);
  background: var(--panel2);
  box-shadow: none;
}

/* Held over from the previous input rather than newly pressed. A motion keys
   off the press, so the distinction matters. */
.btn:not(.fresh) { opacity: .4; }

/* Text chips, for naming a role rather than showing one being pressed: the
   mapping list and anywhere a role is written out. */
.chip {
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .03em;
  padding: 2px 7px;
  border: 1px solid transparent;
  background: var(--panel2);
  color: var(--muted);
}

.chip.lp, .chip.mp, .chip.hp { color: var(--punch); border-color: #23406b; background: #111b2d; }
.chip.lk, .chip.mk, .chip.hk { color: var(--kick); border-color: #6b3a23; background: #2d1a11; }
.chip.sys { color: var(--dim); border-color: var(--line); }

.frames {
  font-family: var(--mono);
  font-size: 12.5px;
  text-align: right;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* The detected command, or the one that came closest. This is the column the
   whole tool exists for, so it is allowed to be the loudest thing in the row. */
/* Capture this input as a command. Quiet until the row is worth capturing or
   the pointer is over it: the history is watched while playing, and a column of
   buttons competing for attention would be worse than useless. */
.keep {
  background: none;
  border: 0;
  color: var(--line2);
  font-size: 14px;
  line-height: 1;
  padding: 2px;
  cursor: pointer;
  opacity: 0;
}

.row:hover .keep { opacity: 1; }
.keep:hover { color: var(--accent); }
.keep.idle { visibility: hidden; }

/* Sets the side from this input down. Hidden until you go looking, like the
   capture button beside it — it corrects a mistake rather than being part of
   reading the history. A mark you have placed stays visible. */
.sideset {
  background: none;
  border: 1px solid var(--line2);
  color: var(--dim);
  font: 600 10px var(--mono);
  letter-spacing: .06em;
  line-height: 1;
  padding: 3px 4px;
  cursor: pointer;
  opacity: 0;
}

.row:hover .sideset { opacity: 1; }
.sideset:hover { color: var(--info); border-color: var(--info); }
.sideset.marked { opacity: 1; color: var(--info); border-color: var(--info); }

.sidemark.byhand em {
  font-style: normal;
  font-size: 9px;
  letter-spacing: .1em;
  color: var(--dim);
  order: 3;
}

.sidemark.byhand::after { order: 2; }

.detect { font-size: 12.5px; color: var(--dim); display: flex; gap: 7px; align-items: baseline; min-width: 0; }
.detect b { font-weight: 600; white-space: nowrap; }
.detect .via, .detect .why, .detect .dirty {
  font-family: var(--mono);
  font-size: 11px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.detect.hit b { color: var(--ok); }
.detect.hit .via { color: var(--dim); }
.detect.hit .dirty { color: var(--accent); }

.detect.miss b { color: var(--bad); }
.detect.miss .why { color: #c48a93; }

/* Confirming a detection. Faint until the row is hovered or an answer has been
   given, so a wall of buttons doesn't compete with the history itself. */
.confirm { display: inline-flex; gap: 2px; flex: 0 0 auto; }

.confirm button {
  background: none;
  border: 1px solid transparent;
  color: var(--dim);
  font-size: 11px;
  line-height: 1;
  padding: 2px 5px;
  cursor: pointer;
  opacity: .35;
}

.row:hover .confirm button { opacity: 1; }
.confirm .yes:hover, .confirm .yes.on { color: var(--ok); border-color: var(--ok); opacity: 1; }
.confirm .no:hover, .confirm .no.on { color: var(--bad); border-color: var(--bad); opacity: 1; }

/* ---- now ---- */

/* The Now panel's rosette and buttons. Named for what it is: calling it .live
   collided with the history's live row, which is also a .live, and quietly
   centred that row's grid so the current input did not line up with the
   history underneath it. */
.nowpad {
  padding: 14px 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  flex-wrap: wrap;
}

/* The eight directions laid out as they sit on a stick, so the shape of what
   you are holding is read by position rather than by decoding an arrow. */
.rosette {
  display: grid;
  grid-template-columns: repeat(3, 26px);
  grid-template-rows: repeat(3, 26px);
  gap: 2px;
}

/* Arrow glyphs are drawn hairline thin at this size and there is no bold cut
   of them to switch to, so the weight is added with a stroke. Without it the
   rosette reads as faint scratches next to the solid button circles. */
.rosette i {
  font-style: normal;
  font-size: 22px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--line2);
  -webkit-text-stroke: 1.1px currentColor;
  transition: color .05s linear;
}

.rosette i.mid {
  font-size: 13px;
  -webkit-text-stroke: 1.6px currentColor;
}

.rosette i.on { color: var(--accent); }
.rosette i.mid.on { color: var(--muted); }

/* Six buttons in the arrangement they sit in on a pad: punches above kicks,
   light to heavy left to right. Unpressed buttons stay visible but dark, so
   the layout is legible even when nothing is held. */
.pad6 {
  display: grid;
  grid-template-columns: repeat(3, 26px);
  grid-template-rows: repeat(2, 26px);
  gap: 5px;
}

.pad6 .btn {
  width: 26px;
  height: 26px;
  font-size: 11px;
  opacity: 1;
  filter: brightness(.32) saturate(.65);
}

.pad6 .btn.on { filter: none; box-shadow: inset 0 -2px 3px rgba(0, 0, 0, .28), 0 0 9px currentColor; }

/* The live display is also the map: a circle is a control, not a readout. */
.pad6.editable .btn { cursor: pointer; }
.pad6.editable .btn:hover { filter: none; outline: 2px solid var(--accent); outline-offset: 2px; }

/* A role with no button behind it. Dashed because it is a hole, not a button
   that happens to be unpressed — the difference matters, and until now an
   unassigned role was simply invisible. */
.pad6 .btn.unset {
  background: none;
  border: 2px dashed var(--line2);
  color: var(--muted);
  filter: none;
  font-weight: 700;
  box-shadow: none;
}

.pad6.editable .btn.unset:hover { border-color: var(--accent); color: var(--accent); outline: none; }

.pad6 .btn.waiting {
  filter: none;
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  animation: waitpulse 1s ease-in-out infinite;
}

@keyframes waitpulse { 50% { opacity: .4; } }

@media (prefers-reduced-motion: reduce) {
  .pad6 .btn.waiting { animation: none; }
}

/* ---- controller panel ---- */

.devrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  padding: 7px 13px;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.devrow .nm { font-weight: 600; font-size: 12.5px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.devrow .caret { color: var(--dim); font-size: 10px; white-space: nowrap; }
.devrow:hover { background: var(--panel2); }

.panelfoot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 13px;
  border-top: 1px solid var(--line);
  font-size: 11px;
}

.panelfoot a { color: var(--info); font-size: 11px; text-decoration: none; }
.panelfoot a:hover { color: var(--accent); }
.panelfoot .warnchip { color: var(--accent); font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em; }

/*
  The bar under the controller panel that asks for a press while remapping.
  Named for what it is rather than "prompt", which the setup wizard also used
  -- and silently inherited this bar's flex layout from, which spread its
  sentence across the panel.
*/
.mapbar[hidden] { display: none; }

.mapbar {
  padding: 8px 13px;
  border-top: 1px solid var(--accent);
  background: #241a09;
  color: #ffd79a;
  font-size: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: space-between;
}

.mapbar b { color: var(--accent); }

.mapbar button {
  background: none;
  border: 1px solid var(--line2);
  color: var(--muted);
  font: 700 10px var(--display);
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 3px 8px;
  cursor: pointer;
  flex: 0 0 auto;
}

.mapbar button:hover { color: var(--text); border-color: var(--accent); }

.qchip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  border: 2px dashed var(--accent);
  color: var(--accent);
  font: 700 10px var(--mono);
  flex: 0 0 auto;
}

/* ---- controllers ---- */

.pads { display: flex; flex-direction: column; gap: 1px; background: var(--line); }

/* A display rule beats the hidden attribute, so say it again. */
.pads[hidden] { display: none; }

.pad {
  display: block;
  width: 100%;
  text-align: left;
  border: 0;
  background: var(--panel);
  color: var(--text);
  padding: 9px 13px;
  cursor: pointer;
  font: inherit;
  position: relative;
}

.pad:hover { background: var(--panel2); }
.pad.active { background: var(--panel2); }
.pad.active .nm { color: var(--accent); }
.pad.pinned::after {
  content: "pinned";
  position: absolute;
  top: 9px;
  right: 13px;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent);
}

.pad .nm { display: block; font-weight: 600; font-size: 13px; }
.pad:not(.live) .nm { color: var(--dim); font-weight: 400; }
.pad .sub { display: block; font-family: var(--mono); font-size: 10.5px; color: var(--dim); }

/* No track. An empty meter drawn in the line colour is indistinguishable from
   a rule, so every controller appeared to have a separator under it. The space
   is still reserved, so the rows stay even; only the amber fill is ever drawn,
   and only when that controller is doing something. */
.pad .meter {
  display: block;
  height: 2px;
  margin-top: 6px;
  background: none;
  overflow: hidden;
}

.pad .meter i { display: block; height: 100%; background: var(--accent); transition: width .25s ease; }

/* ---- browser version ---- */

/* Shown in place of the input history when the display refreshes too slowly
   for a frame count to mean anything. */
.slowbody { padding: 14px 16px 18px; }
.slowbody p { margin: 0 0 10px; color: var(--muted); font-size: 13px; line-height: 1.6; }
.slowbody p b { color: var(--accent); }
.slowbody a { color: var(--info); }

.limits { margin: 0 0 10px; padding-left: 18px; color: var(--muted); font-size: 13px; line-height: 1.6; }
.limits li { margin-bottom: 7px; }
.limits b { color: var(--text); font-weight: 600; }

/* The agent pitch on the browser-only page: two lines and a button. */
.pitch { padding: 11px 13px 13px; }
.pitch p { margin: 0 0 9px; color: var(--muted); font-size: 12.5px; line-height: 1.6; }
.pitch ul { margin: 0 0 10px; padding-left: 17px; color: var(--muted); font-size: 12.5px; line-height: 1.6; }
.pitch li { margin-bottom: 5px; }
.pitch b { color: var(--text); font-weight: 600; }
.pitch em { color: var(--accent); font-style: normal; }
.pitch .fine { color: var(--dim); font-size: 11.5px; }

.getagent {
  display: block;
  text-align: center;
  padding: 7px 10px;
  border: 1px solid var(--accent);
  background: #2a1e08;
  color: var(--accent);
  font: 700 12px var(--display);
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
}

.getagent:hover { background: var(--accent); color: var(--accent-ink); }

/* Inside the agent dialog the button is a block on its own row. */
.aboutBody .getagent { margin-top: 4px; }
.aboutBody em { color: var(--accent); font-style: normal; }
/*
  The agent has gone. Loud, because the page otherwise looks exactly as it did
  a second ago -- panels, history, controller list all still drawn -- while
  reading nothing at all. It stays until the agent answers again.
*/
.offline[hidden] { display: none; }

.offline {
  border-bottom: 1px solid var(--bad);
  background: #2a0f14;
}

.offlinebody {
  max-width: 940px;
  margin: 0 auto;
  padding: 9px 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  align-items: baseline;
  font-size: 12.5px;
  color: #ffc9cf;
}

.offlinebody b {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--bad);
}

.offlinebody .how { color: var(--muted); }
.offlinebody a { color: var(--info); }
.offlinebody code {
  font-family: var(--mono);
  font-size: 11.5px;
  background: #1b0c10;
  padding: 1px 5px;
  color: #ffc9cf;
}
