/* ============================================================
   Gantry web — Rule-based lists                    #/lists/rules/:id
   Layout + motion for surfaces/web/list-rules.jsx. Tokens only.

   The builder is a STACK OF SENTENCES, not a form. Each ruleset card reads
   "Include records matching all of these rules" across its head, and each row
   reads "Where <field> <selector> <value>" across its body — so the logic is
   legible at a glance rather than inferred from nesting. Include and exclude
   are told apart by a spine colour before either word is read.
   ============================================================ */

.cg-rl-wait {
  font-family: var(--font-serif); font-size: 14px; color: var(--fg-3);
}
.cg-rl-note {
  margin: 8px 0 0; font-size: 11px; color: var(--fg-4);
}
.cg-rl-err { font-size: 11px; color: var(--bad); }
.cg-rl-needs { font-size: 11px; color: var(--fg-4); }

/* ---------- Toolbar ---------- */
.cg-rl-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.cg-rl-toolbar-left,
.cg-rl-toolbar-right {
  display: flex; align-items: center; gap: 12px; min-width: 0;
}
.cg-rl-count { font-size: 12px; color: var(--fg-3); }
/* Unsaved is stated, never implied by a colour alone: the count on screen is
   an answer to rules that are not the stored ones, and a reader who misses
   that reports the saved list as wrong. */
.cg-rl-count-draft { color: var(--warn); }

/* ---------- The builder ---------- */
.cg-rl-builder { display: flex; flex-direction: column; gap: 12px; }
.cg-rl-blank {
  margin: 0; padding: 18px 16px;
  border: 1px dashed var(--line); border-radius: var(--r-md);
  font-family: var(--font-serif); font-size: 14px; color: var(--fg-3);
}
.cg-rl-addsets {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}

/* ---------- One ruleset ---------- */
.cg-rl-set {
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--bg-1);
  /* The spine. Include is the brand; exclude is the warning hue — the same
     meaning it carries everywhere else on the product, so nothing new has to
     be learned to read this card. */
  border-left: 3px solid var(--brand);
  animation: cg-rl-in .22s var(--ease) both;
  animation-delay: calc(var(--i, 0) * 28ms);
}
.cg-rl-set[data-mode="exclude"] { border-left-color: var(--warn); }

@keyframes cg-rl-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cg-rl-set { animation: none; }
  .cg-rl-result-row { animation: none; }
}

.cg-rl-set-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px; border-bottom: 1px solid var(--line);
}
.cg-rl-set-words { font-size: 12px; color: var(--fg-3); }
.cg-rl-set-spacer { flex: 1 1 auto; }

/* ---------- Rows ---------- */
.cg-rl-rows { list-style: none; margin: 0; padding: 10px 12px; }
.cg-rl-row {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 0;
  border-radius: var(--r-sm);
  transition: background .14s var(--ease), opacity .14s var(--ease);
}
/* Where the row would land, drawn on the row it would displace. A drop
   indicator that only moves the dragged element gives no clue where it lands
   once the pointer is over a long list. */
.cg-rl-row[data-over="true"] { box-shadow: inset 0 2px 0 0 var(--brand); }
.cg-rl-row[data-dragging="true"] { opacity: .45; }
.cg-rl-row:hover { background: var(--bg-hover); }

/* The joiner column is FIXED WIDTH so every row's field select starts on the
   same x — "Where", "and" and the and/or control are three different widths,
   and a ragged left edge makes the rules unreadable as a list. */
.cg-rl-joiner {
  flex: 0 0 76px; display: flex; align-items: center;
  font-size: 11px; color: var(--fg-4);
}
.cg-rl-joiner-first,
.cg-rl-joiner-echo { padding-left: 2px; }
.cg-rl-joiner-sel { width: 72px; }

.cg-rl-sel { padding: 7px 8px; font-size: 12px; }
.cg-rl-field { flex: 1 1 180px; min-width: 120px; }
.cg-rl-op { flex: 0 1 150px; min-width: 110px; }
.cg-rl-value { flex: 1 1 200px; min-width: 120px; display: block; }
.cg-rl-value .cg-input,
.cg-rl-value select { width: 100%; padding: 7px 8px; font-size: 12px; }
/* The DS MultiSelect is inline-block and sizes to its summary text, so an
   "is one of" row is the one that would not line up with the column above
   it. Widening the wrapper AND the trigger, because the trigger is the part
   with the border. */
.cg-rl-value .cg-mselect { display: block; width: 100%; }
.cg-rl-value .cg-mselect-trigger { width: 100%; justify-content: space-between; }
/* The panel is wider than the column it hangs off, so a long classification
   ("Clinical Nurse Specialist") is readable while the row stays compact. */
.cg-rl-value .cg-mselect-panel { min-width: max(100%, 280px); }
.cg-rl-value-none { color: var(--fg-4); }
.cg-rl-mode { width: 108px; }
.cg-rl-join { width: 78px; }

.cg-rl-addrule {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 0 12px 10px;
}

/* ---------- Grip and delete ----------
   Both sit in reserved space so the row does not reflow when they appear, and
   both stay visible on a touch pointer, which has no hover to reveal them
   with. They remain tabbable at opacity 0 — the keyboard path to reordering
   is Alt+Arrow on the grip, and hiding it from the tab order would remove the
   only non-pointer way to reorder a rule. */
.cg-rl-grip,
.cg-rl-x {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0;
  background: none; border: 0; border-radius: var(--r-sm);
  color: var(--fg-4); cursor: pointer;
  opacity: .45;
  transition: opacity .14s var(--ease), background .14s var(--ease),
              color .14s var(--ease);
}
.cg-rl-grip { cursor: grab; }
.cg-rl-grip:active { cursor: grabbing; }
.cg-rl-row:hover .cg-rl-grip,
.cg-rl-row:hover .cg-rl-x,
.cg-rl-grip:focus-visible,
.cg-rl-x:focus-visible { opacity: 1; }
.cg-rl-grip:hover { background: var(--bg-hover); color: var(--fg-2); }
.cg-rl-x:hover { background: var(--bg-hover); color: var(--bad); }
.cg-rl-x-set { opacity: .55; }
.cg-rl-x-set:hover { opacity: 1; }
.cg-rl-grip:focus-visible,
.cg-rl-x:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.cg-rl-grip:disabled,
.cg-rl-x:disabled { cursor: default; opacity: .2; }

@media (hover: none) {
  .cg-rl-grip, .cg-rl-x { opacity: 1; }
}

/* ---------- Results ---------- */
.cg-rl-results { display: flex; flex-direction: column; gap: 10px; }
.cg-rl-results-head {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}

.cg-rl-table-card { padding: 4px 0; }
.cg-rl-result-rows { list-style: none; margin: 0; padding: 0; }
.cg-rl-result-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px; border-bottom: 1px solid var(--line);
  animation: cg-rl-in .2s var(--ease) both;
  animation-delay: calc(var(--i, 0) * 10ms);
}
.cg-rl-result-row:last-child { border-bottom: 0; }
.cg-rl-result-row:hover { background: var(--bg-hover); }
.cg-rl-result-mark { flex: none; color: var(--fg-4); display: inline-flex; }
.cg-rl-result-main {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
  background: none; border: 0; padding: 0; text-align: left; cursor: pointer;
}
.cg-rl-result-name {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 13px; color: var(--fg);
}
.cg-rl-result-main:hover .cg-rl-result-name { color: var(--brand-text); }
.cg-rl-result-sub { font-size: 11px; color: var(--fg-4); }

.cg-rl-map-card { padding: 0; overflow: hidden; }
.cg-rl-map { height: 440px; width: 100%; }
.cg-rl-map-card .cg-rl-note { padding: 8px 14px 10px; margin: 0; }

/* ---------- Overlays ---------- */
.cg-rl-overlay-head { display: flex; flex-direction: column; gap: 4px; }
.cg-rl-overlay-title {
  font-family: var(--font-serif); font-size: 18px; color: var(--fg);
}
.cg-rl-overlay-copy {
  margin: 12px 0 0; font-size: 12px; line-height: 1.55; color: var(--fg-2);
}
.cg-rl-overlay-warn { margin: 8px 0 0; font-size: 11px; color: var(--warn); }
.cg-rl-overlay-spacer { flex: 1 1 auto; }
.cg-rl-overlay-err {
  margin-top: 12px; padding: 10px 12px;
  border: 1px solid var(--bad); border-radius: var(--r-sm);
}
.cg-rl-overlay-err-t { font-size: 12px; color: var(--bad); }
.cg-rl-overlay-err-d { margin-top: 4px; font-size: 11px; color: var(--fg-3); }

/* The what-is-this-about choice. Asked once, at creation, because the field
   catalogue differs per type — so the two options are given room rather than
   hidden in a dropdown. */
.cg-rl-overlay-choice {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px;
}
.cg-rl-choice {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 10px 12px;
  background: none; border: 1px solid var(--line); border-radius: var(--r-sm);
  color: var(--fg-3); cursor: pointer; text-align: left;
  transition: border-color .14s var(--ease), color .14s var(--ease),
              background .14s var(--ease);
}
.cg-rl-choice:hover { background: var(--bg-hover); }
.cg-rl-choice[data-active="true"] {
  border-color: var(--brand); color: var(--fg);
}
.cg-rl-choice-l { font-size: 13px; }
.cg-rl-choice-h { font-size: 10px; color: var(--fg-4); }
.cg-rl-choice:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

/* ---------- Narrow ----------
   Below ~720px the sentence cannot stay on one line, so the row becomes a
   stack and the joiner column collapses to a label above it. The grip is kept:
   reordering is the one gesture this layout change must not remove. */
@media (max-width: 720px) {
  .cg-rl-row { flex-wrap: wrap; }
  .cg-rl-joiner { flex-basis: 100%; }
  .cg-rl-field, .cg-rl-op, .cg-rl-value { flex-basis: 100%; }
  .cg-rl-overlay-choice { grid-template-columns: 1fr; }
}
