/* F05 — the dictionary editor, and the surfaces F04's issues and F08's hit
   counts render into.

   It lives in a modal now, opened from the app bar, and each keyword is one line
   under a row of column heads — a table in everything but markup. It is not a
   real <table> because a row has to carry two things a table cell cannot: the
   row's own state (fired / idle / off / just-added), which needs a box to paint,
   and F04's per-row issues, which need to span the full width underneath. A
   grid whose column template is shared with the heads gives the alignment
   without giving up either. */

.dictionary {
  /* The shared column template. Declared once, used by the heads and by every
     row, which is the whole reason the columns line up. */
  --dictionary-columns:
    minmax(6rem, 1.6fr)
    minmax(6rem, 1.6fr)
    2.75rem
    4.5rem
    2.25rem
    4.25rem
    4.5rem;

  width: min(66rem, calc(100vw - 2rem));
  max-height: min(46rem, calc(100vh - 3rem));
  padding: 0;
  border: 1px solid var(--colour-border);
  border-radius: 12px;
  background: var(--colour-shell);
  color: var(--colour-text);
  box-shadow: 0 18px 48px rgb(0 0 0 / 24%);
  overflow: hidden;
}

.dictionary::backdrop {
  background: rgb(26 26 25 / 45%);
}

.dictionary--drop-target {
  outline: 2px dashed var(--colour-accent);
  outline-offset: -6px;
}

/* The dialog itself is the frame; the panel is what scrolls, so the header does
   not scroll away from a long dictionary. */
.dictionary__panel {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  max-height: inherit;
  padding: 0 1.25rem 1.25rem;
  overflow: auto;
}

.dictionary__header {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin: 0 -1.25rem;
  padding: 1rem 1.25rem 0.75rem;
  border-bottom: 1px solid var(--colour-border-soft);
  background: var(--colour-shell);
}

.dictionary__title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
}

.dictionary__tally {
  font-size: 0.7rem;
  color: var(--colour-text-muted);
  font-variant-numeric: tabular-nums;
}

.dictionary__close {
  margin-left: auto;
  align-self: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 1px solid var(--colour-border);
  border-radius: 50%;
  background: var(--colour-surface);
  color: var(--colour-text-muted);
  font: inherit;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

.dictionary__close:hover {
  border-color: var(--colour-accent);
  color: var(--colour-accent-ink);
}

.dictionary__close:focus-visible {
  outline: 2px solid var(--colour-accent);
  outline-offset: 2px;
}

/* Where the notices region is parked while the dialog is open. It collapses
   both when the region is elsewhere and when it is here with nothing in it, so
   the panel's gap does not open up around an empty slot. */
.dictionary__notices:not(:has(.notice)) {
  display: none;
}

/* The region's own page framing does not apply once it is inside the panel. */
.dictionary__notices .notices:not(:empty) {
  padding: 0;
}

/* ----------------------------------------------------------- the app bar tab */

.dictionary-open {
  gap: 0.5rem;
  min-width: 0;
}

/* The profile the workspace is masking with, on the control that opens it. Read
   only here and edited in the panel, which is where the name belongs: the bar
   only has to answer which dictionary this is. Given a ceiling and an ellipsis,
   because a name is user input and the bar is not allowed to grow with it. */
.dictionary-open__profile {
  overflow: hidden;
  max-width: 10rem;
  padding-left: 0.5rem;
  border-left: 1px solid var(--colour-border);
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dictionary-open__count {
  padding: 0.15rem 0.4rem;
  border-radius: var(--radius-pill);
  background: rgb(0 0 0 / 6%);
  font-size: 0.65rem;
  font-weight: 400;
  color: var(--colour-text-muted);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------- the profile name */

/* Above the toolbar rather than in the header: it belongs to the dictionary
   below it, and a field wedged between the title and the close button would
   read as chrome of the dialog instead. */
.dictionary__profile {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.35rem 0.75rem;
}

.dictionary__field--profile {
  width: min(18rem, 100%);
}

.dictionary__profile-name {
  width: 100%;
  font-weight: 500;
}

.dictionary__profile-note {
  flex: 1 1 12rem;
  margin: 0 0 0.35rem;
  font-size: 0.7rem;
  color: var(--colour-text-muted);
}

/* -------------------------------------------------------------- the toolbar */

.dictionary__toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 0.75rem;
}

.dictionary__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.dictionary__field {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.dictionary__field--filter {
  margin-left: auto;
  width: min(16rem, 100%);
}

.dictionary__field-label {
  font-size: 0.65rem;
  color: var(--colour-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.dictionary__undo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-small);
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-small);
  background: var(--colour-surface);
  font-size: 0.8rem;
}

/* Toggled by the hidden attribute, and an author `display` outranks the
   user-agent rule that would otherwise honour it. */
.dictionary__undo[hidden] {
  display: none;
}

.dictionary__empty,
.dictionary__privacy {
  margin: 0;
  font-size: 0.75rem;
  color: var(--colour-text-muted);
}

.dictionary__privacy {
  border-top: 1px solid var(--colour-border-soft);
  padding-top: 0.6rem;
}

/* ---------------------------------------------------------------- the table */

.dictionary__table {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.dictionary__columns {
  display: grid;
  grid-template-columns: var(--dictionary-columns);
  gap: 0.5rem;
  padding: 0 0.6rem 0.35rem;
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--colour-text-muted);
}

/* The flag and hit columns read as headings over their controls, so they centre
   over them rather than sitting left of them. */
.dictionary__columns span:nth-child(n + 3):nth-child(-n + 6) {
  text-align: center;
}

.dictionary__rows {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.dictionary__row {
  display: grid;
  grid-template-columns: var(--dictionary-columns);
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--colour-border);
  border-radius: 8px;
  background: var(--colour-surface);
}

/* The mockups' two chip states: a rule that fired carries the accent, a rule
   that is idle or switched off recedes. */
.dictionary__row--matched {
  border-color: var(--colour-accent-line);
}

.dictionary__row--disabled {
  background: rgb(0 0 0 / 2%);
  border-color: var(--colour-border-soft);
}

.dictionary__row--hidden {
  display: none;
}

.dictionary__row--emphasised {
  border-color: var(--colour-accent);
  box-shadow: 0 0 0 3px var(--colour-accent-ring);
}

/* F14 — the row a marked term just became. */
.dictionary__row--flash {
  animation: dictionary-row-flash 1.4s ease-out;
}

@keyframes dictionary-row-flash {
  from {
    border-color: var(--colour-success);
    background: var(--colour-success-surface);
  }

  to {
    border-color: var(--colour-border);
    background: var(--colour-surface);
  }
}

@media (prefers-reduced-motion: reduce) {
  /* The confirmation still has to land, so it holds still instead of fading. */
  .dictionary__row--flash {
    animation: none;
    border-color: var(--colour-success);
    background: var(--colour-success-surface);
  }
}

.dictionary__cell {
  display: flex;
  min-width: 0;
}

.dictionary__term,
.dictionary__replacement {
  width: 100%;
  min-width: 0;
  padding: 0.3rem 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
}

.dictionary__replacement {
  color: var(--colour-accent-ink);
}

.dictionary__flag {
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.dictionary__flag input {
  margin: 0;
  accent-color: var(--colour-accent);
  cursor: pointer;
}

/* The hit count, as the mockups' pill. A count of 0 keeps the warning colour
   rather than the mockups' grey: F08 requirement 4 makes a rule that fired
   nothing a finding, not a neutral value, and that outranks the palette. */
.dictionary__hits {
  margin: 0;
  display: flex;
  gap: 0.2rem;
  align-items: baseline;
  justify-content: center;
  padding: 0.2rem 0.35rem;
  border-radius: var(--radius-pill);
  background: var(--colour-accent-surface);
  color: var(--colour-accent-ink);
  font-family: var(--font-mono);
  font-size: 0.65rem;
  font-variant-numeric: tabular-nums;
}

.dictionary__hits-value {
  font-weight: 600;
}

.dictionary__hits-label {
  font-weight: 400;
}

.dictionary__hits:has(.dictionary__hits-value--zero) {
  background: var(--colour-warning-surface);
  color: var(--colour-warning);
}

.dictionary__hits:has(.dictionary__hits-value--off) {
  background: rgb(0 0 0 / 5%);
  color: var(--colour-text-muted);
}

.dictionary__hits-value--off {
  font-weight: 400;
}

/* F16 — the same full-width treatment as a row's issues, and the same reason:
   a suspended rule is a state of the row, not a seventh column of it. */
.dictionary__override {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-small);
  margin: 0.1rem 0 0;
  padding: 0.3rem 0.45rem;
  border-left: 3px solid currentcolor;
  border-radius: var(--radius-small);
  font-size: 0.7rem;
  color: var(--colour-warning);
  background: var(--colour-warning-surface);
}

.dictionary__override[hidden] {
  display: none;
}

/* ---------------------------------------------------------------- the issues */

.dictionary__issues,
.dictionary__row-issues {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

/* F04's per-row findings take the full width under the line they belong to,
   which is the one thing a single table row could not have given them. */
.dictionary__row-issues {
  grid-column: 1 / -1;
  margin-top: 0.1rem;
}

/* Same reason as .dictionary__undo[hidden]: both lists are emptied and hidden
   together when a keyword has nothing wrong with it. */
.dictionary__issues[hidden],
.dictionary__row-issues[hidden] {
  display: none;
}

.dictionary__issue {
  padding: 0.3rem 0.45rem;
  border-radius: var(--radius-small);
  font-size: 0.7rem;
  /* Reachable without hover: the text is always on screen, never in a tooltip. */
  border-left: 3px solid currentcolor;
}

.dictionary__issue--error {
  color: var(--colour-error);
  background: var(--colour-error-surface);
}

.dictionary__issue--warning {
  color: var(--colour-warning);
  background: var(--colour-warning-surface);
}

/* ------------------------------------------------------------------ narrow */

@media (max-width: 52rem) {
  /* Below this the seven columns stop being legible as columns. The row folds
     into two lines — the pair of fields, then the flags and the count — and the
     heads go with them, because a head over nothing is worse than no head. */
  .dictionary {
    width: 100vw;
    max-width: 100vw;
    max-height: 100vh;
    border-radius: 0;
  }

  .dictionary__columns {
    display: none;
  }

  .dictionary__row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    row-gap: 0.4rem;
    padding: 0.6rem;
  }

  .dictionary__flag,
  .dictionary__hits {
    justify-content: flex-start;
  }

  /* The labels are the only thing naming these controls once the heads are
     gone, so they come back into view. */
  .dictionary__flag .visually-hidden,
  .dictionary__cell .visually-hidden {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    clip-path: none;
    font-size: 0.6rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-text-muted);
  }

  .dictionary__cell {
    flex-direction: column;
    gap: 0.15rem;
  }

  .dictionary__flag {
    gap: 0.3rem;
  }

  .dictionary__field--filter {
    margin-left: 0;
    width: 100%;
  }
}
