/*
 * Notarium — the notification centre and its preference matrix
 *
 * Four surfaces, one design: the bell popover, the slide-over panel, /beskeder,
 * and the kind × channel matrix under Indstillinger.
 *
 * Split out of koncern.css so one agent can own this surface. The file is
 * named `koncern_*` ON PURPOSE: `stylesheet_link_tag :app` emits every
 * sheet in ALPHABETICAL order, and koncern.css currently loads BEFORE
 * notarium.css, so notarium.css wins ties against it. A file called
 * `palette.css` or `notifications.css` would sort AFTER notarium.css and
 * silently start winning ties this CSS has never won. `koncern_…` keeps it
 * between koncern.css and marketing.css — exactly where it has always been.
 *
 * CONSEQUENCE, and it bites on the preference matrix below: anything here that
 * has to beat a `.nt-*` component rule must OUT-SPECIFY it, not merely come
 * later. `.nt-table th` is (0,1,1); `.koncern-prefs th` is also (0,1,1) and
 * would LOSE. Hence `.nt-table.koncern-prefs th` throughout.
 *
 * ── The colour rule this file exists to enforce ─────────────────────────
 * The design system's law (notarium.css:6-11): bordeaux is IDENTITY, green is
 * "i orden", amber is "a frist is approaching", and red means OVERDUE and
 * nothing else.
 *
 * An unread row used to be washed in `--nt-seal-soft` (#f9edee) and a critical
 * one wore a `--nt-danger-soft` (#f8e8e6) chip over a `--nt-danger` rail — two
 * pale pinks 2% apart, from two different token families, under a solid
 * bordeaux bell badge. Worse, the wash was identical for an unread CRITICAL
 * row and an unread ORDINARY one, so the background separated nothing at all
 * while shouting like an alert.
 *
 * So the two axes are now carried on two different CHANNELS, not two shades:
 *
 *   unread   → a bordeaux marker dot in a fixed left gutter, plus full-strength
 *              ink and a heavier title. Never a background. It is the same
 *              bordeaux as the bell badge because it is the same fact: the dot
 *              in the list and the number on the bell are one counter.
 *   critical → a chip, sized like a chip, in the frist vocabulary: amber for
 *              "kritisk" (a frist approaching), red ONLY for "overskredet".
 *              See Workspace::NotificationsController#notification_flag.
 *
 * Background tint is now reserved for hover — a neutral `--nt-surface-raised`,
 * which says "you are pointing at this" and nothing about the message.
 */

/* ══════════════════════════════════════════════════════════════════════
   8. NOTIFICATION CENTRE
   ══════════════════════════════════════════════════════════════════════ */

.koncern-bell { position: relative; display: inline-flex; }

.koncern-bell-button { position: relative; color: var(--nt-text-secondary); }

/* The popover. Wider than a menu because it is a list you read rather than one
   you pick from — and only the LIST scrolls: the unread count and "se alle"
   are the two things a glance is for, so they must not be the parts that
   disappear off the bottom.

   Doubled up as `.nt-navbar-menu.koncern-bell-menu` to zero the padding:
   `.nt-menu` sets `padding: 0.3rem`, it is the same specificity, and it lives
   in notarium.css — which loads AFTER this file and therefore wins ties (see
   the file header). The panel's own rows and rules run edge to edge. */
.nt-navbar-menu.koncern-bell-menu {
  width: min(23rem, calc(100vw - 1.5rem));
  overflow: hidden;
  padding: 0;
}

.koncern-bell-menu .koncern-panel {
  max-height: min(30rem, calc(100dvh - 6rem));
}

.koncern-bell-menu .koncern-note-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* The badge and the unread dots are deliberately the same bordeaux: one fact,
   one colour. Tabular figures so 9 → 10 does not shift the disc. */
.koncern-badge-count {
  position: absolute;
  top: 0;
  right: 0;
  min-width: 1.05rem;
  height: 1.05rem;
  padding: 0 0.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--nt-radius-full);
  background: var(--nt-seal);
  color: var(--nt-on-seal);
  font-family: var(--nt-font-mono);
  font-size: 0.64rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  pointer-events: none;
  box-shadow: 0 0 0 2px var(--nt-surface);
}

/* — /beskeder: filters — */

.koncern-filters {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--nt-space-4);
  flex-wrap: wrap;
}

.koncern-filter-tabs {
  display: inline-flex;
  gap: 0.15rem;
  padding: 0.2rem;
  border-radius: var(--nt-radius);
  border: 1px solid var(--nt-border-subtle);
  background: var(--nt-surface-raised);
}

.koncern-filter-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.75rem;
  border-radius: var(--nt-radius-sm);
  font-size: var(--nt-text-sm);
  color: var(--nt-text-secondary);
  text-decoration: none;
  transition: background-color var(--nt-duration-fast) var(--nt-ease), color var(--nt-duration-fast) var(--nt-ease);
}

.koncern-filter-tab:hover { color: var(--nt-text); }

.koncern-filter-tab[aria-current="true"] {
  background: var(--nt-surface);
  color: var(--nt-text);
  font-weight: 600;
  box-shadow: var(--nt-shadow-1);
}

/* The count is what makes a filter tab worth clicking — "Ulæste 0" saves the
   click that "Ulæste" costs. Mono + tabular so the tabs do not resize as the
   numbers change under a Turbo Stream. */
.koncern-filter-tab-count {
  font-family: var(--nt-font-mono);
  font-size: var(--nt-text-xs);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  color: var(--nt-text-tertiary);
}

.koncern-filter-tab[aria-current="true"] .koncern-filter-tab-count { color: var(--nt-text-secondary); }

.koncern-filter-kind { display: flex; align-items: flex-end; gap: 0.5rem; }
.koncern-filter-kind .nt-label { margin-bottom: 0.35rem; white-space: nowrap; }
.koncern-filter-kind .nt-select { width: auto; min-width: 12rem; }

/* — The row, shared by all three list surfaces — */

.koncern-note-list { display: flex; flex-direction: column; }

/* Three columns: the unread gutter, the message, the actions. The gutter is
   always there — including on read rows, where it is empty — so every title in
   the list starts on the same vertical line and the dots form a column the eye
   can run down. That column IS the unread signal; take the gutter away and you
   are back to bold-text-only, which is what the background wash was there to
   prevent. */
.koncern-note {
  position: relative;
  display: grid;
  grid-template-columns: 0.5rem minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--nt-space-3);
  padding: var(--nt-space-4) var(--nt-space-5);
  border-bottom: 1px solid var(--nt-border-subtle);
  transition: background-color var(--nt-duration-fast) var(--nt-ease);
}

.koncern-note:last-child { border-bottom: 0; }

/* Neutral, and only on hover. The row's background says "you are pointing at
   this" — never "this is urgent". */
.koncern-note:hover { background: var(--nt-surface-raised); }
.koncern-note:focus-within { background: var(--nt-surface-raised); }

.koncern-note-mark {
  width: 0.5rem;
  height: 0.5rem;
  /* Optically on the title's first line rather than on the row's top edge —
     `align-items: start` puts it at the top of a 3-line grid cell otherwise. */
  margin-top: 0.42rem;
  border-radius: 50%;
  background: transparent;
}

.koncern-note-unread .koncern-note-mark { background: var(--nt-seal); }

.koncern-note-body { min-width: 0; }

/* Weight and ink are the second and third unread channels, after the dot. A
   read row is not greyed out — it is still a record you have to be able to
   read in a list of 30 — it just stops competing. */
.koncern-note-title {
  font-size: var(--nt-text-base);
  font-weight: 500;
  color: var(--nt-text-secondary);
  line-height: 1.4;
}

.koncern-note-unread .koncern-note-title {
  font-weight: 650;
  color: var(--nt-text);
}

/* The chip flows inline inside the title (see the partial). It sets its own
   weight, size and colour, so it does not inherit the title's — but it does
   need to be pushed off the last word and nudged onto the text's optical
   line. */
.koncern-note-flag {
  margin-left: 0.45rem;
  vertical-align: 0.05em;
}

.koncern-note-text {
  margin-top: 0.2rem;
  font-size: var(--nt-text-sm);
  color: var(--nt-text-secondary);
  max-width: var(--nt-prose-max);
}

.koncern-note-meta {
  margin-top: 0.35rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  font-size: var(--nt-text-xs);
  color: var(--nt-text-tertiary);
  font-variant-numeric: tabular-nums;
}

/* The actions sit on the title's line, not centred against a 3-line row: a
   check button that floats to the vertical middle of a long besked reads as
   belonging to the body text rather than to the row. */
.koncern-note-actions {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding-top: 0.05rem;
}

/* `position: relative` makes this "positioned": the mark-read form sits
   after the open link in DOM order, so once the stretched link below is
   added, a positioned-and-later element already paints on top and stays
   clickable — no z-index tug-of-war needed. */
.koncern-note-actions form { margin: 0; position: relative; }

/* Stretched link: when a besked has a destination, the whole row is the
   click target. The <a> itself is visually empty (its accessible name lives
   in a visually-hidden span); ::after extends its box to the row's edges
   via the nearest positioned ancestor, `.koncern-note`. */
.koncern-note-linked { cursor: pointer; }

.koncern-note-open {
  position: static;
  width: 0;
  height: 0;
  overflow: visible;
  border: 0;
  padding: 0;
  background: transparent;
  font-size: 0;
}

.koncern-note-open::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* No visible action except the stretched link: collapse the column so a
   read row does not keep a hole where "Åbn" used to sit. `:has(form)` is
   the mark-read button, which must keep its seat. */
.koncern-note-actions:not(:has(form)) {
  width: 0;
  min-width: 0;
  padding: 0;
  overflow: visible;
}

/* Compact: the popover and the slide-over. ~336px of usable width once the
   dropdown's own padding is gone, so the body gets a two-line clamp and the
   row loses the page's generous side padding. */
.koncern-note-compact {
  padding: var(--nt-space-3) var(--nt-space-4);
  gap: var(--nt-space-2);
}

.koncern-note-compact .koncern-note-title { font-size: var(--nt-text-sm); }

.koncern-note-compact .koncern-note-text {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* — The panel body: popover and slide-over — */

.koncern-panel { display: flex; flex-direction: column; }

.koncern-panel-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nt-space-3);
  padding: var(--nt-space-3) var(--nt-space-4);
  border-bottom: 1px solid var(--nt-border-subtle);
}

.koncern-panel-heading {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

/* Only the popover renders this: the slide-over's title belongs to
   shared/_slide_over's chrome, and two titles in one panel is one too many. */
.koncern-panel-title {
  font-family: var(--nt-font-display);
  font-size: var(--nt-text-md);
  font-weight: 600;
  color: var(--nt-text);
  line-height: 1.2;
}

.koncern-panel-count {
  font-size: var(--nt-text-xs);
  color: var(--nt-text-tertiary);
}

/* One row, two weights: the way on ("se alle") and the way out ("indstil
   påmindelser"). It used to be two stacked full-width ghost buttons, which
   gave a 23rem dropdown two blocks of chrome heavier than the beskeder above
   them. */
.koncern-panel-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nt-space-2);
  padding: var(--nt-space-2) var(--nt-space-3);
  border-top: 1px solid var(--nt-border-subtle);
}

.koncern-panel .nt-empty { padding: var(--nt-space-6) var(--nt-space-4); }

.koncern-footnote {
  display: flex;
  flex-direction: column;
  gap: var(--nt-space-1);
  font-size: var(--nt-text-sm);
  color: var(--nt-text-tertiary);
  max-width: var(--nt-prose-max);
}

/* — /beskeder: the list card — */

/* The rows run edge to edge inside the card, so the card supplies no padding
   of its own — hence `overflow: hidden`, which is what keeps the first row's
   corners inside the card's radius. `.nt-pagination` already brings its own
   top rule, so the bar under the last row needs nothing extra. */
.nt-card.koncern-note-card { overflow: hidden; }

/* ══════════════════════════════════════════════════════════════════════
   9. NOTIFICATION PREFERENCES — the kind × channel matrix
   ══════════════════════════════════════════════════════════════════════

   A matrix has to answer two questions at once: "what does Notarium do with
   THIS message" (read across) and "what does SMS do at all" (read down).
   Reading down is what a bare table of checkboxes fails at, so the channel
   columns get vertical rules and a shared alignment, and the row header gets
   real body copy instead of the mono/uppercase `.nt-table th` treatment —
   which is what the inline `style=` attributes in this view used to undo.

   Colour discipline here matters as much as in the list: the locked "Altid"
   cells used to be bordeaux chips, one per row in a column where EVERY row is
   locked, which turned "in-app cannot be switched off" — a piece of dull
   plumbing — into the loudest thing on a settings page. They are neutral now.
   The only colour left is the amber lock on a critical override, which is
   exactly amber's job: a frist is approaching and this cannot be silenced. */

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

.nt-table.koncern-prefs { table-layout: auto; }

.nt-table.koncern-prefs th,
.nt-table.koncern-prefs td { vertical-align: top; }

/* Channel columns: centred, ruled, and as narrow as their content allows so
   the message column keeps the width that makes the descriptions readable. */
.nt-table.koncern-prefs .koncern-prefs-cell {
  width: 1%;
  text-align: center;
  border-left: 1px solid var(--nt-border-subtle);
  padding-left: var(--nt-space-4);
  padding-right: var(--nt-space-4);
}

/* Column headers stop being mono/uppercase/xs: these are three words a person
   has to read as words, not as a data-grid legend. */
.nt-table.koncern-prefs thead th.koncern-prefs-cell {
  font-family: var(--nt-font-body);
  font-size: var(--nt-text-sm);
  font-weight: 600;
  text-transform: none;
  letter-spacing: normal;
  color: var(--nt-text);
  padding-top: var(--nt-space-4);
  padding-bottom: var(--nt-space-4);
}

.nt-table.koncern-prefs thead th.koncern-prefs-kind {
  padding-top: var(--nt-space-4);
  padding-bottom: var(--nt-space-4);
}

.nt-table.koncern-prefs th.koncern-prefs-kind {
  white-space: normal;
  font-family: var(--nt-font-body);
  font-size: var(--nt-text-base);
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--nt-text);
  min-width: 15rem;
}

.koncern-prefs-kind-name {
  font-weight: 600;
  color: var(--nt-text);
}

.koncern-prefs-kind-note {
  margin-top: 0.15rem;
  font-size: var(--nt-text-sm);
  font-weight: 400;
  color: var(--nt-text-secondary);
  max-width: 26rem;
}

/* — Cell states — */

.koncern-prefs-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
}

/* A real box, not a 16px system checkbox: this is the one control on the page,
   and a column of them is what the user scans. `appearance: none` is safe here
   — nothing in notarium.css styles a bare checkbox, and this file is unlayered
   so it also beats any Tailwind utility on the same property. */
.koncern-prefs-switch input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 1.3rem;
  height: 1.3rem;
  margin: 0;
  border: 1.5px solid var(--nt-border-strong);
  border-radius: var(--nt-radius-sm);
  background: var(--nt-surface);
  cursor: pointer;
  position: relative;
  transition: background-color var(--nt-duration-fast) var(--nt-ease),
              border-color var(--nt-duration-fast) var(--nt-ease);
}

.koncern-prefs-switch:hover input[type="checkbox"] { border-color: var(--nt-seal); }

.koncern-prefs-switch input[type="checkbox"]:checked {
  background: var(--nt-seal);
  border-color: var(--nt-seal);
}

/* The tick, drawn rather than glyphed: a text checkmark inherits the body
   font's baseline and never centres in a 1.3rem box. */
.koncern-prefs-switch input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 0.4rem;
  top: 0.16rem;
  width: 0.32rem;
  height: 0.62rem;
  border: solid var(--nt-on-seal);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.koncern-prefs-switch input[type="checkbox"]:focus-visible {
  outline: none;
  box-shadow: var(--nt-shadow-focus);
}

/* Locked: a fact about the plumbing, so it is set in the quietest voice the
   page has. Icon AND word — "colour alone is not a status signal" applies to
   the absence of colour too. */
.koncern-prefs-locked {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: var(--nt-text-xs);
  font-weight: 500;
  color: var(--nt-text-secondary);
  white-space: nowrap;
}

.koncern-prefs-locked svg { color: var(--nt-text-tertiary); }

/* The override lock: amber, because the thing it cannot silence is a frist
   that is approaching. Tiny and beside the switch rather than a chip under it
   — the old "Altid ved kritiske frister" chip was a five-word amber block in
   four cells, taller than the control it annotated. The sentence still exists,
   in the legend and in the card below the table. */
.koncern-prefs-override {
  display: inline-flex;
  color: var(--nt-warn-text);
  cursor: help;
}

/* Unused: an em rule, not an unticked box. An unticked box says "you could
   turn this on"; this channel is never used for this besked at all. */
.koncern-prefs-unused {
  display: inline-block;
  width: 0.85rem;
  height: 2px;
  border-radius: var(--nt-radius-full);
  background: var(--nt-text-disabled);
  vertical-align: middle;
}

/* Not in the plan: a padlock over a channel we DO sell.
   Deliberately not the neutral "Altid" lock beside it — that one says "this
   cannot be turned off", this one says "this is not yours yet" — and
   deliberately not amber or red either: the design system spends those on a
   frist that is approaching or overdue, and an unsold channel is neither. So
   it is the quietest voice on the page with a dashed edge, which is the one
   thing on the grid that reads as "available, elsewhere". The sentence and the
   price live in the upsell card under the table; a grid cell can only carry a
   glyph and two words. */
.koncern-prefs-unentitled {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.1rem 0.4rem;
  border: 1px dashed var(--nt-border-subtle);
  border-radius: var(--nt-radius-xs);
  font-size: var(--nt-text-xs);
  font-weight: 500;
  color: var(--nt-text-tertiary);
  white-space: nowrap;
  cursor: help;
}

.koncern-prefs-unentitled svg { color: var(--nt-text-disabled); }

/* In the legend it is a swatch, not a label: the words come from the legend
   item beside it, so the padding and the second colour would only make the row
   taller. */
.koncern-prefs-legend .koncern-prefs-unentitled {
  padding: 0.1rem 0.2rem;
  cursor: default;
}

/* — The legend — */

/* The single highest-value thing on this page. Four markers appear in the
   grid; without a key, three of them are a guess. */
.koncern-prefs-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nt-space-2) var(--nt-space-5);
  padding: var(--nt-space-3) var(--nt-space-5);
  border-bottom: 1px solid var(--nt-border-subtle);
  background: var(--nt-surface-raised);
}

.koncern-prefs-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: var(--nt-text-xs);
  color: var(--nt-text-secondary);
}

/* A non-interactive replica of the checked box, at the size it appears in the
   grid. Drawn rather than an <input> so the legend cannot be clicked, tabbed
   into, or submitted. */
.koncern-prefs-legend-box {
  flex: none;
  width: 0.95rem;
  height: 0.95rem;
  border-radius: var(--nt-radius-xs);
  background: var(--nt-seal);
  position: relative;
}

.koncern-prefs-legend-box::after {
  content: "";
  position: absolute;
  left: 0.3rem;
  top: 0.11rem;
  width: 0.22rem;
  height: 0.46rem;
  border: solid var(--nt-on-seal);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}

/* — Narrow viewports — */

/* Below ~46rem the four columns cannot coexist, and a horizontally scrolling
   settings form is a form people give up on. The table becomes one card per
   besked, each channel a labelled row — the `data-label` on every cell is what
   carries the column header down with it. */
@media (max-width: 46rem) {
  .nt-table.koncern-prefs,
  .nt-table.koncern-prefs tbody,
  .nt-table.koncern-prefs tr,
  .nt-table.koncern-prefs th,
  .nt-table.koncern-prefs td { display: block; }

  .nt-table.koncern-prefs thead { display: none; }

  .nt-table.koncern-prefs tbody tr {
    border-bottom: 1px solid var(--nt-border-subtle);
    padding: var(--nt-space-4) 0;
  }

  .nt-table.koncern-prefs tbody tr:last-child { border-bottom: 0; }

  .nt-table.koncern-prefs th.koncern-prefs-kind {
    border-bottom: 0;
    padding: 0 var(--nt-space-4) var(--nt-space-2);
    min-width: 0;
  }

  .nt-table.koncern-prefs .koncern-prefs-cell {
    width: auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--nt-space-3);
    text-align: left;
    border-left: 0;
    border-bottom: 0;
    padding: var(--nt-space-2) var(--nt-space-4);
  }

  .nt-table.koncern-prefs .koncern-prefs-cell::before {
    content: attr(data-label);
    font-size: var(--nt-text-sm);
    color: var(--nt-text-secondary);
  }

  .koncern-prefs-legend { padding: var(--nt-space-3) var(--nt-space-4); }
}

/* Nothing here animates position, only colour — but the row's hover fade and
   the switch's fill are still motion to somebody who asked for none. */
@media (prefers-reduced-motion: reduce) {
  .koncern-note,
  .koncern-filter-tab,
  .koncern-prefs-switch input[type="checkbox"] { transition: none; }
}

/* ── Live arrivals ─────────────────────────────────────────── */

/* The empty state lives INSIDE the list rather than instead of it, so a
   besked arriving over the Turbo Stream has an id to be prepended into — see
   _panel_body. Which means the panel has to decide, in CSS, which of the two
   is showing. :has() rather than a sibling rule, because the prepended row and
   the empty state are siblings in either order depending on when they arrived. */
.koncern-note-list:has(.koncern-note) .koncern-note-empty { display: none; }
