/* Monospace, hairline rules, no cards, no accent colour anywhere. Hierarchy comes from
   size and opacity, never from a box or a fill. The only thing on the page allowed to
   look like a widget is an app, because an app is the content. */

:root {
  color-scheme: light dark;
  --bg: #fcfcfc;
  /* The frame sits on its own plane, a shade off the page ground in both themes. That
     one step is what makes an embedded app read as an object rather than as more page. */
  --surface: #ffffff;
  --fg: #17181a;
  --muted: #86898e;
  --rule: #e2e4e7;
  --warn: #9a4a33;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0c0d0e;
    --surface: #131517;
    --fg: #e6e7e9;
    --muted: #71757a;
    --rule: #24272a;
    --warn: #d08466;
  }
}

* { box-sizing: border-box; }
html, body { margin: 0; background: var(--bg); color: var(--fg); }
body {
  font-family: ui-monospace, "SF Mono", "SFMono-Regular", "Cascadia Mono", Menlo, Consolas, monospace;
  font-size: 15px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: 1px; }
button, input, textarea { font: inherit; color: inherit; }

main { max-width: 680px; margin: 0 auto; padding: 9vh 28px 16vh; }
@media (max-width: 520px) { main { padding: 6vh 20px 12vh; } }

/* Header */
header { margin-bottom: 8vh; }
.top { display: flex; align-items: baseline; gap: 1.5ch; }
.wordmark { font-size: 15px; font-weight: 600; margin: 0; text-decoration: none; }
.tagline { color: var(--muted); margin: 0.2rem 0 0; max-width: 56ch; }
.who { margin-left: auto; color: var(--muted); font-size: 13px; white-space: nowrap; }
.who button {
  border: 0; background: none; padding: 0; color: var(--muted); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.who button:hover { color: var(--fg); }

/* One app */
.item { border-top: 1px solid var(--rule); padding: 2.4rem 0 2rem; }
.item h2, .item h1 { font-size: 15px; font-weight: 600; margin: 0; }
.item h2 a { text-decoration: none; }
.item h2 a:hover { text-decoration: underline; }
.readme { margin: 0.15rem 0 0; }
.meta { margin: 0.35rem 0 0; color: var(--muted); font-size: 13px; }
.meta a { color: var(--muted); }
.meta .sep { padding: 0 0.7ch; opacity: 0.5; }
.meta .warn { color: var(--warn); }

/* Where a fork came from, quoted. A fork is a new object and stands on its own, but it
   started as somebody else's idea and the page should say so without being asked: the
   parent is attached to the child, with the sentence that made it. */
.quote {
  margin-top: 0.9rem;
  border-left: 2px solid var(--rule);
  padding: 0.1rem 0 0.1rem 1.5ch;
}
.quote .from { color: var(--muted); font-size: 12px; }
.quote .from::before { content: "\2442  "; }
.quote .name { text-decoration: none; font-weight: 600; }
.quote .name:hover { text-decoration: underline; }
.quote .desc { margin: 0.1rem 0 0; font-size: 13px; }
.quote .said { color: var(--muted); font-size: 13px; margin: 0.25rem 0 0; }
.quote .said::before { content: "\201C"; }
.quote .said::after { content: "\201D"; }

/* The other direction: what came out of this one. */
.forks { margin-top: 1.4rem; }
.forks > .from { color: var(--muted); font-size: 12px; }
.forks .f { border-top: 1px solid var(--rule); padding: 0.7rem 0; }
.forks .f a { text-decoration: none; font-weight: 600; }
.forks .f a:hover { text-decoration: underline; }
.forks .f p { margin: 0.1rem 0 0; color: var(--muted); font-size: 13px; }

/* THE FRAME. The app is a bounded surface with its own plane and its own edge, and the
   prompt is docked to it, so what you are looking at reads as one embedded running
   object rather than as more page. Everything the object owns lives inside this box;
   everything about it lives outside. It is the one exception to "no boxes" on the site,
   and it earns it by being the content. */
.frame {
  margin-top: 1.1rem;
  border: 1px solid var(--rule);
  border-radius: 5px;
  background: var(--surface);
  overflow: hidden;
}
.frame-top {
  display: flex; align-items: baseline; gap: 1ch;
  padding: 0.4rem 0.75rem;
  border-bottom: 1px solid var(--rule);
  color: var(--muted); font-size: 12px;
}
.frame-top .addr { margin-left: auto; }
.frame-top a { color: var(--muted); }
.stage { min-height: 3rem; }
.stage iframe { display: block; width: 100%; border: 0; background: transparent; }

/* The docked bar. ONE action: you write what you would change, you press the button, you
   get your own copy. It read as two competing choices because nothing looked like a field
   and nothing looked like a button, so the placeholder and the label were just two bits of
   sentence sitting next to each other. The field is a field now and the button is a
   button, which is the whole fix. */
.prompt {
  display: flex; align-items: center; gap: 0.75ch;
  padding: 0.55rem 0.75rem;
  border-top: 1px solid var(--rule);
  flex-wrap: wrap;
}
.prompt input {
  flex: 1; min-width: 12ch;
  border: 0; border-bottom: 1px solid var(--rule);
  background: none; padding: 0.3rem 0; outline: none;
}
.prompt input:focus { border-bottom-color: var(--fg); }
.prompt input::placeholder { color: var(--muted); }
.prompt button {
  border: 1px solid var(--rule); border-radius: 4px;
  background: none; padding: 0.3rem 0.8rem; cursor: pointer;
  color: var(--fg); white-space: nowrap;
}
.prompt button:hover:not(:disabled) { border-color: var(--fg); }
.prompt button.second { color: var(--muted); }
.prompt button.second:hover:not(:disabled) { color: var(--fg); }
.prompt button:disabled { opacity: 0.4; cursor: default; }
.note {
  padding: 0 0.75rem 0.55rem;
  color: var(--muted); font-size: 12px;
}
.note:empty { display: none; }
.note .warn { color: var(--warn); }
.note button {
  border: 0; background: none; padding: 0; color: var(--muted); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.note button:hover { color: var(--fg); }

/* Source, folded away */
details { border-top: 1px solid var(--rule); }
details > summary {
  padding: 0.7rem 0; cursor: pointer; color: var(--muted); font-size: 13px; list-style: none;
}
details > summary::-webkit-details-marker { display: none; }
details > summary::before { content: "+ "; }
details[open] > summary::before { content: "\2013 "; }
details > summary:hover { color: var(--fg); }
pre {
  margin: 0 0 1.2rem; padding: 0 0 0 2ch; overflow-x: auto; font-size: 13px;
  color: var(--muted); white-space: pre-wrap; word-break: break-word;
}

/* The thread */
.thread { margin-top: 8vh; }
.thread h2 { font-size: 13px; font-weight: 400; margin: 0 0 0.2rem; color: var(--muted); }
.p { border-top: 1px solid var(--rule); padding: 1.1rem 0; }
.p .said { margin: 0; }
.p .by { margin: 0.2rem 0 0; color: var(--muted); font-size: 13px; }
.p .by a { color: var(--muted); }
.p.failed .by { color: var(--warn); }

.empty { color: var(--muted); padding: 2.4rem 0; border-top: 1px solid var(--rule); }
footer {
  border-top: 1px solid var(--rule); margin-top: 8vh; padding-top: 1.6rem;
  color: var(--muted); font-size: 13px;
}
footer a { color: var(--muted); }

.spin { display: inline-block; animation: sp 1s steps(8) infinite; }
@keyframes sp { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation: none; } }

/* A card that arrived while you were looking. It settles rather than snapping in, and
   under prefers-reduced-motion it simply appears. */
.item.arriving { opacity: 0; transform: translateY(-6px); }
.item { transition: opacity 0.25s ease, transform 0.25s ease; }
@media (prefers-reduced-motion: reduce) {
  .item { transition: none; }
  .item.arriving { opacity: 1; transform: none; }
}