/*
 * Day Ledger — visual layer on top of Bootstrap.
 *
 * The subject is a paper time sheet: a row of fifteen-minute punch boxes per
 * task, filled from the bottom as the clock runs. Planned boxes are verdigris,
 * anything past the plan is ochre, and overspend is called out in crimson.
 * Numbers are set in tabular monospace so the countdown does not jitter.
 */

:root {
  /* Set live from the appearance dialog; these are the fallbacks. */
  --dl-accent: #2f6f6b;
  --dl-accent-soft: rgba(47, 111, 107, 0.14);
  --dl-accent-strong: #24544f;
  --dl-font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --dl-root-size: 16px;

  --dl-planned: var(--dl-accent);
  --dl-planned-soft: var(--dl-accent-soft);
  --dl-unplanned: #b5651d;
  --dl-unplanned-soft: rgba(181, 101, 29, 0.16);
  --dl-over: #a4243b;
  --dl-rule: rgba(31, 41, 51, 0.14);
  /* Boxes are square: a slot is a unit of time, not a bar to be read as a
     quantity, and a rectangle invited that misreading. */
  --dl-slot-size: 28px;

  --bs-primary: var(--dl-accent);
  --bs-link-color: var(--dl-accent);
  --bs-link-hover-color: var(--dl-accent-strong);
}

html {
  font-size: var(--dl-root-size);
}

body {
  font-family: var(--dl-font);
}

[data-bs-theme="dark"] {
  --dl-unplanned: #d18a3f;
  --dl-unplanned-soft: rgba(209, 138, 63, 0.18);
  --dl-over: #e2607a;
  --dl-rule: rgba(255, 255, 255, 0.14);
}

.btn-primary {
  --bs-btn-bg: var(--dl-accent);
  --bs-btn-border-color: var(--dl-accent);
  --bs-btn-hover-bg: var(--dl-accent-strong);
  --bs-btn-hover-border-color: var(--dl-accent-strong);
  --bs-btn-active-bg: var(--dl-accent-strong);
  --bs-btn-active-border-color: var(--dl-accent-strong);
}

.btn-outline-primary {
  --bs-btn-color: var(--dl-accent);
  --bs-btn-border-color: var(--dl-accent);
  --bs-btn-hover-bg: var(--dl-accent);
  --bs-btn-hover-border-color: var(--dl-accent);
}

body {
  min-height: 100vh;
}

.font-mono,
.time-left__value,
.export-box {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------- navbar */

.app-navbar {
  border-bottom: 1px solid var(--dl-rule);
  background-color: var(--bs-body-bg);
  backdrop-filter: saturate(150%) blur(6px);
}

.brand-mark {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 650;
  letter-spacing: -0.015em;
}

.brand-mark__icon {
  color: var(--dl-accent);
  font-size: 1.05rem;
  line-height: 1;
}

.day-nav {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

#day-label {
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

#day-input {
  width: 9.5rem;
}

.running-chip {
  display: inline-flex;
  align-items: center;
  max-width: 15rem;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  font-size: 0.8125rem;
  border: 1px solid var(--dl-rule);
  cursor: default;
}

/* Accent text on an accent-tinted ground was the low-contrast pair called out
   on screen. The ground stays, the text goes to the body colour. */
.running-chip--live {
  border-color: var(--dl-accent);
  background: var(--dl-accent-soft);
  color: var(--bs-body-color);
  cursor: pointer;
}

.running-chip--idle {
  color: var(--bs-secondary-color);
}

.pulse-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--dl-planned);
  box-shadow: 0 0 0 0 var(--dl-planned);
  animation: dl-pulse 2s infinite;
  flex: none;
}

@keyframes dl-pulse {
  0% { box-shadow: 0 0 0 0 var(--dl-accent-soft); }
  70% { box-shadow: 0 0 0 8px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* The navbar menu must never run off a short window. */
.scroll-menu {
  max-height: min(70vh, 30rem);
  overflow-y: auto;
}

.dropdown-item .badge {
  font-weight: 500;
}

/* ----------------------------------------------------------------- cards */

#board {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.task-card {
  border: 1px solid var(--dl-rule);
  border-left: 3px solid transparent;
  transition: border-color 0.15s ease;
}

/* Focus is not tracking: it is "the card you are looking at", which is what
   keeps a card findable after sorting moves it. */
.task-card.is-focused {
  outline: 2px solid var(--dl-accent);
  outline-offset: 1px;
}

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

.task-card.is-running {
  border-left-color: var(--dl-accent);
  box-shadow: 0 1px 12px var(--dl-accent-soft);
}

.task-name {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 0.15rem;
  overflow-wrap: anywhere;
}

.min-w-0 {
  min-width: 0;
}

/* Icon fonts sit on a text baseline, so an <i> keeps the line box's descender
   space and the glyph rides high in it. The glyph actually lives in ::before,
   so that is what has to become a block with a 1em line box; the flex parent
   then centres a box whose height equals the glyph's em square. */
.slot--add .bi,
.brand-mark__icon,
.step-badge .bi {
  display: block;
  line-height: 1;
}

.slot--add .bi::before,
.brand-mark__icon::before,
.step-badge .bi::before {
  display: block;
  line-height: 1;
}

.btn-ghost {
  border: 0;
  color: var(--bs-secondary-color);
  background: transparent;
}

.btn-ghost > .bi {
  font-size: 1.25rem;
  line-height: 1;
}

.btn-ghost > .bi-list {
  font-size: 1.5rem;
}

.btn-ghost:hover,
.btn-ghost:focus-visible {
  color: var(--bs-body-color);
  background: var(--bs-tertiary-bg);
}

/* The countdown is the loudest thing on the card, on purpose. */
.time-left {
  text-align: right;
  line-height: 1.1;
  min-width: 6.5rem;
}

.time-left__value {
  display: block;
  font-size: 1.6rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--dl-planned);
}

.time-left--over .time-left__value {
  color: var(--dl-over);
}

/* ------------------------------------------------------------ slot strip */

.slot-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 0.9rem;
}

.slot {
  position: relative;
  width: var(--dl-slot-size);
  height: var(--dl-slot-size);
  padding: 0;
  border-radius: 3px;
  border: 1px solid var(--dl-planned);
  background: var(--dl-planned-soft);
  overflow: hidden;
  flex: none;
}

.slot--unplanned {
  border-color: var(--dl-unplanned);
  background: var(--dl-unplanned-soft);
}

.slot__fill {
  position: absolute;
  inset: auto 0 0 0;
  background: var(--dl-planned);
  transition: height 0.4s linear;
}

.slot--unplanned .slot__fill {
  background: var(--dl-unplanned);
}

/* Acknowledged boxes get a punched notch at the top. */
.slot.is-done::before {
  content: "";
  position: absolute;
  top: 3px;
  left: 50%;
  transform: translateX(-50%);
  width: 8px;
  height: 3px;
  border-radius: 2px;
  background: var(--bs-body-bg);
  opacity: 0.85;
  z-index: 2;
}

/* Exported boxes are crossed through. */
.slot.is-tracked::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    45deg,
    transparent 0 3px,
    var(--bs-body-bg) 3px 4px
  );
  opacity: 0.7;
  z-index: 1;
}

.slot:hover,
.slot:focus-visible {
  outline: 2px solid var(--bs-body-color);
  outline-offset: 1px;
}

.slot--add {
  border-style: dashed;
  border-color: var(--dl-rule);
  background: transparent;
  color: var(--bs-secondary-color);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.slot--add:hover {
  color: var(--bs-body-color);
}

/* ----------------------------------------------------------------- steps */

.step-list {
  list-style: none;
  margin: 0.9rem 0 0;
  padding: 0.75rem 0 0;
  border-top: 1px dashed var(--dl-rule);
  display: grid;
  gap: 0.15rem;
}

.step-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
}

.step-row .step-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.step-status {
  flex: none;
  margin-left: auto;
}

/* The badge and the menu it opens are set at the same scale. They were not:
   the badge inherited .badge's 0.75em while the menu used the full body size,
   so the control looked half the size of its own options. */
.step-status {
  --dl-status-size: 0.8125rem;
}

.step-badge {
  cursor: pointer;
  font-size: var(--dl-status-size);
}

.step-status .dropdown-menu {
  --bs-dropdown-font-size: var(--dl-status-size);
  --bs-dropdown-item-padding-y: 0.35rem;
  --bs-dropdown-min-width: 9rem;
}

.step-badge__caret {
  font-size: 0.75em;
  opacity: 0.75;
}

.step-edit-row .step-status {
  margin-left: 0;
}

.step-row--done .step-title {
  text-decoration: line-through;
  color: var(--bs-secondary-color);
}

/* No max-height and no overflow here on purpose. A scroller inside a scrollable
   modal body gives you two nested scrollbars for one list, and its overflow
   clips anything a control inside tries to render outside the row. The modal
   body is already scrollable; let it do the job. */
.step-edit-list,
.link-edit-list {
  overflow: visible;
}

.step-state-select {
  flex: none;
  width: auto;
  min-width: 7.5rem;
}

.step-edit-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Label plus its pin toggle take a third; the URL gets the rest. */
.link-label-group {
  flex: 0 0 auto;
  width: 34%;
  min-width: 10rem;
}

.task-link:hover {
  border-color: var(--dl-accent);
  background: var(--dl-accent-soft);
}

.detail-links {
  padding-left: 1.1rem;
}

.drag-handle {
  cursor: grab;
  color: var(--bs-secondary-color);
}

.step-ghost {
  opacity: 0.4;
}

.step-title-input {
  flex: 1 1 auto;
}

/* ---------------------------------------------------------------- dialogs */

.modal-body {
  overflow-x: hidden;
  word-break: break-word;
}

.modal-body .table {
  table-layout: fixed;
}

/* Both panes stretch to the row, and the row to the dialog, so the editor is
   as tall as the space it was given instead of a fixed box floating in it. */
.note-editor {
  min-height: 60vh;
}

.md-editor {
  position: relative;
  min-height: 60vh;
  display: flex;
}

/* The two layers share every metric that affects glyph position. Change one,
   change the other, or the caret drifts away from the text. */
.md-highlight,
.md-input {
  margin: 0;
  width: 100%;
  border: 1px solid var(--dl-rule);
  border-radius: var(--bs-border-radius);
  padding: 0.75rem 1rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.875rem;
  line-height: 1.6;
  tab-size: 2;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  overflow: auto;
}

.md-highlight {
  position: absolute;
  inset: 0;
  background: var(--bs-tertiary-bg);
  pointer-events: none;
}

.md-input {
  position: relative;
  z-index: 1;
  resize: none;
  background: transparent;
  color: transparent;
  caret-color: var(--bs-body-color);
}

.md-input:focus {
  outline: 2px solid var(--dl-accent);
  outline-offset: -1px;
}

.md-input::selection {
  background: var(--dl-accent-soft);
  color: transparent;
}

/* Markdown token colours, derived from the theme rather than a vendor theme
   file, so light and dark both work without a second stylesheet. */
.hljs-section {
  color: var(--dl-accent);
  font-weight: 700;
}

.hljs-strong {
  color: var(--bs-body-color);
  font-weight: 700;
}

.hljs-emphasis {
  color: var(--bs-body-color);
  font-style: italic;
}

.hljs-code {
  color: var(--dl-unplanned);
}

.hljs-bullet,
.hljs-symbol {
  color: var(--dl-accent);
}

.hljs-quote {
  color: var(--bs-secondary-color);
  font-style: italic;
}

.hljs-link,
.hljs-string {
  color: var(--dl-unplanned);
}

.note-preview {
  min-height: 60vh;
  overflow-y: auto;
  border: 1px solid var(--dl-rule);
  border-radius: var(--bs-border-radius);
  padding: 0.75rem 1rem;
  background: var(--bs-tertiary-bg);
}

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

.markdown-body pre {
  background: var(--bs-body-bg);
  padding: 0.6rem 0.8rem;
  border-radius: var(--bs-border-radius);
  overflow-x: auto;
}

.markdown-body code {
  font-size: 0.85em;
}

.markdown-body blockquote {
  border-left: 3px solid var(--dl-rule);
  padding-left: 0.8rem;
  color: var(--bs-secondary-color);
}

.export-box {
  min-height: 16rem;
  font-size: 0.75rem;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}

.dropzone {
  border: 2px dashed var(--dl-rule);
  border-radius: var(--bs-border-radius-lg);
  padding: 1.25rem;
  text-align: center;
}

.dropzone.is-over {
  border-color: var(--dl-planned);
  background: var(--dl-planned-soft);
}

.dropzone__icon {
  font-size: 1.75rem;
  color: var(--bs-secondary-color);
}

/*
 * No rule here touches .form-check.
 *
 * .copy-row used to set `padding` on the .form-check element itself, which
 * overrode Bootstrap's padding-left: 1.5em. The input is float:left with
 * margin-left:-1.5em, so it was laid out outside the row and clipped: present,
 * checked, and invisible. Padding belongs on the .list-group-item around it.
 */
.day-list {
  overflow: visible;
}

/* ------------------------------------------------------------ empty/boot */

.empty-state {
  text-align: center;
  padding: 4rem 1rem;
  border: 1px dashed var(--dl-rule);
  border-radius: var(--bs-border-radius-lg);
  color: var(--bs-secondary-color);
}

.empty-state h2 {
  font-size: 1.125rem;
  color: var(--bs-body-color);
}

.empty-state__icon {
  font-size: 2rem;
  display: block;
  margin-bottom: 0.75rem;
}

#boot-screen {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--bs-body-bg);
  z-index: 2000;
}

@media (max-width: 575.98px) {
  #day-input { width: 8.5rem; }
  .time-left__value { font-size: 1.3rem; }
  .time-left { min-width: 5rem; }
}

@media (prefers-reduced-motion: reduce) {
  .pulse-dot { animation: none; }
  .slot__fill { transition: none; }
}

/* ------------------------------------------------------- appearance dialog */

.ap-heading {
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: 0.6875rem;
  color: var(--bs-secondary-color);
}

.swatch-grid {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 0.4rem;
}

.swatch {
  aspect-ratio: 1;
  border-radius: 50%;
  border: 2px solid transparent;
  background: var(--swatch);
  padding: 0;
}

[data-bs-theme="dark"] .swatch {
  background: var(--swatch-dark);
}

.swatch.is-active {
  border-color: var(--bs-body-color);
  box-shadow: inset 0 0 0 2px var(--bs-body-bg);
}

.icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(2.6rem, 1fr));
  gap: 0.3rem;
  max-height: 14rem;
  overflow-y: auto;
  padding: 0.25rem;
  border: 1px solid var(--dl-rule);
  border-radius: var(--bs-border-radius);
}

.icon-pick {
  aspect-ratio: 1;
  border: 1px solid transparent;
  border-radius: var(--bs-border-radius);
  background: transparent;
  color: var(--bs-body-color);
  font-size: 1.1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.icon-pick:hover {
  background: var(--bs-tertiary-bg);
}

.icon-pick.is-active {
  border-color: var(--dl-accent);
  color: var(--dl-accent);
  background: var(--dl-accent-soft);
}

/* Three properties of a box, weighted the same. */
.slot-toggles {
  display: grid;
  gap: 0.35rem;
}

/* The border and padding go on a wrapper, never on the .form-check, for the
   same reason as above. */
.slot-toggle {
  border: 1px solid var(--dl-rule);
  border-radius: var(--bs-border-radius);
  padding: 0.5rem;
}


/* ---------------------------------------------------------------- motion */

/* One switch, set on <html> by applyAppearance(). Covers Bootstrap's own
   transitions too, which is why it is written this broadly. */
[data-dl-motion="off"] *,
[data-dl-motion="off"] *::before,
[data-dl-motion="off"] *::after {
  animation-duration: 0s !important;
  animation-delay: 0s !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0s !important;
  transition-delay: 0s !important;
  scroll-behavior: auto !important;
}

[data-dl-motion="off"] .pulse-dot {
  animation: none;
}

.task-link {
  text-decoration: none;
  max-width: 100%;
  overflow-wrap: anywhere;
}

.task-link:hover {
  border-color: var(--dl-accent) !important;
  background: var(--dl-accent-soft);
}

.chip-time {
  opacity: 0.85;
}

.activity-log,
.details-note {
  max-height: 18rem;
  overflow-y: auto;
}

.details-note {
  min-height: 0;
}

/* --------------------------------------------------------- box edit menu */

.slot-wrap {
  display: inline-flex;
}

/* Bootstrap adds a caret to anything with data-bs-toggle="dropdown"; a 28px
   square has no room for one. */
.slot-wrap .slot::after {
  display: none;
}

.slot-menu {
  min-width: 16rem;
  padding-top: 0.5rem;
}
