/* Gigit's only stylesheet. Spec section 10: one hand-written file, no
   framework, no build step, no CDN. Everything a page can show is styled
   here, so a page only ever needs the helpers in html.ts. */

/* ------------------------------------------------------------- the palette
   Every colour in the app is one of these. Dark mode below redefines the
   same names and nothing else, so no rule is ever written twice. */

:root {
  color-scheme: light dark;

  --bg: #f6f8fa;
  --surface: #ffffff;
  --surface-2: #f6f8fa;
  --surface-3: #eaeef2;
  --border: #d0d7de;
  --border-strong: #afb8c1;

  --text: #1f2328;
  --text-muted: #59636e;

  --accent: #0969da;
  --accent-hover: #0860ca;
  --accent-fg: #ffffff;
  --accent-soft: #ddf4ff;

  --success: #1a7f37;
  --success-soft: #dafbe1;
  --danger: #cf222e;
  --danger-soft: #ffebe9;
  --warn: #9a6700;
  --warn-soft: #fff8c5;

  /* Diffs get their own pair so a tweak to the semantic colours above never
     changes how a patch reads. */
  --diff-add: #e6ffec;
  --diff-del: #ffebe9;
  --diff-hunk-bg: #ddf4ff;
  --diff-hunk-fg: #0550ae;

  /* The nav and the deploy log are dark in both themes: one is chrome, the
     other is a terminal. */
  --nav-bg: #24292f;
  --nav-fg: #ffffff;
  --nav-fg-muted: #d0d7de;
  --term-bg: #0d1117;
  --term-fg: #d5dbe3;

  --radius: 6px;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0d1117;
    --surface: #151b23;
    --surface-2: #1b2028;
    --surface-3: #262c36;
    --border: #3d444d;
    --border-strong: #4d545e;

    --text: #e6edf3;
    --text-muted: #9198a1;

    --accent: #4493f8;
    --accent-hover: #58a6ff;
    --accent-fg: #ffffff;
    --accent-soft: #121d2f;

    --success: #3fb950;
    --success-soft: #12261e;
    --danger: #f85149;
    --danger-soft: #291415;
    --warn: #d29922;
    --warn-soft: #272115;

    --diff-add: #12261e;
    --diff-del: #291415;
    --diff-hunk-bg: #121d2f;
    --diff-hunk-fg: #4493f8;

    --nav-bg: #151b23;
    --nav-fg: #e6edf3;
    --nav-fg-muted: #9198a1;
  }
}

/* ---------------------------------------------------------------- the page */

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
  /* The page column never scrolls sideways; wide things scroll in .scroll-x. */
  overflow-x: hidden;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

p {
  margin: 0 0 10px;
}

p:last-child {
  margin-bottom: 0;
}

ul {
  margin: 6px 0;
  padding-left: 20px;
}

code {
  font-family: var(--mono);
  font-size: 0.92em;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--surface-3);
  overflow-wrap: anywhere;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

.main {
  max-width: 1120px;
  margin: 0 auto;
  padding: 20px 16px 64px;
}

/* The one vertical rhythm in the app: every page is a stack of boxes. */
.stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.main > .box {
  margin-bottom: 16px;
}

/* ------------------------------------------------------------------- nav */

.nav {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  padding: 0 16px;
  min-height: 48px;
  background: var(--nav-bg);
  color: var(--nav-fg);
}

.nav a {
  color: var(--nav-fg-muted);
}

.nav-brand {
  font-size: 15px;
  font-weight: 600;
  color: var(--nav-fg) !important;
}

.nav a:hover {
  color: var(--nav-fg);
  text-decoration: none;
}

.nav-links {
  display: flex;
  gap: 16px;
}

.nav-spacer {
  flex: 1 1 auto;
}

.nav-user {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* The account menu: a details element dressed as a dropdown. nav.js only
   adds closing it on an outside click or Escape. */
.nav-menu {
  position: relative;
}

.nav-menu > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: var(--radius);
  color: var(--nav-fg-muted);
  cursor: pointer;
  user-select: none;
  list-style: none;
}

.nav-menu > summary::-webkit-details-marker {
  display: none;
}

.nav-menu > summary:hover,
.nav-menu[open] > summary {
  background: rgba(127, 127, 127, 0.25);
  color: var(--nav-fg);
}

/* The caret sits one step under the 16px default so it does not shout next
   to 14px nav text. Two classes because ".icon" is defined further down the
   file and would otherwise win on size. */
.icon.nav-menu-caret {
  width: 14px;
  height: 14px;
}

.nav-menu[open] .nav-menu-caret {
  transform: rotate(180deg);
}

.nav-menu-list {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 20;
  min-width: 180px;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.22);
}

/* Both rows are one control each; the logout one has to be a form post, so
   its button is stripped back to look like the link above it. */
.nav-menu-list a,
.nav-menu-list button {
  display: block;
  width: 100%;
  padding: 6px 10px;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--text) !important;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.nav-menu-list a:hover,
.nav-menu-list button:hover {
  background: var(--surface-3);
  text-decoration: none;
}

/* ------------------------------------------------------------------ boxes
   win() in html.ts renders one of these for every titled region. */

.box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.box-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  border-radius: var(--radius) var(--radius) 0 0;
}

.box-title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.box-actions {
  display: flex;
  gap: 4px;
}

.box-actions button {
  min-width: 26px;
  padding: 2px 6px;
  font-size: 12px;
}

.box-body {
  padding: 14px;
}

/* Where the status bar used to be: one muted line, and the region kanban.js
   and log.js write progress and errors into. */
.box-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  padding: 8px 14px;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 12px;
}

.box-foot-item {
  margin: 0;
}

/* A plain bordered container. sunken() wraps anything that needs an edge of
   its own inside a box: a table, a diff, a blob. */
.frame {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.scroll-x {
  overflow-x: auto;
}

/* --------------------------------------------------------------- tables */

.grid {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.grid th {
  padding: 8px 12px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  color: var(--text-muted);
  font-weight: 600;
  text-align: left;
  white-space: nowrap;
}

.grid td {
  padding: 7px 12px;
  border-top: 1px solid var(--border);
  vertical-align: top;
}

/* The first row sits against the frame edge or the header, never both. */
.grid tbody tr:first-child td {
  border-top: none;
}

.grid thead + tbody tr:first-child td {
  border-top: 1px solid var(--border);
}

/* Each action in a table cell is its own little post form; they belong on
   one line, not stacked. */
.grid td > form {
  display: inline-block;
}

.grid td > form + form {
  margin-left: 6px;
}

/* Headerless two column tables: commit metadata, run metadata, account. */
.kv td:first-child {
  width: 1%;
  white-space: nowrap;
  color: var(--text-muted);
}

/* -------------------------------------------------------------- controls */

button,
input,
select,
textarea {
  font: inherit;
  color: var(--text);
}

input[type="text"],
input[type="password"],
input[type="file"],
select,
textarea {
  padding: 5px 10px;
  min-height: 32px;
  max-width: 100%;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
}

textarea {
  width: 100%;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.5;
  resize: vertical;
}

input[readonly] {
  background: var(--surface-2);
  color: var(--text-muted);
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}

label {
  color: var(--text-muted);
  font-weight: 500;
}

button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 5px 14px;
  min-height: 32px;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font-weight: 500;
  cursor: pointer;
}

button:hover {
  background: var(--surface-3);
}

button:active {
  background: var(--border);
}

button:disabled {
  opacity: 0.55;
  cursor: default;
}

/* One primary per form at most: the thing the page is for. */
button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
}

button.primary:hover:not(:disabled) {
  background: var(--accent-hover);
}

button.danger {
  color: var(--danger);
  border-color: var(--border-strong);
}

button.danger:hover:not(:disabled) {
  background: var(--danger);
  border-color: var(--danger);
  color: #ffffff;
}

/* Two shapes only. ".field-row" is a row of controls side by side, which is
   now always buttons or links; every labelled control is a stacked row, with
   the label on its own line above its input. */
.field-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.field-row + .field-row,
.field-row-stacked + .field-row,
.field-row + .field-row-stacked,
.field-row-stacked + .field-row-stacked {
  margin-top: 12px;
}

/* Inside a stack the gap already spaces them; the adjacency rule above is for
   the plain form bodies that are not one. */
.stack > .field-row,
.stack > .field-row-stacked {
  margin-top: 0;
}

.field-row-stacked {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 5px;
}

.field-row-stacked > label {
  font-size: 13px;
}

/* A stacked control fills its box, which is right for a card title or a body,
   but a select holds one short line, so it gets a column width instead. */
.field-row-stacked > select {
  max-width: 420px;
}

/* Same reason, for a form that is nothing but short fields: without this the
   inputs stretch the full width of the page and read as banners. */
.narrow-form {
  max-width: 420px;
}

/* ------------------------------------------------------------------ icons
   Lucide 1.38.0 (https://lucide.dev), ISC. The geometry is one <symbol>
   sprite printed by the page shell (src/icons.ts); every icon anywhere is a
   <use> pointing at it, so a glyph exists once per document however often it
   is drawn, and kanban.js builds one carrying no path data at all.

   A <use> renders into a shadow tree, so no rule may reach the shapes:
   ".icon path {...}" matches nothing and fails silently. Fill and stroke are
   inherited properties, so setting them here on the referencing <svg> is
   what crosses the boundary. That is also why no <symbol> carries a
   presentation attribute of its own: one there could not be overridden. */

.icon-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.icon {
  display: inline-block;
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  /* Sits the 16px box on the baseline of the 14px text beside it. */
  vertical-align: -0.125em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* A control whose whole label is its icon: the name lives in aria-label and
   title instead. Square, so a row of them reads as a row of them. This block
   must stay after ".box-actions button" and "button.danger", which are the
   same specificity and set the padding and rest colour it is overriding. */
button.icon-button {
  width: 28px;
  min-width: 28px;
  min-height: 28px;
  padding: 0;
  color: var(--text-muted);
}

button.icon-button:hover:not(:disabled) {
  color: var(--text);
}

button.icon-button.danger:hover:not(:disabled) {
  color: var(--accent-fg);
}

/* -------------------------------------------------------- repo header */

.repo-header {
  margin-bottom: 16px;
}

/* Inside a stack the gap already separates it. */
.stack > .repo-header {
  margin-bottom: 0;
}

.repo-title {
  margin: 0;
  font-size: 20px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.repo-desc {
  margin: 4px 0 0;
  color: var(--text-muted);
}

.repo-clone {
  margin-top: 12px;
  align-items: center;
}

.repo-clone input {
  flex: 1 1 320px;
  min-width: 0;
  font-family: var(--mono);
  font-size: 12px;
}

/* The section tabs. The active one carries aria-current, which is both the
   accessible answer and the styling hook. The underline is an inset shadow
   rather than a border so it cannot shift the row when a tab activates, and
   so the row still scrolls cleanly on a narrow screen. */
.tabs {
  display: flex;
  gap: 2px;
  margin-top: 14px;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
}

.tabs a {
  padding: 8px 14px;
  border-radius: var(--radius) var(--radius) 0 0;
  color: var(--text);
  white-space: nowrap;
}

.tabs a:hover {
  background: var(--surface-3);
  text-decoration: none;
}

.tabs a[aria-current="page"] {
  box-shadow: inset 0 -2px var(--accent);
  font-weight: 600;
}

/* ------------------------------------------------------------ breadcrumb */

.breadcrumb {
  margin-bottom: 12px;
  font-family: var(--mono);
  font-size: 13px;
  overflow-wrap: anywhere;
}

.breadcrumb .sep {
  color: var(--text-muted);
  padding: 0 2px;
}

/* ----------------------------------------------------------- file listing */

.tree-name {
  overflow-wrap: anywhere;
}

/* Directories read before files: heavier, and the row they lead to is the
   common case, so give them the whole cell width. */
.tree-dir a {
  font-weight: 600;
}

/* SHAs, refs and paths are all fixed width wherever they appear. */
.mono,
.sha {
  font-family: var(--mono);
  font-size: 12.5px;
}

/* ------------------------------------------------------------- activity */

.event {
  padding: 12px 14px;
}

.event-head {
  overflow-wrap: anywhere;
}

.event ul {
  margin: 6px 0 0;
  color: var(--text-muted);
}

/* --------------------------------------------------------------- pills */

.pill {
  display: inline-block;
  padding: 1px 9px;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.pill-queued {
  background: var(--surface-3);
  border-color: var(--border);
  color: var(--text-muted);
}

.pill-running {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}

.pill-success {
  background: var(--success-soft);
  border-color: var(--success);
  color: var(--success);
}

.pill-failed {
  background: var(--danger-soft);
  border-color: var(--danger);
  color: var(--danger);
}

.pill-error,
.pill-unknown {
  background: var(--warn-soft);
  border-color: var(--warn);
  color: var(--warn);
}

/* ----------------------------------------------------------- code views */

.plain {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-family: var(--mono);
  font-size: 13px;
}

/* preText inside a box body wants an edge of its own, like a code block. */
.box-body > .plain {
  padding: 10px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.diff,
.blob {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.45;
}

.diff td,
.blob td {
  padding: 0 10px;
  vertical-align: top;
  white-space: pre;
}

/* The gutter is scenery, not content: it must never land in a copied
   selection of the file. */
.diff .lineno,
.blob .lineno {
  width: 1%;
  padding: 0 8px;
  text-align: right;
  background: var(--surface-2);
  border-right: 1px solid var(--border);
  color: var(--text-muted);
  user-select: none;
}

.diff .add {
  background: var(--diff-add);
}

.diff .del {
  background: var(--diff-del);
}

.diff .hunk {
  background: var(--diff-hunk-bg);
  color: var(--diff-hunk-fg);
}

.diff-file {
  margin: 16px 0 6px;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.diff-file:first-child {
  margin-top: 0;
}

/* A terminal, so it stays dark in both themes. log.js appends to it and
   keeps it pinned to the bottom. */
.log-output {
  height: 60vh;
  margin: 0;
  padding: 10px 12px;
  overflow: auto;
  background: var(--term-bg);
  color: var(--term-fg);
  border-radius: var(--radius);
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- board */

.board {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 8px;
}

.board-column {
  flex: 0 0 280px;
  max-width: 280px;
}

.board-column .box-body {
  padding: 10px;
}

.board-cards {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 48px;
  max-height: 65vh;
  overflow-y: auto;
  margin-bottom: 10px;
}

.board-card {
  /* Grip in the first column, title and meta stacked in the second. */
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 6px;
  padding: 10px;
  background: var(--surface-2);
  cursor: grab;
}

/* Decoration, not a control: the whole card is what drags, so this only
   makes visible the affordance "cursor: grab" already implied. */
.board-card-grip {
  grid-column: 1;
  grid-row: 1;
  align-self: start;
  margin-top: 2px;
  color: var(--border);
}

.board-card:hover .board-card-grip {
  color: var(--text-muted);
}

.board-card:hover {
  border-color: var(--border-strong);
}

.board-card.dragging {
  opacity: 0.4;
}

/* The card title fills its card so the whole block reads as one target. */
.board-card-title {
  display: block;
  grid-column: 2;
  color: var(--text);
  font-weight: 500;
  overflow-wrap: anywhere;
}

.board-card-meta {
  display: flex;
  grid-column: 2;
  justify-content: space-between;
  gap: 8px;
  margin-top: 6px;
  color: var(--text-muted);
  font-size: 12px;
}

/* Each half is an icon plus its word, and the assignee half is what has to
   give when the name is long. */
.board-card-meta > span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}

.drop-line {
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
  pointer-events: none;
}

.board-add {
  flex: 0 0 240px;
}

/* The inline add-card and rename-column rows kanban.js builds. */
.inline-edit input[type="text"] {
  flex: 1 1 100%;
  min-width: 0;
}

/* ----------------------------------------------------------- attachments */

.attachment {
  padding: 10px;
}

.attachment-name {
  display: flex;
  align-items: center;
  gap: 6px;
  overflow-wrap: anywhere;
}

.thumb {
  max-width: 240px;
  height: auto;
  border-radius: 4px;
}

/* --------------------------------------------------------- card editor */

/* The block document on the card page. It is a field, so it borrows the
   textarea's frame, but the type inside is the page's sans stack at a
   reading line height rather than a code field's mono. Spec section 10c. */

.ce-wrap {
  position: relative;
}

.ce {
  padding: 10px 12px;
  min-height: 180px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.6;
}

.ce:focus,
.ce:focus-within {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}

/* The newline decision, applied uniformly: a soft break is a newline in the
   document, in the projection and here. There is no <br> anywhere. */
.ce-text {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  min-height: 1.6em;
}

.ce-block {
  margin: 2px 0;
}

.ce-block + .ce-block {
  margin-top: 6px;
}

.ce-h1 > .ce-text,
.ce-h2 > .ce-text,
.ce-h3 > .ce-text {
  font-weight: 600;
  line-height: 1.3;
}

.ce-h1 > .ce-text {
  font-size: 24px;
}

.ce-h2 > .ce-text {
  font-size: 19px;
}

.ce-h3 > .ce-text {
  font-size: 16px;
}

.ce-h1,
.ce-h2,
.ce-h3 {
  margin-top: 16px;
}

.ce-li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.ce-li > .ce-text {
  flex: 1 1 auto;
  min-width: 0;
}

.ce-bullet,
.ce-marker {
  flex: 0 0 auto;
  min-width: 18px;
  text-align: right;
  color: var(--text-muted);
  user-select: none;
}

/* The checkbox sits on the first line of the item, not on the box's own
   baseline, which is what makes a wrapped to-do read straight. */
.ce-check {
  flex: 0 0 auto;
  margin: 5px 0 0;
}

.ce-todo[data-done="1"] > .ce-text {
  color: var(--text-muted);
  text-decoration: line-through;
}

.ce-block[data-indent="1"] {
  margin-left: 24px;
}

.ce-block[data-indent="2"] {
  margin-left: 48px;
}

.ce-block[data-indent="3"] {
  margin-left: 72px;
}

.ce-quote {
  padding-left: 12px;
  border-left: 3px solid var(--border-strong);
  color: var(--text-muted);
}

/* Code reads like the .plain blocks elsewhere on the site. */
.ce-code > .ce-text {
  padding: 8px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.5;
}

.ce code {
  padding: 1px 4px;
  background: var(--surface-3);
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 13px;
}

.ce-divider {
  padding: 6px 0;
}

.ce-divider hr {
  margin: 0;
  border: 0;
  border-top: 1px solid var(--border-strong);
}

/* .thumb's 240px cap is a list treatment; an image in the body is content. */
.ce-img {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: 4px;
}

.ce-caption {
  padding-top: 4px;
  color: var(--text-muted);
  font-size: 13px;
}

.ce-file {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 8px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.ce-missing {
  padding: 8px 10px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
}

/* An upload still in flight. It carries data-pending, so it is also the one
   kind of block that can never be serialised into a save. */
.ce-pending {
  opacity: 0.55;
}

.ce-block[data-empty="1"] > .ce-text::before {
  content: attr(data-placeholder);
  color: var(--text-muted);
  pointer-events: none;
}

/* The label above the region. <label for> cannot target a div, so the field
   gets a span and aria-labelledby instead. */
.ce-label {
  color: var(--text-muted);
  font-weight: 500;
}

.ce-hint {
  margin: 6px 0 0;
  font-size: 12px;
}

.ce-file-input {
  display: none;
}

/* The slash menu, absolutely placed inside .ce-wrap and never inside the
   editable region. Not a modal: it closes on Escape and on blur. */
.ce-menu {
  position: absolute;
  z-index: 5;
  min-width: 220px;
  max-height: 280px;
  overflow-y: auto;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.22);
}

.ce-menu[hidden] {
  display: none;
}

.ce-menu-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 8px;
  border-radius: 4px;
  cursor: pointer;
}

.ce-menu-item.is-active {
  background: var(--accent-soft);
}

.ce-menu-hint {
  color: var(--text-muted);
  font-family: var(--mono);
  font-size: 12px;
}

.ce-link-bar {
  margin-top: 6px;
}

.ce-link-bar[hidden] {
  display: none;
}

.ce-link-bar input[type="text"] {
  flex: 1 1 220px;
}

/* ----------------------------------------------------------- login page */

.login-box {
  max-width: 360px;
  margin: 48px auto 0;
}

.field-row.login-actions {
  margin-top: 18px;
}

.form-error {
  margin-top: 12px;
  color: var(--danger);
}

.login-actions button {
  width: 100%;
}

/* The token field and its reveal button are one control. */
.input-reveal {
  display: flex;
  align-items: stretch;
  gap: 6px;
}

.input-reveal input {
  flex: 1 1 auto;
  min-width: 0;
}

.reveal {
  flex: 0 0 auto;
  padding: 0 10px;
  color: var(--text-muted);
}

.reveal .icon-eye-off,
.reveal[aria-pressed="true"] .icon-eye {
  display: none;
}

.reveal[aria-pressed="true"] .icon-eye-off {
  display: inline-block;
}

/* ------------------------------------------------- credentials and copying */

/* The copy button lives in a box header, so it inherits ".box-actions button"
   for its size. Only its two transient states are its own. */
.copy-button[data-state="done"] {
  color: var(--success);
  border-color: var(--success);
}

.copy-button[data-state="failed"] {
  color: var(--danger);
  border-color: var(--danger);
}

/* A copy button standing on its own in the page stack, with the text it copies
   never painted at all. It is the whole feature, so it is a pill rather than
   another rectangle: nothing else on the page is this shape, which is what
   stops one small control reading as a broken box. */
.pill-row {
  display: flex;
  justify-content: flex-end;
}

/* Laid out explicitly rather than by inheritance from "button". This control
   is one icon beside one word and nothing else, so the row, the no-wrap and
   the centring are stated here where they can be read, instead of being
   assembled out of three rules further up the file. */
button.copy-button.pill {
  display: inline-flex;
  flex-flow: row nowrap;
  align-items: center;
  justify-content: center;
  /* The icon is a 16px box with the glyph drawn inside it, so the optical gap
     is always a little tighter than the number. 10px reads as the 8px it
     needs to be. */
  gap: 10px;
  padding: 5px 18px;
  min-height: 30px;
  border-radius: 999px;
  color: var(--text-muted);
  font-size: 13px;
  /* The label is a flex item, so its box is centred against the icon's; with
     the inherited leading still on it, the glyphs sit low inside that box and
     the two read as misaligned. Collapsing the line box to the text height
     makes centring the boxes the same thing as centring what you can see. */
  line-height: 1;
}

button.copy-button.pill > .icon {
  flex: 0 0 auto;
  margin: 0;
  /* Only meaningful when an icon is not a flex item, and here it always is. */
  vertical-align: 0;
}

button.copy-button.pill > .copy-label {
  display: block;
  white-space: nowrap;
}

button.pill:hover:not(:disabled) {
  color: var(--text);
  border-color: var(--accent);
}

/* The done and failed colours above set only the text and the border, which on
   a pill leaves the fill flat. Tint it too, so a click that landed is obvious
   without reading the label. */
button.pill[data-state="done"] {
  background: var(--success-soft);
}

button.pill[data-state="failed"] {
  background: var(--danger-soft);
}

/* A link that stands in a row of buttons: the admin's per-user "Setup" is a
   GET, so it must be an anchor, but it has to line up with the two forms
   beside it. Everything here is copied off "button" on purpose; the two must
   not drift apart. */
.button-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 5px 14px;
  min-height: 32px;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  color: var(--text);
  font-weight: 500;
  text-decoration: none;
}

.button-link:hover {
  background: var(--surface-3);
  color: var(--text);
  text-decoration: none;
}

/* A long block that is worth keeping on the page but not worth reading every
   visit. The summary is the only affordance; the block itself is a .plain. */
.fold {
  margin-top: 12px;
}

.fold > summary {
  cursor: pointer;
  color: var(--text-muted);
  font-weight: 500;
  list-style-position: inside;
}

.fold > summary:hover {
  color: var(--accent);
}

.fold > .plain {
  margin-top: 10px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 10px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* ---------------------------------------------------------- access grid */

.access-grid th:not(:first-child),
.access-grid td:not(:first-child) {
  text-align: center;
}

.access-grid input[type="checkbox"] {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

/* The boxes carry no visible label, so the label is only there to widen the
   hit area around its checkbox. */
.access-grid td label {
  display: inline-block;
  padding: 6px;
  cursor: pointer;
}

/* ----------------------------------------------------------------- misc */

.muted {
  color: var(--text-muted);
}

.right {
  display: block;
  text-align: right;
}

/* Never a blank box: an empty region says what would fill it. */
.empty {
  margin: 0;
  padding: 20px 4px;
  color: var(--text-muted);
  text-align: center;
}

.pager {
  margin-top: 14px;
  justify-content: center;
  color: var(--text-muted);
}

/* ---------------------------------------------------------------- phone */

@media (max-width: 640px) {
  .main {
    padding: 14px 10px 48px;
  }

  .nav {
    padding: 6px 10px;
    gap: 10px;
  }

  .box-body {
    padding: 12px;
  }

  .repo-title {
    font-size: 18px;
  }

  .board-column,
  .board-add {
    flex-basis: 84vw;
    max-width: 84vw;
  }
}
