:root {
  --bg: #f7f7f8;
  --fg: #1d1d20;
  --muted: #5f5f66;
  --surface: #ffffff;
  --border: #e2e2e6;
  --accent: #2f5bd3;

  color-scheme: light dark;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.5;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #141416;
    --fg: #ececf0;
    --muted: #a0a0aa;
    --surface: #1d1d21;
    --border: #2e2e34;
    --accent: #7c9cf5;
  }
}

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
}

a {
  color: var(--accent);
}

.app-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.app-name {
  color: var(--fg);
  font-weight: 600;
  text-decoration: none;
}

main {
  padding: 1.5rem 1rem;
  max-width: 72rem;
  margin: 0 auto;
}

/* The main navigation: My tasks and the project switcher. */
.app-nav {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-width: 0;
}

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

.app-projects {
  position: relative;
  min-width: 0;
}

.app-projects summary {
  overflow: hidden;
  max-width: 16rem;
  cursor: pointer;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.app-projects .menu {
  right: auto;
  left: 0;
  max-height: 70vh;
  overflow-y: auto;
}

.app-projects .menu a[aria-current="true"] {
  font-weight: 600;
}

.app-projects .key {
  color: var(--muted);
  font-size: 0.875rem;
}

/* The Archived Projects, collapsed at the bottom of the switcher. */
.archived-projects {
  border-top: 1px solid var(--border);
}

.archived-projects summary {
  padding: 0.5rem 1rem;
  color: var(--muted);
  font-size: 0.875rem;
}

.archived-projects ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* „Zarchiwizowany” after a Project's name in the panel's list. */
.archived-mark {
  margin-left: 0.5rem;
  color: var(--muted);
  font-size: 0.875rem;
}

/* The bell, right before the avatar: how many Notifications are unread,
   and the newest ones in its menu. */
.app-bell {
  position: relative;
  margin-left: auto;
}

.app-bell summary {
  position: relative;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  color: var(--muted);
  list-style: none;
  cursor: pointer;
}

.app-bell summary::-webkit-details-marker {
  display: none;
}

.app-bell summary:hover,
.app-bell[open] summary {
  color: var(--fg);
}

.bell-count {
  position: absolute;
  top: -0.125rem;
  right: -0.25rem;
  min-width: 1.125rem;
  padding: 0 0.25rem;
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.125rem;
  text-align: center;
  background: #c62828;
  border-radius: 0.5625rem;
}

.bell-menu {
  width: min(22rem, calc(100vw - 2rem));
}

.bell-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Marked like the page's (.notification-unread). */
.bell-item {
  border-left: 3px solid transparent;
}

.bell-item a {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.bell-item .notification-task {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bell-empty {
  margin: 0;
  padding: 0.5rem 1rem;
  color: var(--muted);
}

.menu .bell-all {
  border-top: 1px solid var(--border);
  color: var(--accent);
}

/* The page of the bell alone, which nothing links to. */
.bell-page {
  margin: 0;
}

/* Signed-in User in the header: the avatar and name open the menu. */
.app-user {
  position: relative;
  margin-left: auto;
}

.app-bell + .app-user {
  margin-left: 0;
}

.app-user summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  list-style: none;
  cursor: pointer;
}

.app-user summary::-webkit-details-marker {
  display: none;
}

.app-user-name {
  color: inherit;
}

/* On a phone the avatar alone opens the menu, leaving room for the
   navigation. */
@media (max-width: 40rem) {
  .app-user-name {
    display: none;
  }
}

.menu {
  position: absolute;
  top: calc(100% + 0.25rem);
  right: 0;
  z-index: 10;
  min-width: 14rem;
  margin: 0;
  padding: 0.25rem 0;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
}

.menu form {
  margin: 0;
}

.menu a,
.menu .link-button {
  display: block;
  width: 100%;
  padding: 0.5rem 1rem;
  color: var(--fg);
  text-align: left;
  text-decoration: none;
}

.menu a:hover,
.menu .link-button:hover {
  background: var(--bg);
}

/* Initials on a colour picked by the User's ID (avatarColor in auth.go):
   white text, contrast at least 4.5:1 on each. */
.avatar {
  display: inline-grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  color: #fff;
  font-size: 0.8rem;
  font-weight: 600;
  user-select: none;
}

.avatar-0 { background: #c2410c; }
.avatar-1 { background: #1d4ed8; }
.avatar-2 { background: #15803d; }
.avatar-3 { background: #7e22ce; }
.avatar-4 { background: #be123c; }
.avatar-5 { background: #0f766e; }
.avatar-6 { background: #a16207; }
.avatar-7 { background: #4338ca; }

button,
.button {
  display: inline-block;
  padding: 0.5rem 1rem;
  border: 1px solid var(--accent);
  border-radius: 0.375rem;
  background: var(--accent);
  color: var(--surface);
  font: inherit;
  text-decoration: none;
  cursor: pointer;
}

button:disabled {
  border-color: var(--border);
  background: var(--border);
  color: var(--muted);
  cursor: not-allowed;
}

/* An action that takes something away, e.g. deactivating an account. */
button.danger:enabled,
a.button.danger {
  border-color: #be123c;
  background: #be123c;
  color: #ffffff;
}

.link-button {
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  text-decoration: underline;
}

/* Login and activation. */
.auth {
  max-width: 24rem;
  margin: 2rem auto;
}

.auth form,
form.fields {
  display: grid;
  gap: 0.5rem;
}

.auth input,
.fields input,
.project-search input {
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: inherit;
}

.auth button,
.fields button {
  margin-top: 0.5rem;
}

.hint {
  margin: 0 0 0.5rem;
  color: var(--muted);
  font-size: 0.875rem;
}

.form-error {
  padding: 0.5rem 0.75rem;
  border-left: 3px solid #be123c;
  background: var(--surface);
}

/* The User's own profile. */
.profile {
  max-width: 36rem;
}

.profile dl,
.facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.25rem 1rem;
}

.profile dt,
.facts dt {
  color: var(--muted);
}

.profile dd,
.facts dd {
  margin: 0;
}

.profile form.fields {
  max-width: 24rem;
}

.empty-state {
  color: var(--muted);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The admin panel, and the views and settings of a Project, which scroll
   sideways where they do not fit, on a phone. */
.tabs {
  display: flex;
  gap: 1.5rem;
  margin-bottom: 1.5rem;
  overflow-x: auto;
  scrollbar-width: thin;
  border-bottom: 1px solid var(--border);
}

.tabs a {
  flex: none;
  padding: 0.5rem 0;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  text-decoration: none;
}

.tabs a[aria-current="page"] {
  border-bottom-color: var(--accent);
  color: var(--fg);
  font-weight: 600;
}

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

.filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

select {
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: inherit;
}

/* Wide tables scroll sideways on a phone, not the page. Relative, so
   what is absolutely positioned inside (.visually-hidden) scrolls too. */
.table-scroll {
  position: relative;
  overflow-x: auto;
}

.users,
.projects,
.my-tasks {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
}

.users th,
.projects th,
.my-tasks th,
.users td,
.projects td,
.my-tasks td {
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
}

/* My tasks: a long title wraps rather than widen the table. */
.my-tasks td.my-task-title {
  min-width: 12rem;
  white-space: normal;
}

.users th,
.projects th,
.my-tasks th {
  color: var(--muted);
  font-size: 0.875rem;
  font-weight: 600;
}

/* Notifications: an unread one has a bar of the accent colour on its
   left; a Comment shows its first lines. */
.toolbar .tabs {
  margin-bottom: 0;
}

.notification-list {
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.375rem;
}

.notification {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border);
  border-left: 3px solid transparent;
}

.notification:last-child {
  border-bottom: 0;
}

.notification-unread {
  border-left-color: var(--accent);
}

.notification-link {
  display: block;
  color: var(--fg);
  text-decoration: none;
}

.notification-link:hover .notification-task {
  text-decoration: underline;
}

.notification-unread .notification-task {
  font-weight: 600;
}

.notification-task {
  display: block;
  overflow-wrap: anywhere;
}

.notification-task .key {
  color: var(--muted);
}

/* The Tasks of a Notification of a bulk change, each a link. */
.notification-tasks {
  margin: 0.25rem 0 0;
  padding-left: 1.25rem;
}

.notification-tasks .notification-task {
  color: var(--fg);
}

.notification-comment {
  display: -webkit-box;
  margin: 0.25rem 0 0;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
}

.notification-comment-deleted {
  color: var(--muted);
  font-style: italic;
}

.notification-meta {
  margin: 0.25rem 0 0;
  color: var(--muted);
  font-size: 0.8rem;
}

.users form {
  margin: 0;
}

.admin form.fields {
  max-width: 24rem;
}

.fields .checkbox {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.fields .checkbox input {
  width: 1rem;
  height: 1rem;
  margin: 0;
  padding: 0;
}

.fields .actions {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 0.5rem;
}

.fields .actions button {
  margin-top: 0;
}

/* A label, its input and hint swapped together, as the Project key. */
.fields .field {
  display: grid;
  gap: 0.5rem;
}

/* A list of checkboxes to choose any of, as a Project's first Members. */
.fields .choices {
  display: grid;
  gap: 0.25rem;
  margin: 0.5rem 0 0;
  padding: 0.5rem 0.75rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
}

.fields .choices .hint {
  margin: 0;
}

/* Project keys are uppercase; the app folds what is typed. */
#key {
  text-transform: uppercase;
}

/* A Project's settings. */
.project-settings {
  max-width: 36rem;
}

.project-settings .key {
  color: var(--muted);
  font-size: 1rem;
  font-weight: 400;
}

.project-settings form.fields {
  max-width: 24rem;
  margin-bottom: 1rem;
}

/* A Project's Board: a column per Status, scrolling sideways. A Closing
   status looks like the others. */
.project-board .key {
  color: var(--muted);
  font-size: 1rem;
  font-weight: 400;
}

.board {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  overflow-x: auto;
  padding-bottom: 0.75rem;
  scroll-snap-type: x proximity;
}

.board-column {
  display: flex;
  flex: 0 0 16rem;
  flex-direction: column;
  max-height: calc(100vh - 12rem);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  scroll-snap-align: start;
}

.board-column-name {
  margin: 0;
  padding: 0.625rem 0.75rem 0.375rem;
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.board-cards {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-height: 2.5rem;
  padding: 0.25rem 0.5rem 0.5rem;
  overflow-y: auto;
}

/* A Task's card: the title, then its Type, Task key, Priority and
   Assignee in a row. */
.card {
  padding: 0.5rem 0.625rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 0.375rem;
}

.card-title {
  margin: 0 0 0.375rem;
  overflow-wrap: anywhere;
}

.card-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--muted);
  font-size: 0.8rem;
}

.card-due {
  white-space: nowrap;
}

.card-meta .avatar {
  width: 1.5rem;
  height: 1.5rem;
  margin-left: auto;
  font-size: 0.7rem;
}

.task-type,
.priority {
  text-decoration: none;
  cursor: help;
}

.task-type {
  display: inline-grid;
  place-items: center;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 0.25rem;
  color: #fff;
  font-size: 0.7rem;
  font-weight: 600;
}

/* White text, contrast at least 4.5:1 on each. */
.task-type-task { background: #1d4ed8; }
.task-type-bug { background: #be123c; }
.task-type-story { background: #15803d; }

.priority-4,
.priority-5 {
  color: #be123c;
  font-weight: 600;
}

@media (prefers-color-scheme: dark) {
  .priority-4,
  .priority-5 {
    color: #fb7185;
  }
}

/* No Assignee: a "?" in the place of one. */
.avatar-none {
  border: 1px dashed var(--muted);
  color: var(--muted);
}

/* Quick add at the bottom of a column: the title alone. */
.quick-add {
  padding: 0 0.5rem 0.5rem;
}

.quick-add summary {
  padding: 0.25rem;
  border-radius: 0.375rem;
  color: var(--muted);
  cursor: pointer;
  list-style: none;
}

.quick-add summary::-webkit-details-marker {
  display: none;
}

.quick-add summary:hover {
  background: var(--bg);
  color: var(--fg);
}

.quick-add input[name="title"] {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: inherit;
}

.quick-add .form-error,
.quick-add .hint {
  margin: 0.375rem 0 0;
  font-size: 0.8rem;
}

@media (max-width: 40rem) {
  .board {
    scroll-snap-type: x mandatory;
  }

  .board-column {
    flex-basis: 85vw;
  }
}

/* A card's title links to its Task; the link covers the whole card. */
.card {
  position: relative;
}

.card-title a {
  color: inherit;
  text-decoration: none;
}

.card-title a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.card-title a:focus-visible {
  outline: none;
}

.card:hover,
.card:has(a:focus-visible) {
  border-color: var(--accent);
}

.card:has(a:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* The card of the Task open in the panel (app.js). */
.card.card-open {
  border-color: var(--accent);
  box-shadow: inset 3px 0 0 var(--accent);
}

/* Dragging a card (app.js, SortableJS): it grabs, and the place it
   would drop into shows as a faded card. */
.card {
  cursor: grab;
}

.card.sortable-ghost {
  opacity: 0.4;
  border-style: dashed;
}

/* A card someone else just changed, as the Board refreshes live
   (app.js): it flashes, and says who changed it and what over its top
   edge, for a moment. So does a part of an open Task someone else just
   changed (.live-flash), as its panel or page refreshes live. */
.card-change {
  display: none;
}

.card.card-flash,
.live-flash {
  --flash-bg: #fff3bf;
  --flash-ring: #fcc419;
  animation: card-flash 2.5s ease-out;
}

@media (prefers-color-scheme: dark) {
  .card.card-flash,
  .live-flash {
    --flash-bg: #4d3f0b;
    --flash-ring: #b08900;
  }
}

.card-flash .card-change {
  position: absolute;
  right: 0.5rem;
  bottom: calc(100% - 0.375rem);
  z-index: 2;
  display: block;
  max-width: calc(100% - 1rem);
  margin: 0;
  padding: 0.125rem 0.5rem;
  overflow: hidden;
  color: var(--surface);
  font-size: 0.75rem;
  white-space: nowrap;
  text-overflow: ellipsis;
  background: var(--fg);
  border-radius: 0.375rem;
  pointer-events: none;
}

@keyframes card-flash {
  0%,
  30% {
    background: var(--flash-bg);
    box-shadow: 0 0 0 3px var(--flash-ring);
  }
}

@media (prefers-reduced-motion: reduce) {
  .card.card-flash,
  .live-flash {
    animation: none;
    box-shadow: 0 0 0 3px var(--flash-ring);
  }
}

/* A move that went through though someone had changed the card since:
   over the Board, at the bottom, until the next redraw or ✕. */
.board-warning {
  position: fixed;
  bottom: 1rem;
  left: 50%;
  z-index: 15;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  max-width: min(36rem, calc(100vw - 2rem));
  margin: 0;
  padding: 0.625rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid #a16207;
  border-radius: 0.375rem;
  box-shadow: 0 4px 16px rgb(0 0 0 / 0.15);
  transform: translateX(-50%);
}

.board-warning-close {
  flex: none;
  padding: 0.125rem 0.375rem;
  color: var(--muted);
  background: none;
  border: 0;
  cursor: pointer;
}

/* „Przenieś do…” on a card, over its link, at the end of its row. With
   JS a choice posts it, so there is no button, and a mouse sees it in
   the card's corner, on the card it points at (or the keyboard is in). */
.card-key {
  white-space: nowrap;
}

.card-move {
  position: relative;
  z-index: 1;
  display: flex;
  gap: 0.25rem;
  margin: 0;
}

html:not(.js) .card-meta {
  flex-wrap: wrap;
}

.card-move select {
  max-width: 8rem;
  padding: 0 0.25rem;
  color: var(--muted);
  font-size: 0.75rem;
}

.card-move-save {
  padding: 0 0.5rem;
  font-size: 0.75rem;
}

.js .card-move-save {
  display: none;
}

@media (hover: hover) {
  .js .card-move {
    position: absolute;
    top: 0.375rem;
    right: 0.375rem;
  }

  .js .card:not(:hover, :focus-within) .card-move {
    opacity: 0;
  }
}

/* A press held on a card starts a drag on a touch screen (app.js): it
   selects no text and opens no menu of the link. */
@media (pointer: coarse) {
  .card {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
  }
}

/* On a phone, with JS, a Status at a time: tabs over its column, the one
   marked data-shown (app.js), which takes the width and scrolls with the
   page. Without JS the columns stay side by side. */
.board-tabs {
  display: none;
}

.board-tabs [role="tab"] {
  flex: none;
  padding: 0.25rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--fg);
  font-size: 0.875rem;
}

.board-tabs [role="tab"][data-shown] {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--surface);
}

.board-tab-count {
  font-size: 0.75rem;
  font-weight: 600;
}

@media (max-width: 40rem) {
  .js .board {
    display: block;
    overflow-x: visible;
    scroll-snap-type: none;
  }

  .js .board-tabs {
    display: flex;
    gap: 0.375rem;
    margin-bottom: 0.75rem;
    padding-bottom: 0.125rem;
    overflow-x: auto;
  }

  .js .board-column {
    max-height: none;
  }

  .js .board-column:not([data-shown]),
  .js .board-column-name {
    display: none;
  }

  .js .board-cards {
    overflow-y: visible;
  }
}

/* A Task's panel, over the Board on the right; the Board keeps room for
   it, so it stays visible and clickable. */
.task-panel {
  position: fixed;
  top: var(--panel-top, 3.5rem);
  right: 0;
  bottom: 0;
  z-index: 5;
  width: min(36rem, 100vw);
  overflow-y: auto;
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: -8px 0 24px rgb(0 0 0 / 0.12);
}

.task-panel:focus {
  outline: none;
}

main:has(.task-panel) {
  max-width: none;
  margin-right: min(36rem, 100vw);
}

.task-panel .task-head {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.task-head {
  padding: 0.75rem 1.25rem 0.5rem;
}

.task-topline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.task-key {
  color: var(--muted);
  font-size: 0.875rem;
  font-weight: 600;
}

.task-crumbs {
  color: var(--muted);
  font-size: 0.8rem;
}

.task-actions {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-left: auto;
}

/* A quiet button or link, in the header of a Task. */
.ghost {
  padding: 0.25rem 0.5rem;
  border: 1px solid transparent;
  border-radius: 0.375rem;
  background: none;
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.5;
  text-decoration: none;
}

.ghost:hover,
.ghost:focus-visible {
  border-color: var(--border);
  color: var(--fg);
}

/* The title, edited in place: a field that looks like a heading. */
.task-title-form {
  margin: 0.25rem 0 0;
}

.task-title {
  display: block;
  width: calc(100% + 0.75rem);
  margin: 0 -0.375rem;
  padding: 0.125rem 0.375rem;
  overflow: hidden;
  resize: none;
  border: 1px solid transparent;
  border-radius: 0.375rem;
  background: none;
  color: var(--fg);
  font-family: inherit;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  field-sizing: content;
}

.task-title:hover {
  border-color: var(--border);
}

.task-title:focus {
  border-color: var(--accent);
  outline: none;
  background: var(--bg);
}

.task-title-hint {
  display: none;
  margin: 0.25rem 0 0;
  font-size: 0.8rem;
}

.task-title-form:focus-within .task-title-hint,
.task-title[aria-invalid="true"] ~ .task-title-hint {
  display: block;
}

/* With JS, Enter saves: no button. */
.js .task-title-save {
  display: none;
}

.task-title-save {
  margin-left: 0.5rem;
  padding: 0.125rem 0.5rem;
}

.task-title-form .form-error {
  margin: 0.25rem 0 0;
  font-size: 0.875rem;
}

/* The title of a Task in the Trash, which is read-only: text alone. */
.task-title-read {
  margin: 0.25rem 0 0;
  font-size: 1.25rem;
  line-height: 1.3;
}

/* Under the header of an open Task, for a moment: who else just changed
   what (app.js), a click away from Historia. */
.task-news:empty {
  display: none;
}

.task-news-bubble {
  margin: 0.5rem 1.25rem 0;
  padding: 0.375rem 0.75rem;
  color: var(--surface);
  font-size: 0.875rem;
  background: var(--fg);
  border-radius: 0.375rem;
  cursor: pointer;
}

.task-news-bubble .task-news-show {
  margin-left: 0.5rem;
  padding: 0;
  color: inherit;
  font-size: inherit;
  text-decoration: underline;
  background: none;
  border: 0;
}

.task-page .task-news-bubble {
  margin: 0 0 0.75rem;
}

/* How many Comments or files a Task has, on its tab; none for none. */
.tab-count {
  margin-left: 0.25rem;
  padding: 0 0.375rem;
  font-size: 0.75rem;
  border-radius: 1rem;
  background: var(--border);
}

.tab-count:empty {
  display: none;
}

/* The bar over a Task in the Trash: who moved it there and when, and
   Przywróć for its Reporter or an Admin; and the one over every page of
   an Archived Project: who archived it and when. */
.task-trashed,
.project-archived {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0 0 0.5rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-left: 3px solid #a16207;
  border-radius: 0.375rem;
  background: color-mix(in srgb, #a16207 8%, var(--surface));
  font-size: 0.875rem;
}

.task-trashed p,
.project-archived p,
.task-trash-form {
  margin: 0;
}

.task-trashed button {
  padding: 0.25rem 0.75rem;
}

/* The header's menu „⋯”: its actions in a box under it, as „Usuń” of a
   Comment asks again. */
.task-menu {
  position: relative;
}

.task-menu summary {
  list-style: none;
  cursor: pointer;
}

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

.task-menu form {
  position: absolute;
  right: 0;
  z-index: 3;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
  white-space: nowrap;
}

/* A field of a Task in the Trash: a disabled fieldset, which shows the
   value as the form of a field does at rest. */
fieldset.task-field {
  min-inline-size: 0;
  padding: 0;
  border: 0;
}

fieldset.task-field :disabled {
  appearance: none;
  opacity: 1;
  color: inherit;
}

/* The fields, always all shown: pills, then the others. */
.task-fields {
  padding: 0.75rem 1.25rem 0;
}

.task-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.125rem 0.625rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.875rem;
}

.pill .avatar {
  width: 1.25rem;
  height: 1.25rem;
  font-size: 0.65rem;
}

.pill-status {
  border-color: transparent;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
}

.pill-closing {
  background: color-mix(in srgb, #15803d 16%, transparent);
  color: #15803d;
}

@media (prefers-color-scheme: dark) {
  .pill-closing {
    color: #4ade80;
  }
}

/* A field edited in place: a form of its own, which looks like the value
   it shows until it is hovered or focused. */
.task-field {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  margin: 0;
}

.task-field select,
.task-field input {
  padding: 0.0625rem 0.25rem;
  border: 1px solid transparent;
  border-radius: 0.25rem;
  background: none;
  color: inherit;
  font: inherit;
}

.task-field select:hover,
.task-field input:hover {
  border-color: var(--border);
}

.task-field select:focus,
.task-field input:focus {
  border-color: var(--accent);
  outline: none;
  background: var(--bg);
}

.task-field [aria-invalid="true"] {
  border-color: #be123c;
}

.task-estimate {
  width: 5rem;
}

.task-estimate-unit {
  color: var(--muted);
}

.task-field-clear {
  padding: 0 0.25rem;
  font-size: 0.75rem;
}

/* With JS, a field saves as it changes: no button. */
.js .task-field-save {
  display: none;
}

.task-field-save {
  padding: 0.0625rem 0.5rem;
  font-size: 0.8rem;
}

.pill-field {
  padding: 0 0.375rem 0 0.625rem;
}

.pill .form-error,
.task-props .form-error {
  flex-basis: 100%;
  margin: 0.25rem 0 0;
  font-size: 0.8rem;
}

.pill:has(.form-error) {
  flex-wrap: wrap;
  border-radius: 0.5rem;
}

/* Overdue: an open Task whose Due date has passed, marked in red on its
   card and in its panel. */
.pill-overdue {
  border-color: #be123c;
}

.overdue,
.due-overdue {
  color: #be123c;
  font-weight: 600;
}

.overdue {
  font-size: 0.75rem;
}

@media (prefers-color-scheme: dark) {
  .pill-overdue {
    border-color: #fb7185;
  }

  .overdue,
  .due-overdue {
    color: #fb7185;
  }
}

.task-props {
  display: grid;
  gap: 0.25rem;
  margin: 0.75rem 0;
  font-size: 0.875rem;
}

.task-props > div {
  display: grid;
  grid-template-columns: 8rem minmax(0, 1fr);
  gap: 0.5rem;
  align-items: baseline;
}

.task-props dt {
  color: var(--muted);
}

.task-props dd {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  margin: 0;
}

.task-props .hint {
  margin: 0;
}

.task-props .avatar {
  width: 1.25rem;
  height: 1.25rem;
  font-size: 0.65rem;
}

/* The palette of Labels and Epics (tracker.Colors): --palette is the
   colour of the text, from which a tint is mixed. */
.label-gray, .epic-gray { --palette: #4b5563; }
.label-red, .epic-red { --palette: #b91c1c; }
.label-orange, .epic-orange { --palette: #c2410c; }
.label-yellow, .epic-yellow { --palette: #a16207; }
.label-green, .epic-green { --palette: #15803d; }
.label-teal, .epic-teal { --palette: #0f766e; }
.label-blue, .epic-blue { --palette: #1d4ed8; }
.label-indigo, .epic-indigo { --palette: #4338ca; }
.label-purple, .epic-purple { --palette: #7e22ce; }
.label-pink, .epic-pink { --palette: #be185d; }

@media (prefers-color-scheme: dark) {
  .label-gray, .epic-gray { --palette: #d1d5db; }
  .label-red, .epic-red { --palette: #fca5a5; }
  .label-orange, .epic-orange { --palette: #fdba74; }
  .label-yellow, .epic-yellow { --palette: #fde047; }
  .label-green, .epic-green { --palette: #86efac; }
  .label-teal, .epic-teal { --palette: #5eead4; }
  .label-blue, .epic-blue { --palette: #93c5fd; }
  .label-indigo, .epic-indigo { --palette: #a5b4fc; }
  .label-purple, .epic-purple { --palette: #d8b4fe; }
  .label-pink, .epic-pink { --palette: #f9a8d4; }
}

.labels {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.label {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0 0.5rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: color-mix(in srgb, var(--palette) 14%, transparent);
  color: var(--palette);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/* A Label offered to put on a Task, and the ✕ that takes one off. */
button.label {
  cursor: pointer;
}

button.label:hover,
button.label:focus-visible {
  border-color: var(--palette);
}

.label-add,
.label-remove {
  display: inline;
  margin: 0;
}

.label-remove button {
  padding: 0 0.125rem;
  border: 0;
  background: none;
  color: inherit;
  font-size: 0.7rem;
  line-height: 1;
}

.label-picker {
  flex-basis: 100%;
}

.label-picker summary {
  width: fit-content;
  color: var(--accent);
  font-size: 0.8rem;
  cursor: pointer;
}

.label-picker[open] {
  display: grid;
  gap: 0.5rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
}

.label-new {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  margin: 0;
}

.label-new label {
  flex-basis: 100%;
  color: var(--muted);
  font-size: 0.8rem;
}

.label-new input {
  width: min(100%, 12rem);
}

.label-new select,
.label-new button {
  padding: 0.25rem 0.5rem;
  font-size: 0.875rem;
}

.label-new input {
  font-size: 0.875rem;
}

.label-new .form-error {
  flex-basis: 100%;
  margin: 0;
}

.card-labels {
  margin: 0 0 0.375rem;
}

/* Epics: a chip as a Label's, but square-cornered with a bar of its
   colour; on a card, a strip over its title. */
.epic {
  display: inline-block;
  padding: 0 0.5rem;
  border-left: 0.25rem solid var(--palette);
  border-radius: 0.25rem;
  background: color-mix(in srgb, var(--palette) 14%, transparent);
  color: var(--palette);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.card-epic {
  margin: 0 0 0.375rem;
  padding: 0 0.375rem;
  border-left: 0.25rem solid var(--palette);
  color: var(--palette);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

/* The Epik field of a Task: a dot of the Epic's colour before the choice,
   its progress under it, then „+ nowy epik”. */
.epic-swatch {
  display: inline-block;
  width: 0.625rem;
  height: 0.625rem;
  margin-right: 0.375rem;
  border-radius: 50%;
  background: var(--palette);
  vertical-align: middle;
}

.epic-progress {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.25rem 0 0;
  color: var(--muted);
  font-size: 0.8rem;
}

.epic-progress progress {
  width: min(100%, 8rem);
  height: 0.375rem;
  accent-color: var(--accent);
}

.epic-new-picker summary {
  width: fit-content;
  margin-top: 0.25rem;
  color: var(--accent);
  font-size: 0.8rem;
  cursor: pointer;
}

.epic-new-picker[open] {
  margin-top: 0.25rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
}

.epic-new {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  margin: 0;
}

.epic-new input {
  width: min(100%, 12rem);
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  font-size: 0.875rem;
}

.epic-new select,
.epic-new button {
  padding: 0.25rem 0.5rem;
  font-size: 0.875rem;
}

.epic-new .form-error {
  flex-basis: 100%;
  margin: 0;
}

/* The Epiki section of a Project's settings: as the Etykiety one, with
   each Epic's progress under its chip. */
.epic-list > li > .epic {
  justify-self: start;
}

.epic-list .epic-progress {
  grid-column: 1;
  margin: 0;
}

.epic-list .label-form {
  grid-column: 2;
  grid-row: 1 / span 2;
}

@media (max-width: 40rem) {
  .epic-list .label-form {
    grid-column: 1;
    grid-row: auto;
  }
}

/* The Etykiety section of a Project's settings: a Label a row, its chip,
   then the form of its name and colour. */
.label-list {
  margin: 0 0 1.5rem;
  padding: 0;
  list-style: none;
}

.label-list > li {
  display: grid;
  grid-template-columns: minmax(0, 8rem) minmax(0, 1fr);
  align-items: center;
  gap: 0.5rem 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
}

.label-list > li > .label {
  justify-self: start;
}

.label-list .form-error {
  grid-column: 1 / -1;
  margin: 0;
}

@media (max-width: 40rem) {
  .label-list > li {
    grid-template-columns: minmax(0, 1fr);
  }
}

.label-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  margin: 0;
}

.label-form input,
.label-new input {
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: inherit;
}

.label-form input {
  width: min(100%, 11rem);
}

.label-form select,
.label-form button {
  padding: 0.25rem 0.75rem;
}

/* The Statusy section of a Project's settings: a Status a row, in the
   order of the Board's columns. For an Admin, the handle a drag takes it
   by (only with JS, app.js), then the form of its name and whether it is
   closing, and under them ↑, ↓ and the links to flag or delete it. */
.status-list {
  margin: 0 0 1.5rem;
  padding: 0;
  list-style: none;
}

.status-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 0.5rem 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}

.status-row > * {
  grid-column: 2;
}

.status-row > .status-handle {
  grid-column: 1;
  grid-row: 1;
}

.status-main {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem 0.75rem;
}

/* A width of its own: a share of the form's leaves the form wider than
   what it holds, and the mark of a closing Status far from it. */
.status-main .label-form input {
  width: 13rem;
}

.status-row.sortable-ghost {
  opacity: 0.4;
}

.status-handle {
  display: none;
  color: var(--muted);
  cursor: grab;
  touch-action: none;
  user-select: none;
}

.js .status-handle {
  display: inline;
}

.status-closing {
  padding: 0.0625rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--muted);
  font-size: 0.875em;
}

.status-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem 0.75rem;
}

.status-actions form {
  margin: 0;
}

.status-actions button.ghost {
  min-width: 2.25rem;
  border-color: var(--border);
  font-size: 1rem;
}

.status-row .form-error {
  margin: 0;
}

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

/* Tabs: Szczegóły, Komentarze, … (app.js shows one at a time), which
   scroll sideways where they do not fit, on a phone. */
.task-tabs {
  display: flex;
  gap: 0.25rem;
  padding: 0 1.25rem;
  overflow-x: auto;
  scrollbar-width: thin;
  border-bottom: 1px solid var(--border);
}

.task-tabs [role="tab"] {
  flex: none;
  padding: 0.375rem 0.625rem;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: none;
  color: var(--muted);
  font-weight: 500;
}

.task-tabs [role="tab"][aria-selected="true"] {
  border-bottom-color: var(--accent);
  color: var(--accent);
}

.task-tab {
  padding: 0.75rem 1.25rem 1.25rem;
}

.task-description h2 {
  margin: 0;
  font-size: 1rem;
}

.task-description-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

/* A description's Markdown, as HTML, and its preview. */
.markdown {
  overflow-wrap: anywhere;
  line-height: 1.55;
}

.markdown > :first-child {
  margin-top: 0;
}

.markdown > :last-child {
  margin-bottom: 0;
}

.markdown h1,
.markdown h2,
.markdown h3,
.markdown h4 {
  margin: 1rem 0 0.5rem;
  font-size: 1rem;
}

.markdown h1 {
  font-size: 1.25rem;
}

.markdown h2 {
  font-size: 1.125rem;
}

.markdown p,
.markdown ul,
.markdown ol,
.markdown blockquote,
.markdown pre,
.markdown table {
  margin: 0 0 0.75rem;
}

.markdown ul,
.markdown ol {
  padding-left: 1.5rem;
}

/* A task list's items carry their checkbox instead of a bullet. */
.markdown li:has(> input[type="checkbox"]) {
  list-style: none;
  margin-left: -1.25rem;
}

.markdown blockquote {
  padding-left: 0.75rem;
  border-left: 3px solid var(--border);
  color: var(--muted);
}

.markdown code {
  padding: 0.1rem 0.3rem;
  border-radius: 0.25rem;
  background: var(--bg);
  font-size: 0.875em;
}

.markdown pre {
  overflow-x: auto;
  padding: 0.75rem;
  border-radius: 0.375rem;
  background: var(--bg);
}

.markdown pre code {
  padding: 0;
}

.markdown table {
  display: block;
  overflow-x: auto;
  border-collapse: collapse;
}

.markdown th,
.markdown td {
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--border);
}

/* A picture fits the text's width, and opens whole in a new tab
   (markdown.Render makes it a link). */
.markdown img {
  max-width: 100%;
  height: auto;
}

.markdown a {
  color: var(--accent);
}

/* The editor of a description: the toolbar, the text, Podgląd. Without
   JS there is neither the toolbar nor Podgląd, only the text. */
.markdown-editor {
  display: grid;
  gap: 0.75rem;
}

.markdown-tabs {
  padding: 0;
}

html:not(.js) .markdown-tabs,
html:not(.js) .md-toolbar {
  display: none;
}

.md-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.125rem;
  padding: 0.375rem 0;
}

.md-toolbar > * {
  min-width: 1.75rem;
  padding: 0.125rem 0.375rem;
  border: 1px solid transparent;
  border-radius: 0.25rem;
  color: var(--muted);
  text-align: center;
  cursor: pointer;
  user-select: none;
}

.md-toolbar > :hover,
.md-toolbar > :focus-visible {
  border-color: var(--border);
  color: var(--fg);
}

.markdown-input {
  box-sizing: border-box;
  width: 100%;
  min-height: 10rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: 0.875rem/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  resize: vertical;
}

.markdown-preview {
  min-height: 10rem;
  padding: 0.5rem 0;
}

/* „Dodaj plik” under the text, and how the last upload went (app.js).
   Without JS nothing uploads, so there is none. The file field itself is
   hidden in its label, which takes the clicks and shows its focus. */
html:not(.js) .markdown-upload {
  display: none;
}

.markdown-upload {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.375rem;
}

.markdown-upload-button {
  position: relative;
  padding: 0.125rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.25rem;
  color: var(--muted);
  font-size: 0.875rem;
  cursor: pointer;
}

.markdown-upload-button:hover,
.markdown-upload-button:focus-within {
  color: var(--fg);
}

.markdown-upload-button:has(:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.markdown-upload-input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  opacity: 0;
}

.markdown-upload-status {
  margin: 0;
  color: var(--muted);
  font-size: 0.8125rem;
}

.markdown-upload-status.upload-error {
  padding-left: 0.5rem;
  border-left: 3px solid #be123c;
  color: var(--fg);
}

/* A link to a file that is no more (its Comment deleted), in place of
   the picture or link: its text and what it says, in a dashed frame. */
.attachment-gone {
  padding: 0 0.25rem;
  border: 1px dashed var(--border);
  border-radius: 0.25rem;
  color: var(--muted);
}

/* A mention of a Member in a text: their name now. */
.mention {
  color: var(--accent);
  font-weight: 600;
}

/* @ in the text: the Members to mention, under the cursor, which
   text-expander puts there (app.js fills the list). */
.mention-expander {
  display: block;
  position: relative;
}

.mention-menu {
  position: absolute;
  z-index: 20;
  min-width: 12rem;
  max-width: min(20rem, 90vw);
  margin: 0;
  padding: 0.25rem 0;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
  list-style: none;
  font-size: 0.875rem;
}

.mention-option {
  padding: 0.25rem 0.75rem;
  cursor: pointer;
  overflow-wrap: anywhere;
}

.mention-option[aria-selected="true"],
.mention-option:hover {
  background: var(--bg);
  color: var(--accent);
}

/* Powiązania, under the description: the links grouped by type, one a
   row, the other Task's title cut short to fit; a Closed one's struck
   out. „+ Dodaj powiązanie” opens as „+ nowy epik” does. */
.task-links {
  margin-top: 1.25rem;
}

.task-page-main > .task-links {
  margin-top: 0;
  padding: 0 1.25rem 0.75rem;
}

.task-links h2 {
  margin: 0 0 0.5rem;
  font-size: 1rem;
}

.task-links > .muted {
  margin: 0;
  font-size: 0.875rem;
}

.task-link-group h3 {
  margin: 0.5rem 0 0.25rem;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 500;
}

.task-link-group ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.task-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.875rem;
}

.task-link:last-child {
  border-bottom: 0;
}

.task-link-key {
  flex: none;
  font-weight: 600;
}

.task-link-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.task-link-closed .task-link-key,
.task-link-closed .task-link-title,
.task-link-trashed .task-link-key,
.task-link-trashed .task-link-title {
  color: var(--muted);
  text-decoration: line-through;
}

/* An open Task, not in the Trash, that this one waits for. */
.task-link-blocking .task-link-key {
  color: #be123c;
}

/* „w koszu”, in place of the Status of a Task in the Trash. */
.pill-trash {
  color: var(--muted);
  font-size: 0.75rem;
}

.task-link .pill {
  flex: none;
}

.task-link-remove {
  flex: none;
  margin: 0;
}

.task-link-remove button {
  padding: 0 0.25rem;
  line-height: 1;
}

.link-picker summary {
  width: fit-content;
  margin-top: 0.5rem;
  color: var(--accent);
  font-size: 0.8rem;
  cursor: pointer;
}

.link-picker[open] {
  margin-top: 0.5rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
}

.link-new {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  margin: 0.5rem 0 0;
}

.link-new input {
  width: min(100%, 12rem);
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  font-size: 0.875rem;
}

.link-new select,
.link-new button {
  max-width: 100%;
  padding: 0.25rem 0.5rem;
  font-size: 0.875rem;
}

.link-new .form-error {
  flex-basis: 100%;
  margin: 0;
}

/* The Załączniki tab: the Task's files, one a row. */
.task-attachments {
  margin: 0;
  padding: 0;
  list-style: none;
}

.task-attachments li {
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.875rem;
  overflow-wrap: anywhere;
}

.task-attachments li:last-child {
  border-bottom: 0;
}

.task-attachments time {
  color: var(--muted);
  font-size: 0.8rem;
}

/* Czas pracy: the form of a new Work log, then the Work logs, one a row.
   On the page it sits under the fields. */
.task-page-side > .task-work {
  padding: 0.75rem 1.25rem 1.25rem;
  border-top: 1px solid var(--border);
}

.task-work h2 {
  margin: 0 0 0.5rem;
  font-size: 1rem;
}

.task-logged {
  margin: 0.25rem 0 0;
}

.work-form {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 0.375rem 0.5rem;
  font-size: 0.875rem;
}

.work-form label {
  color: var(--muted);
}

.work-form input {
  width: min(100%, 14rem);
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: inherit;
}

.work-form-hours input {
  width: 5rem;
}

.work-form button {
  grid-column: 2;
  justify-self: start;
  padding: 0.25rem 0.75rem;
  font-size: 0.875rem;
}

.work-form .form-error {
  grid-column: 1 / -1;
  margin: 0;
}

.work-logs {
  margin: 0.75rem 0 0;
  padding: 0;
  list-style: none;
}

.work-logs > li {
  padding: 0.5rem 0;
  border-top: 1px solid var(--border);
  font-size: 0.875rem;
}

.work-log-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
}

.work-log-spent {
  margin-left: auto;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.work-log-note {
  margin: 0.25rem 0 0;
  overflow-wrap: anywhere;
}

.work-log-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.25rem;
}

.work-log-edit[open] {
  flex-basis: 100%;
}

.work-log-edit summary,
.work-log-delete summary {
  list-style: none;
  cursor: pointer;
  font-size: 0.8rem;
}

.work-log-edit summary::-webkit-details-marker,
.work-log-delete summary::-webkit-details-marker {
  display: none;
}

.work-log-edit .work-form {
  margin-top: 0.5rem;
}

/* „Usuń” asks again, in a box under it, as a Comment's does. */
.work-log-delete {
  position: relative;
}

.work-log-delete form {
  position: absolute;
  left: 0;
  z-index: 2;
  width: 16rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
}

.work-log-delete form .hint {
  margin: 0 0 0.5rem;
}

/* A file dragged over the text, which takes it on drop (app.js). */
.markdown-input.drop-target {
  border-color: var(--accent);
  outline: 2px dashed var(--accent);
}

.markdown-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.5rem 0 0;
}

.markdown-actions .hint {
  margin: 0 auto 0 0;
}

.markdown-mine h3,
.markdown-theirs h3 {
  margin: 0 0 0.25rem;
  font-size: 0.875rem;
}

/* Someone else's save since the editor opened: their version, then what
   was typed, which was not saved. */
.markdown-conflict {
  display: grid;
  gap: 0.5rem;
  padding: 0.75rem;
  border-left: 3px solid #a16207;
  background: var(--bg);
}

.markdown-conflict p {
  margin: 0;
}

.markdown-theirs details {
  margin-top: 0.5rem;
  font-size: 0.875rem;
}

/* What changed in a text: deleted struck out, inserted underlined, the
   new lines kept. */
.text-diff {
  margin-top: 0.375rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-size: 0.8125rem;
}

.text-diff del {
  background: #fde2e4;
  color: #9f1239;
}

.text-diff ins {
  background: #dcfce7;
  color: #166534;
  text-decoration: underline;
}

@media (prefers-color-scheme: dark) {
  .text-diff del {
    background: #4c0519;
    color: #fecdd3;
  }

  .text-diff ins {
    background: #052e16;
    color: #bbf7d0;
  }
}

.task-activity-diff summary {
  color: var(--muted);
  font-size: 0.8rem;
  cursor: pointer;
}

/* A text whose version was redacted shows each of the two versions
   alone, one under the other, the redacted one as its marker. */
.text-side + .text-side {
  margin-top: 0.5rem;
}

.text-side p {
  margin: 0;
}

/* The versions an entry spans that were redacted, or that an Admin may
   redact. */
.text-versions {
  margin: 0.5rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.8125rem;
}

.text-versions li + li {
  margin-top: 0.25rem;
}

/* Who removed a text for good, in place of it. */
.redacted {
  color: var(--muted);
  font-style: italic;
}

/* „Usuń treść” and „Usuń plik” ask again, in the flow under them. */
.redaction {
  display: inline-block;
}

.redaction summary {
  font-size: 0.8rem;
  cursor: pointer;
}

.redaction form {
  margin-top: 0.375rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
}

.redaction form .hint {
  margin: 0 0 0.5rem;
}

.task-activity {
  margin: 0;
  padding: 0;
  list-style: none;
}

.task-activity li {
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.875rem;
}

.task-activity li:last-child {
  border-bottom: 0;
}

.task-activity-who {
  font-weight: 600;
}

.task-activity time {
  margin-left: 0.375rem;
  color: var(--muted);
  font-size: 0.8rem;
}

.task-activity-what {
  display: block;
}

/* The Komentarze tab: the field of a new Comment, smaller than a
   description's, then the Comments, newest first. */
.comment-form {
  margin-bottom: 0.75rem;
}

.comment-form .markdown-input,
.comment-form .markdown-preview {
  min-height: 5rem;
}

.comments {
  margin: 0;
  padding: 0;
  list-style: none;
}

.comment {
  padding: 0.5rem 0 0.75rem;
  border-bottom: 1px solid var(--border);
}

.comment:last-child {
  border-bottom: 0;
}

.comment-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.875rem;
}

.comment-head time {
  color: var(--muted);
  font-size: 0.8rem;
}

.comment-actions {
  display: flex;
  align-items: flex-start;
  gap: 0.125rem;
  margin-left: auto;
}

.comment > .markdown,
.comment > .comment-editor {
  margin-top: 0.25rem;
}

.comment-deleted p {
  margin: 0;
  font-size: 0.875rem;
  font-style: italic;
}

/* „Usuń” asks again, in a box under it. */
.comment-delete {
  position: relative;
}

.comment-delete summary {
  list-style: none;
  cursor: pointer;
}

.comment-delete summary::-webkit-details-marker {
  display: none;
}

.comment-delete form {
  position: absolute;
  right: 0;
  z-index: 2;
  width: 16rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
}

.comment-delete form .hint {
  margin: 0 0 0.5rem;
}

/* A Task as a page of its own: the description and tabs on the left,
   the fields in a side column. */
.task-page {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
}

.task-page .task-head {
  border-bottom: 1px solid var(--border);
}

.task-page-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
}

.task-page-main {
  min-width: 0;
  padding: 0.75rem 0 0;
}

.task-page-main > .task-description {
  padding: 0 1.25rem 0.75rem;
}

.task-page-side {
  border-left: 1px solid var(--border);
}

.task-page-side .task-props > div {
  grid-template-columns: 6.5rem minmax(0, 1fr);
}

/* On a phone the panel and the page take the whole screen. */
@media (max-width: 40rem) {
  .task-panel {
    top: 0;
    z-index: 20;
    width: 100vw;
    border-left: 0;
  }

  main:has(.task-panel) {
    margin-right: auto;
  }

  main:has(.task-page) {
    padding: 0;
  }

  .task-page {
    border: 0;
    border-radius: 0;
  }

  .task-page-grid {
    grid-template-columns: 1fr;
  }

  .task-page-side {
    order: -1;
    border-bottom: 1px solid var(--border);
    border-left: 0;
  }

  .task-head,
  .task-fields,
  .task-tab {
    padding-right: 1rem;
    padding-left: 1rem;
  }

  .task-tabs {
    padding: 0 1rem;
  }
}

/* A List other than the Board: its name with „⋯” (a List of the
   Project's own), the quick add, then the table of its Tasks. */
.list-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.list-head h2 {
  margin: 0;
}

.list-menu {
  position: relative;
}

.list-menu summary {
  list-style: none;
  cursor: pointer;
}

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

.list-menu-body {
  position: absolute;
  left: 0;
  z-index: 3;
  display: grid;
  gap: 0.75rem;
  width: min(20rem, calc(100vw - 2rem));
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
}

.danger-link {
  color: #be123c;
}

.list-add {
  margin: 1rem 0 0.5rem;
}

.list-add input[name="title"] {
  width: 100%;
  max-width: 36rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: inherit;
}

.list-add .hint,
.list-add .form-error {
  margin: 0.25rem 0 0;
  font-size: 0.8rem;
}

.list-summary {
  margin: 0 0 0.5rem;
  font-size: 0.875rem;
}

.list-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
}

.list-table th,
.list-table td {
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
}

.list-table th {
  color: var(--muted);
  font-size: 0.875rem;
  font-weight: 600;
}

/* A header sorts by its column: it says which way it is sorted. */
.list-table th a {
  color: inherit;
  text-decoration: none;
}

.list-table th a:hover {
  color: var(--fg);
}

.list-table th[aria-sort="ascending"] a::after {
  content: " ↑";
}

.list-table th[aria-sort="descending"] a::after {
  content: " ↓";
}

.list-table td.list-title {
  min-width: 14rem;
  white-space: normal;
}

.list-title a {
  color: inherit;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.row-epic {
  margin-right: 0.375rem;
  padding: 0 0.375rem;
  border-left: 0.25rem solid var(--palette);
  color: var(--palette);
  font-size: 0.75rem;
  font-weight: 600;
}

.row-labels {
  display: inline-flex;
  margin-left: 0.375rem;
  vertical-align: middle;
}

.list-row-closed .list-title a {
  color: var(--muted);
}

/* A row's title links to its Task; the link covers the whole row but
   its handle. */
.list-row {
  position: relative;
}

.list-row .list-title a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.list-row .list-title a:focus-visible {
  outline: none;
}

.list-row:hover,
.list-row:has(.list-title a:focus-visible) {
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}

.list-row:has(.list-title a:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* The row of the Task open in the panel (app.js). */
.list-row.row-open {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  box-shadow: inset 3px 0 0 var(--accent);
}

/* The handle ⠿, which drags a row in the List's own order (app.js,
   SortableJS); a sorted List has nothing to drag. */
.list-table .list-handle {
  width: 1.5rem;
  padding-right: 0;
}

.row-handle {
  display: none;
  position: relative;
  z-index: 1;
  color: var(--muted);
  cursor: grab;
  touch-action: none;
  user-select: none;
}

.js [data-manual] .row-handle {
  display: inline;
}

.list-row.sortable-ghost {
  opacity: 0.4;
}

/* A row's cells that change a field (Status, Assignee, Priority) sit
   over the link that covers the row. */
.list-row .row-field {
  position: relative;
  z-index: 1;
}

/* A row's checkbox, which picks it for the bulk bar, sits over the link
   that covers the row; a row picked is lit. While one of them is
   dragged, the others picked wait faded (app.js, .row-along). */
.list-table .list-pick {
  width: 1.5rem;
  padding-right: 0;
}

.row-pick {
  position: relative;
  z-index: 1;
}

.list-row:has(.row-pick:checked) {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}

.list-row.row-along {
  opacity: 0.4;
}

/* The bulk bar under the table: without JS a form like any other; with
   it, shown while a row is picked (app.js, data-picked) or it says why
   a change was refused, held at the bottom of the screen as the table
   scrolls, its lists posting as soon as one is chosen. A drag hides it,
   for the zones of the other Lists. */
.list-bulk {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  background: var(--surface);
}

.js .list-bulk {
  position: sticky;
  bottom: 1rem;
  z-index: 10;
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.2);
}

.js .list-bulk:not([data-picked], [data-error]),
.dragging .list-bulk {
  display: none;
}

.list-bulk-count {
  display: none;
  margin: 0;
}

.js .list-bulk-count {
  display: block;
}

.list-bulk-field {
  display: inline-flex;
  gap: 0.25rem;
}

.js .list-bulk-apply {
  display: none;
}

.list-bulk .form-error {
  flex-basis: 100%;
  margin: 0;
}

/* While a card or a row is dragged (app.js, .dragging), the Project's
   other Lists at the bottom of the screen, to drop it on; the Board's
   opens upwards on its Statuses once the drag reaches it. */
.drop-zones {
  display: none;
}

.dragging .drop-zones {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: center;
  gap: 0.5rem;
  width: max-content;
  max-width: calc(100vw - 2rem);
  transform: translateX(-50%);
}

.drop-zone {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 9rem;
  min-height: 3rem;
  padding: 0.5rem 1rem;
  overflow: hidden;
  border: 2px dashed var(--border);
  border-radius: 0.5rem;
  background: var(--surface);
  color: var(--fg);
  font-weight: 600;
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.2);
}

/* The card or the row over a zone: unseen there, but not hidden, which
   would stop the drag (app.js), and the zone lit. */
.drop-zone > .card,
.drop-zone > .list-row {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.drop-zone:has(> .card, > .list-row) {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 15%, var(--surface));
}

.drop-board {
  display: flex;
  flex-direction: column-reverse;
  gap: 0.5rem;
}

.drop-statuses {
  display: none;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  max-width: calc(100vw - 2rem);
}

.drop-board.open .drop-statuses {
  display: flex;
}

.drop-status {
  min-width: 7rem;
  font-weight: 500;
}

/* On a phone the table shows the key, the title and the Status alone;
   a row drags after a press held, as a card does (app.js). */
@media (max-width: 40rem) {
  .list-table .list-handle,
  .list-table .list-assignee,
  .list-table .list-priority,
  .list-table .list-due,
  .list-table .list-estimate {
    display: none;
  }

  .list-table td.list-title {
    min-width: 0;
  }

  .list-table th,
  .list-table td {
    padding: 0.5rem;
  }
}

/* A Project's header: its name, and „Szukaj w MKG” beside it, under it
   on a phone. */
.project-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  margin-bottom: 1rem;
}

.project-header h1 {
  margin: 0;
}

.project-search input {
  width: 16rem;
  max-width: 100%;
}

@media (max-width: 40rem) {
  .project-search,
  .project-search input {
    width: 100%;
  }
}

/* The results of a search: the title and the piece of text found wrap
   rather than widen the table; the words found are marked. */
.search-results td.search-title {
  min-width: 16rem;
  white-space: normal;
}

.search-snippet,
.search-in-comment {
  margin: 0.25rem 0 0;
  font-size: 0.875rem;
}

.search-snippet {
  color: var(--muted);
}

.search-snippet mark {
  padding: 0 0.125rem;
  border-radius: 0.125rem;
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  color: var(--fg);
}

.search-closed .search-title a {
  color: var(--muted);
}

/* The bar of filters over a view (filter-bar): the title's text, then a
   field per <details>, its checkboxes in a box under it, „Pokaż
   zamknięte” and „Wyczyść filtry”. „Filtruj” sends it without JS; with
   JS each change does, and the button hides. On a phone the fields hide
   under „Filtry (n)” (app.js marks the open bar data-shown). */
.filters {
  margin: 0 0 0.75rem;
}

.filters-fields {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.filters-toggle {
  display: none;
}

.filter-text {
  width: min(16rem, 100%);
  padding: 0.375rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  color: var(--fg);
  font: inherit;
}

.filter {
  position: relative;
}

.filter > summary {
  padding: 0.25rem 0.625rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  cursor: pointer;
  list-style: none;
  font-size: 0.875rem;
  white-space: nowrap;
}

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

.filter > summary::after {
  content: " ▾";
  color: var(--muted);
}

.filter:has(.filter-choice:checked) > summary {
  border-color: var(--accent);
  color: var(--accent);
}

.filter-choices {
  position: absolute;
  left: 0;
  z-index: 4;
  display: grid;
  gap: 0.25rem;
  min-width: 12rem;
  max-height: 20rem;
  overflow-y: auto;
  margin: 0.25rem 0 0;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background: var(--surface);
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
}

.filter-choice-label,
.filter-toggle {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.875rem;
  white-space: nowrap;
  cursor: pointer;
}

.filter-project,
.filter-hint {
  margin: 0.25rem 0 0;
  font-size: 0.75rem;
}

.filter-project {
  color: var(--muted);
  font-weight: 600;
}

.filter-former > summary {
  color: var(--muted);
  font-size: 0.8125rem;
  cursor: pointer;
}

.filter-former {
  display: grid;
  gap: 0.25rem;
}

.filters-clear {
  font-size: 0.875rem;
}

.js .filters-apply {
  display: none;
}

.board-summary {
  margin: 0 0 0.5rem;
}

@media (max-width: 40rem) {
  .js .filters-toggle {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    border-color: var(--border);
    background: var(--surface);
    color: var(--fg);
  }

  .js .filters-fields:not([data-shown]) {
    display: none;
  }

  .js .filters-fields {
    margin-top: 0.5rem;
  }

  .filter-choices {
    position: static;
    box-shadow: none;
  }
}

/* The notice of an open form of a Task (edit-notice), which a live
   refresh fills: someone saved another version, „Pokaż zmiany”; or the
   form saves no more, „Kopiuj tekst”. Empty, it takes no room. */
.live-notice:empty {
  display: none;
}

.live-notice {
  margin: 0 0 0.5rem;
}

.live-changes summary,
.draft-copy {
  cursor: pointer;
}

.live-changes .markdown-theirs {
  margin-top: 0.5rem;
}

.draft-copy {
  margin-left: 0.25rem;
  padding: 0.125rem 0.5rem;
}

/* Over the page whose session ended while it was open (app.js): it is no
   longer live, and the link signs in again. */
.signed-out {
  position: fixed;
  inset: auto 1rem 1rem;
  z-index: 30;
  max-width: 32rem;
  margin: 0 auto;
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  border-left: 3px solid #a16207;
  border-radius: 0.375rem;
  background: var(--surface);
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
}

.signed-out p {
  margin: 0;
}
