/* The chrome the playground and the REPL share: colours, the top bar and its
   controls, the status indicators, and the help panel. Loaded by both pages,
   so the two cannot drift apart. */

/* Light is the default and dark follows the reader's system setting, the
   same way ghul.dev does. The editor theme is switched to match in each page's script:
   chrome and editor have to move together or the page looks broken. */
:root {
  color-scheme: light dark;

  --bg: #ffffff;
  --bg-raised: #f6f7f9;
  --fg: #1f2328;
  --fg-muted: #656d76;
  --border: #d8dde3;
  --accent: #0969da;
  --ok: #1a7f37;
  --warn: #9a6700;
  --bad: #cf222e;
  --shadow: 0 8px 28px rgba(0, 0, 0, 0.12);
  --mono: 'Fira Code', ui-monospace, SFMono-Regular, Menlo, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1e1e1e;
    --bg-raised: #252526;
    --fg: #e6edf3;
    --fg-muted: #9198a1;
    --border: #3c3c3c;
    --accent: #4daafc;
    --ok: #3fb950;
    --warn: #d29922;
    --bad: #f85149;
    --shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
  }
}

* { box-sizing: border-box; }

body {
  font-family: system-ui, -apple-system, sans-serif;
  font-size: 14px;
  margin: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--fg);
}

/* --- the top bar ---

   Two registers and one geometry. An action - File, Run - carries the
   foreground colour; an indicator or a secondary icon carries the muted one
   and brightens on hover. Weight is left to the wordmark, which is the only
   thing in the bar that should be asking for attention. Everything in the row
   is one height and one text size, so the bar has a single rhythm whatever
   sits in it. */

header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-raised);
  flex: none;
}

header :where(#file-toggle, #reset, #run, .indicator, .group button) {
  height: 1.75rem;
  font-size: 0.8125rem;
}

/* An action, so the foreground colour, at the bar's one height and size. */
/* A labelled action with no icon of its own. */
#file-toggle { padding: 0 0.5rem; }

header svg { width: 15px; height: 15px; fill: currentColor; display: block; }

/* Square, so an icon on its own has the same hit area as its neighbours
   rather than a short wide slab around a small glyph - and wider only when
   it has a count to carry. */
.group button { min-width: 1.75rem; padding: 0 0.35rem; gap: 0.3rem; }

/* Tight, because these are one toolbar rather than three loose controls
   sharing the bar's spacing with the indicators beside them. */
.group { display: flex; align-items: center; gap: 0.125rem; margin-right: -0.25rem; }

.group button { color: var(--fg-muted); }
.group button:hover:not(:disabled) { color: var(--fg); }

.wordmark {
  font-size: 0.95rem;
  font-weight: 600;
  margin: 0;
  white-space: nowrap;
}

.wordmark span { color: var(--fg-muted); font-weight: 400; }

/* Reads as the page's name rather than as a link, so it is not underlined
   and takes the colours around it. */
.wordmark a { color: inherit; text-decoration: none; }
.wordmark a:hover { color: var(--accent); }
.wordmark a:hover span { color: inherit; }

/* Separates the name from the controls, so the gap between them does not
   have to be wide enough to say it on its own. */
.divider {
  width: 1px;
  height: 1.25rem;
  background: var(--border);
  flex: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
}

button:hover:not(:disabled) { background: color-mix(in srgb, var(--fg) 8%, transparent); }
button:disabled { cursor: default; opacity: 0.45; }
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

#fullscreen .exit { display: none; }
:root:fullscreen #fullscreen .enter { display: none; }
:root:fullscreen #fullscreen .exit { display: block; }

.spacer { margin-left: auto; }

/* The status indicators. A dot carries the state at a glance and the
   tooltip explains it, which is the part a first-time reader needs. One
   shape for both, so the pair reads as a pair - including the transparent
   border, which is what every button in the bar is sized with and what the
   compiler span would otherwise be two pixels short of. */
.indicator {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0 0.4rem;
  color: var(--fg-muted);
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: 6px;
}

/* The analyser's indicator is a button only so that a click can reconnect
   it. While there is nothing to reconnect it behaves as the label beside it. */
button.indicator:is([data-state="ready"], [data-state="connecting"]) { cursor: default; }
button.indicator:is([data-state="ready"], [data-state="connecting"]):hover { background: none; }

.indicator .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--fg-muted);
  flex: none;
}

/* By state rather than by indicator, so each page's indicators share one
   vocabulary: ready is green, anything under way pulses amber, a failure is
   red, and a service that is resting or switched off is grey. */
.indicator[data-state="ready"] .dot { background: var(--ok); }

.indicator:is([data-state="working"], [data-state="connecting"], [data-state="running"]) .dot {
  background: var(--warn);
  animation: pulse 1.2s ease-in-out infinite;
}

.indicator:is([data-state="failed"], [data-state="disconnected"]) .dot { background: var(--bad); }

.indicator:is([data-state="dormant"], [data-state="off"], [data-state="idle"]) .dot { background: var(--fg-muted); }

@keyframes pulse { 50% { opacity: 0.25; } }

/* --- the about panel --- */

#help {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  /* Above the images overlay and the file menu both: it is the topmost
     thing on the page whenever it is open. */
  z-index: 30;
}

#help[hidden] { display: none; }

#help article {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow);
  max-width: 34rem;
  max-height: 100%;
  overflow: auto;
  padding: 1.25rem 1.5rem 1.5rem;
}

#help h2 { margin: 0 0 0.75rem; font-size: 1.05rem; }
#help h3 { margin: 1.25rem 0 0.4rem; font-size: 0.9rem; }
#help p, #help li { line-height: 1.55; color: var(--fg); margin: 0.5rem 0; }
#help ul { margin: 0.5rem 0; padding-left: 1.2rem; }
#help a { color: var(--accent); }
#help code, kbd {
  font-family: var(--mono);
  font-size: 0.85em;
  background: color-mix(in srgb, var(--fg) 8%, transparent);
  padding: 0.1em 0.35em;
  border-radius: 4px;
}

#help footer { margin-top: 1.25rem; display: flex; justify-content: flex-end; }
#help footer button { border-color: var(--border); padding: 0.35rem 0.9rem; }

/* --- narrow screens ---

   A phone is too narrow for every label in the bar. The indicators keep their
   dots, which carry the state, and the tooltips still explain it; the divider
   goes, since the gap it marks is gone. What still does not fit wraps onto a
   second row rather than off the edge, where a control could not be reached. */
@media (max-width: 640px) {
  header { gap: 0.35rem; row-gap: 0.25rem; padding: 0.4rem; flex-wrap: wrap; }
  header .icon-label { display: none; }
  header .divider { display: none; }
  .indicator > span:not(.dot) { display: none; }
}

/* Run, which becomes Stop while there is something to stop. The playground
   runs a program with it and the REPL a cell. */
#run {
  padding: 0 0.7rem 0 0.55rem;
  border-color: var(--border);
  background: var(--bg);
}

/* New session is an action too, so it has Run's outline and an icon of its
   own; without them it reads as the session's title. */
#reset {
  padding: 0 0.7rem 0 0.55rem;
  border-color: var(--border);
  background: var(--bg);
}

#reset svg { width: 14px; height: 14px; fill: var(--fg-muted); }

/* A shade smaller than the bar's icons, so the triangle sits inside the
   button's border rather than filling it. */
#run svg { width: 14px; height: 14px; fill: var(--ok); }
#run:disabled svg { fill: var(--fg-muted); }

/* Shown in place of the play triangle while a run is in flight, so the
   button itself carries the progress rather than only the status text. */
#run .spinner { display: none; width: 14px; height: 14px; }
#run[data-busy] .spinner { display: block; animation: spin 0.9s linear infinite; }
#run[data-busy] .play { display: none; }

/* Once the program is actually running there is something to stop, so the
   button becomes that instead - the spinner goes, because the square is
   now what says a run is in flight. */
#run .stop { display: none; width: 12px; height: 12px; fill: var(--bad); }
#run[data-stop] .stop { display: block; }
#run[data-stop] .play, #run[data-stop] .spinner { display: none; }

@keyframes spin { to { transform: rotate(360deg); } }
