/* ==========================================================================
  global
  =========================================================================== */
:root {
  --font-family-system-ui:
    system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
    "Segoe UI Symbol", "Noto Color Emoji";
  --font-family-ui-monospace:
    ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas,
    "DejaVu Sans Mono", monospace;

  --color-gray-1: oklch(0.15 0 0);
  --color-gray-2: oklch(0.25 0 0);
  --color-gray-3: oklch(0.35 0 0);
  --color-gray-4: oklch(0.45 0 0);
  --color-gray-5: oklch(0.6 0 0);
  --color-gray-6: oklch(0.7 0 0);
  --color-gray-7: oklch(0.8 0 0);
  --color-gray-8: oklch(0.9 0 0);
  --color-red: oklch(0.7 0.1 30);
  --color-orange: oklch(0.7 0.1 60);
  --color-yellow: oklch(0.7 0.1 90);
  --color-green: oklch(0.7 0.1 150);
  --color-blue: oklch(0.7 0.1 240);
  --color-purple: oklch(0.7 0.1 300);

  --color-bg-dark: var(--color-gray-1);
  --color-bg-dim: var(--color-gray-2);
  --color-bg-light: var(--color-gray-3);
  --color-bg-bright: var(--color-gray-4);

  --color-border-dim: var(--color-gray-2);
  --color-border-light: var(--color-gray-3);
  --color-border-bright: var(--color-gray-4);

  --color-text-dark: var(--color-gray-5);
  --color-text-dim: var(--color-gray-6);
  --color-text-light: var(--color-gray-7);
  --color-text-bright: var(--color-gray-8);

  --color-primary: var(--color-blue);
  --color-info: var(--color-text-light);
  --color-ok: var(--color-green);
  --color-notice: var(--color-red);
  --color-error: var(--color-red);

  --filter-darker: brightness(80%);
  --filter-brighter: brightness(115%);

  --size-2xs: 0.25rem;
  --size-xs: 0.5rem;
  --size-s: 0.75rem;
  --size-m: 1rem;
  --size-l: 1.25rem;
  --size-xl: 1.5rem;

  --space-block: var(--size-m);
  --space-inline: var(--size-xs);
  --icon-vertical-align: -0.125em;

  --border-dim: var(--color-border-dim) solid 1px;
  --border-light: var(--color-border-light) solid 1px;
  --border-bright: var(--color-border-bright) solid 1px;
  --border-current: var(--color-primary) solid 1px;

  --border-radius-s: var(--size-2xs);
  --border-radius-m: var(--size-xs);

  --altcha-color-error-text: var(--color-error);
  --altcha-color-border: var(--color-border-light);
  --altcha-color-border-focus: var(--color-border-bright);
  --altcha-border-radius: var(--border-radius-s);
}

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

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
  background-color: var(--color-bg-dark);
  height: 100%;
  color: var(--color-text-light);
  font-family: var(--font-family-system-ui);
}

body {
  display: flex;
  justify-content: center;
  min-height: 100vh;
  line-height: 1.2;
  -webkit-font-smoothing: antialiased;
}

/* links */
a {
  color: var(--color-primary);
  text-decoration-line: none;

  &:hover,
  &:focus {
    filter: var(--filter-brighter);
  }

  &:focus-visible {
    outline: var(--border-bright);
  }

  &:visited {
    color: var(--color-purple);
  }
}

/* media */
img,
svg {
  display: block;
  max-width: 100%;
}

/* headings */
h1 {
  margin-block: var(--space-block);
  font-size: var(--size-xl);
}

h2 {
  margin-block: var(--space-block);
  font-size: var(--size-l);
}

h3 {
  margin-block: var(--space-block);
  font-size: var(--size-m);
}

h4,
h5,
h6 {
  margin-block: var(--space-block);
  font-size: var(--size-m);
}

/* paragraphs */
p {
  margin-block: var(--space-block);
}

blockquote {
  margin-block-start: var(--space-block);
  border-left: var(--color-bg-light) solid var(--size-2xs);
  padding: calc(var(--space-block) / 2);
  color: var(--color-text-dim);
}

pre,
code {
  margin-block-start: var(--space-block);
  background-color: var(--color-bg-dim);
  font-family: var(--font-family-ui-monospace);
  white-space: pre-wrap;
  word-break: break-all;
}

pre:has(code) {
  border-radius: var(--border-radius-s);
  background-color: var(--color-bg-dim);
  padding: calc(var(--space-block) / 4) calc(var(--space-inline) / 2);
}

/* lists */
ul,
ol {
  margin-block-start: var(--space-block);
  padding-inline-start: calc(var(--space-inline) * 3);

  ul,
  ol {
    margin-block-start: 0;
  }
}

ul.no-bullets {
  padding-inline-start: 0;
  list-style-type: none;
}

/* tables */
table {
  margin-block-start: var(--space-block);
  border-collapse: separate;
  border-spacing: 0 1px;
  width: 100%;

  th {
    background-color: var(--color-bg-light);
    text-align: left;
  }

  tr:nth-child(odd) {
    background-color: var(--color-bg-dim);
  }

  .empty-row {
    background-color: var(--color-bg-dark);
    height: 1em;
  }
}

/* forms */
form {
  display: flex;
  flex-direction: column;
  gap: calc(var(--space-block) / 2);
  margin-block-start: var(--space-block);
}

fieldset {
  border: var(--border-dim);
  border-radius: var(--border-radius-s);
}

input,
button,
textarea,
select {
  font: inherit;
}

input,
select,
textarea {
  border: var(--border-light);
  border-radius: var(--border-radius-s);
  background-color: var(--color-bg-dim);
  resize: vertical;
  scrollbar-color: var(--color-bg-light) var(--color-bg-dim);
  scrollbar-width: thin;
  color: var(--color-text-light);
}

input[type="submit"] {
  padding: calc(var(--space-block) / 4) var(--space-inline);
}

select {
  width: 100%;
}

textarea {
  height: calc(var(--space-block) * 8);
}

input:active,
input:focus,
select:active,
select:focus,
textarea:active,
textarea:focus {
  outline: none;
  border: var(--border-bright);
}

input[type="checkbox"]:has(+ *),
input[type="radio"]:has(+ *) {
  margin-inline-end: calc(var(--space-inline) / 2);
}

input[type="checkbox"]:active,
input[type="checkbox"]:focus {
  outline: var(--border-bright);
}

input[type="submit"]:active {
  background-color: var(--color-bg-light);
}

option:checked {
  background-color: var(--color-bg-light);
  color: var(--color-text-light);
}

/* misc. */
hr {
  border: var(--border-light);
}

/* ==========================================================================
  Utilities
  =========================================================================== */
.middle {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--space-block) / 4);
  margin-block-start: 20vh;

  * {
    margin: 0;
  }
}

.bracketed {
  &::before {
    content: "[";
  }

  &::after {
    content: "]";
  }
}

.comma-separate > :not(:last-child):after {
  content: ", ";
}

.dot-separate > :not(:last-child)::after {
  content: " · ";
}

.token {
  user-select: all;
}

.user-text {
  overflow-wrap: anywhere;

  :first-child {
    margin-block-start: 0;
    padding-block-start: 0;
  }

  :last-child {
    margin-block-end: 0;
    padding-block-end: 0;
  }
}

/* ==========================================================================
  Components
  =========================================================================== */
#error {
  font-size: var(--size-s);
  font-family: var(--font-family-ui-monospace);

  .error-logo {
    font-size: var(--size-xs);
    white-space: pre;
  }
}

#root {
  display: flex;
  flex-direction: column;
  margin-inline: calc(var(--space-inline) / 2) var(--space-inline);
  margin-block: calc(var(--space-block) / 4) calc(var(--space-block));
  width: 80ch;
}

#main {
  flex-grow: 1;
}

/* headers and footers */
.base-footer {
  display: flex;
  column-gap: calc(var(--space-inline) * 2);
  justify-content: center;
  align-items: center;
  margin-block-start: calc(var(--space-block) * 1.5);
  font-size: var(--size-s);
}

/* nav */
.navbar {
  display: flex;

  justify-content: space-between;
  align-items: center;

  .navbar-nav {
    column-gap: var(--space-inline);
  }

  .navbar-brand {
    a {
      color: inherit;
    }

    /* FIXME: why do we have to set the width? */
    .logo {
      fill: currentColor;
      width: 70.33px;
      height: calc(var(--space-block) * 1.25);
    }
  }
}

.nav-links {
  a {
    padding: calc(var(--space-block) / 4) 0;
    color: inherit;

    &:visited {
      color: inherit;
    }

    &.current {
      border-bottom: var(--border-current);
    }
  }
}

.nav-buttons {
  display: flex;

  a {
    display: inline-flex;
    align-items: center;
    border: var(--border-light);
    border-radius: var(--border-radius-s);
    padding: calc(var(--space-block) / 4) var(--space-inline);
    height: 100%;
    color: inherit;

    &:visited {
      color: inherit;
    }

    &.current {
      border: var(--border-current);
    }
  }
}

.nav-pills {
  display: flex;
  gap: var(--space-inline);
  margin-block-start: var(--space-block);
  font-size: var(--size-s);

  a {
    display: inline-flex;
    align-items: center;
    border: var(--border-light);
    border-radius: var(--border-radius-m);
    padding: calc(var(--space-block) / 4) var(--space-inline);
    height: 100%;
    color: inherit;

    &:visited {
      color: inherit;
    }

    &.current {
      border: var(--border-current);
    }
  }
}

.nav-tabs {
  display: flex;
  gap: calc(var(--space-inline) * 1.5);
  margin-block-start: var(--space-block);
  border-bottom: var(--border-dim);

  a {
    display: inline-flex;
    align-items: center;
    padding: calc(var(--space-block) / 4) 0;
    height: 100%;
    color: inherit;

    &:visited {
      color: inherit;
    }

    &.current {
      border-bottom: var(--border-current);
    }
  }
}

/* images */
.icon {
  display: inline-block;
  vertical-align: var(--icon-vertical-align);
  width: 1em;
  min-width: 1em;
  height: 1em;
  line-height: 1;

  & + :not(&) {
    margin-inline-start: calc(var(--space-inline) / 4);
  }
}

.icon-text {
  white-space: nowrap;
}

.labeled-icon {
  white-space: nowrap;
}

.avatar {
  border-radius: 50%;
}

/* banners and alerts */
.info {
  color: var(--color-info);
}

.ok {
  color: var(--color-ok);
}

.notice {
  color: var(--color-notice);
}

.error {
  color: var(--color-error);
}

.banner {
  margin-block-start: var(--space-block);
  border: var(--border-bright);
  border-radius: var(--border-radius-s);
  padding: calc(var(--space-block) / 4) calc(var(--space-inline) / 2);

  &.ok {
    animation: dissolve 5s ease-out forwards;
    border-color: var(--color-ok);
  }

  &.error {
    border-color: var(--color-error);
  }

  & + & {
    margin-block-start: calc(var(--space-block) / 4);
  }
}

.alert {
  &.ok {
    animation: dissolve 5s ease-out forwards;
  }
}

@keyframes dissolve {
  0% {
    opacity: 1;
  }

  80% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

/* htmx */
[data-loading] {
  display: none;
}

.loading {
  animation: spin 0.5s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

/* pagination */
.pagination {
  margin-block-start: calc(var(--space-block) * 1.5);
  text-align: center;

  a {
    margin-inline: calc(var(--space-inline) * 1.25);
  }
}

/* titles */
.title {
  color: var(--color-text-bright);
  font-size: var(--size-xl);

  &::before {
    content: "❯ ";
    color: var(--color-primary);
  }
}

.subtitle {
  font-size: var(--size-l);
}

/* layouts */
.user-profile-view {
  position: relative;
  margin-block-start: var(--space-block);

  .avatar {
    position: absolute;
    top: 0px;
    right: 0px;
    width: 80px;
    height: 80px;
  }
}

.label-left {
  display: grid;
  grid-template-columns: 1fr 3fr;
  grid-auto-rows: minmax(var(--space-block), auto);
  gap: calc(var(--space-block) / 4);

  .only-label {
    display: flex;
    grid-column: span 2;
  }

  .no-label {
    display: flex;
    grid-column-start: 2;
  }
}

/* tags */
.tag {
  display: inline-block;
  border: var(--border-light);
  border-radius: var(--border-radius-m);
  background-color: var(--color-bg-dim);
  padding: 0 calc(var(--space-inline) / 2);
  color: inherit;
  font-size: var(--size-s);

  &:visited {
    color: inherit;
  }

  &.managed {
    color: var(--color-yellow);
  }

  &.computed {
    color: var(--color-orange);
  }

  &.community {
    color: var(--color-text-dim);
  }

  &:has(+ &) {
    margin-inline-end: calc(var(--space-inline) / 2);
  }
}

span.tag:hover {
  cursor: default;
}

/* post/comment common */
.post-meta,
.post-actions,
.comment-meta,
.comment-actions {
  margin-block: calc(var(--space-block) / 4);
  color: var(--color-text-dark);
  font-size: var(--size-s);

  a,
  a:visited {
    color: inherit;
  }
}

.post-meta,
.comment-meta {
  .username-flags {
    color: var(--color-border-bright);

    &::before,
    &::after {
      vertical-align: calc(var(--icon-vertical-align) * -1);
    }

    .creator {
      color: var(--color-yellow);
    }

    .pseudonymous {
      color: var(--color-text-dark);
    }

    .user {
      color: var(--color-green);
    }
  }
}

.post-actions,
.comment-actions {
  .labeled-icon {
    margin-inline-end: var(--space-inline);
  }
}

.post-meta {
  margin-inline-end: var(--space-inline);
}

/* posts */
.post-header {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: calc(var(--space-inline) / 4);
  margin-block-start: var(--space-block);

  .post-comments {
    display: inline-grid;
    width: fit-content;

    .icon {
      grid-area: 1 / 1;
      width: 3em;
      height: 3em;
      color: var(--color-border-bright);
    }

    .icon-text {
      grid-area: 1 / 1;
      justify-self: center;
      margin-top: 0.65em;
      margin-left: 0;
      color: var(--color-text-light);
      font-size: var(--size-m);
    }
  }
}

.post-headline {
  .post-icons {
    vertical-align: middle;
  }

  .post-title {
    vertical-align: middle;
  }

  .post-url-host {
    color: var(--color-border-bright);
    font-size: var(--size-s);

    a,
    a:visited {
      color: var(--color-text-dim);
    }
  }
}

.poll {
  .user-text {
    margin-block-start: 0;
  }

  .poll-results {
    display: grid;
    grid-template-columns: 1fr min-content;
    gap: calc(var(--space-block) / 4);
    margin-block-start: var(--space-block);
    border: var(--border-dim);
    border-radius: var(--border-radius-s);
    padding: calc(var(--space-block) / 4);

    .poll-choice {
      position: relative;
      padding: calc(var(--space-block) / 4);
    }

    .poll-choice-bar {
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      z-index: -1;
      border-radius: var(--border-radius-s);
      background: var(--color-bg-dim);
      height: 100%;
    }

    .poll-choice-value {
      place-content: center;
      padding: calc(var(--space-block) / 4);
      text-align: right;
      white-space: nowrap;
    }

    .poll-choice-leading {
      color: var(--color-text-bright);
      font-weight: bold;

      .poll-choice-bar {
        background: var(--color-bg-light);
      }
    }

    .poll-info {
      margin-inline: calc(var(--space-inline) / 2) 0;
      margin-block: calc(var(--space-block) / 2) 0;
      color: var(--color-text-dark);
      font-size: var(--size-s);
    }
  }
}

/* comments */
.comment {
  margin-block-start: var(--space-block);

  &:target {
    animation: highlight 3s ease-out;
  }

  &.new-reply {
    border-left: var(--color-primary) solid 1px;
    padding-left: calc(var(--space-inline) / 2);
  }
}

@keyframes highlight {
  0% {
    background-color: var(--color-bg-bright);
  }

  100% {
    background-color: transparent;
  }
}

.comment-tree {
  margin-inline-start: var(--space-inline);
  margin-block-start: var(--space-block);

  .comment-indent {
    margin-inline-start: var(--space-inline);
    border-left: var(--border-dim);
    border-left-style: dotted;
    padding-inline-start: var(--space-inline);
  }

  summary::marker {
    content: "[+]";
  }

  details[open] summary::marker {
    content: "[−]";
  }

  details:not([open]) {
    filter: var(--filter-darker);
  }
}

/* ==========================================================================
  Media queries
  =========================================================================== */
@media (max-width: 576px) {
  .collapse-icon {
    .icon {
      display: none;
    }
  }

  .collapse-text {
    .icon-text {
      display: none;
    }
  }

  .label-left {
    grid-template-columns: 1fr 2fr;
  }
}
