/* Regulatory Monitor — tab views, subscription editor, network map.
 *
 * Registered globally in templates/base.html (NOT via {% block head_extra %}):
 * the app shell swaps <body> under hx-boost and never re-injects <head>, so a
 * per-page stylesheet would only apply on a hard reload. Loaded after
 * responsive.css so its own media queries win.
 */

/* Surface accent. This screen is deliberately teal (it pairs with .hero--teal,
 * from app.css's per-surface hero family) rather than the app's indigo --brand.
 * Declared here because there is no global --accent token: the var(--accent, …)
 * fallbacks this file used to carry never resolved, so the colour was pinned to
 * one light-mode value and stayed dark on dark backgrounds.
 *
 * Theme is driven solely by [data-theme] app-wide — deliberately no
 * prefers-color-scheme here, or a dark OS would flip the accent on a user who
 * has explicitly chosen the light theme.
 */
:root { --reg-accent: #0f766e; }
[data-theme="dark"] { --reg-accent: #2dd4bf; }

/* NB the filter/row-action dropdown theming lives in app.css next to
   .data-table__menu — the same Bootstrap-vs-[data-theme] problem affects every
   data-table surface, not just this one, so it is fixed once in the shared
   chrome rather than patched per feature.

   The popover below IS ours, so it stays here. */
[data-theme="dark"] .popover {
  --bs-popover-bg: var(--bg-elev, #16202f);
  --bs-popover-border-color: var(--border, rgba(127, 127, 127, .25));
  --bs-popover-header-bg: var(--bg-elev-2, #1b2739);
  --bs-popover-header-color: var(--text);
  --bs-popover-body-color: var(--text);
}

/* Inline "?" that opens the provenance popover. */
.reg-help {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.05rem;
  height: 1.05rem;
  margin-left: .15rem;
  padding: 0;
  border: 1px solid currentColor;
  border-radius: 50%;
  background: transparent;
  color: inherit;
  font-size: .68rem;
  font-weight: 700;
  line-height: 1;
  opacity: .75;
  cursor: pointer;
  vertical-align: text-top;
}
.reg-help:hover { opacity: 1; }
.reg-help:focus-visible { outline: 2px solid var(--reg-accent); outline-offset: 1px; }

/* --------------------------------------------------------- loading overlay */
/* Shown while a filter change is in flight. Deliberately an overlay on the
   region being replaced, not a blocking modal: the results are what the user
   is watching, and a modal would hide them and steal focus for what is usually
   a sub-second request. The old rows stay visible but dimmed and inert, so
   nothing jumps and a double-click can't fire two requests. */
.reg-busy { position: relative; }
.reg-busy > * { transition: opacity .12s ease; }
.reg-busy.is-loading > * { opacity: .45; pointer-events: none; }

.reg-busy.is-loading::after {
  content: "";
  position: absolute;
  top: 1.75rem;
  left: 50%;
  width: 1.9rem;
  height: 1.9rem;
  margin-left: -.95rem;
  border: 2.5px solid var(--border, rgba(127, 127, 127, .3));
  border-top-color: var(--reg-accent);
  border-radius: 50%;
  animation: reg-spin .7s linear infinite;
  z-index: 4;
}
/* On the map, centre the spinner over the dark canvas instead. */
.reg-map-wrap.reg-busy.is-loading::after {
  top: 50%; margin-top: -.95rem;
  border-color: rgba(255, 255, 255, .22);
  border-top-color: #2dd4bf;
}

@keyframes reg-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .reg-busy.is-loading::after { animation-duration: 2s; }
}

/* ---------------------------------------------------------------- tab views */
.reg-view { display: none; }
.reg-view.on { display: block; }

/* ------------------------------------------------------- subscription editor */
.reg-checkgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: .25rem .5rem;
}

.reg-check {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  /* min-height keeps the row a comfortable touch target even for one-line
     labels; the checkgrid is the densest control on the page. */
  min-height: 44px;
  padding: .5rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: .9rem;
  line-height: 1.35;
}
.reg-check:hover { background: var(--bg-elev-2); }
.reg-check input { margin-top: .18rem; flex: 0 0 auto; }
.reg-check span { display: flex; flex-direction: column; gap: .1rem; }

/* Selected checkboxes get the same accent treatment as .reg-radio — with 40+
   jurisdictions the native tick alone is too small to scan a selection by. */
.reg-check:has(input:checked) {
  border-color: color-mix(in srgb, var(--reg-accent) 35%, transparent);
  background: color-mix(in srgb, var(--reg-accent) 7%, transparent);
}
.reg-check:has(input:focus-visible) {
  outline: 2px solid var(--reg-accent);
  outline-offset: 1px;
}

.reg-check__kind {
  font-style: normal;
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  opacity: .65;
}
.reg-check__kind--tax { color: #b45309; }
.reg-check__kind--compliance { color: #6d28d9; }
.reg-check__kind--regulatory { color: #0f766e; }

.reg-areagroup { border: 0; margin: 0 0 1rem; padding: 0; }
.reg-areagroup legend {
  font-size: .78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  opacity: .7;
  margin-bottom: .4rem;
  float: none;
  width: auto;
}

.reg-radioset { display: flex; flex-direction: column; gap: .5rem; }
.reg-radio {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  padding: .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.reg-radio:hover { border-color: var(--reg-accent); }
.reg-radio:has(input:focus-visible) {
  outline: 2px solid var(--reg-accent);
  outline-offset: 1px;
}
.reg-radio input { margin-top: .2rem; }
.reg-radio span { display: flex; flex-direction: column; }
.reg-radio em { font-style: normal; font-size: .8rem; opacity: .7; }
.reg-radio:has(input:checked) {
  border-color: var(--reg-accent);
  background: color-mix(in srgb, var(--reg-accent) 7%, transparent);
}

/* -------------------------------------------------------- subscription list */
.reg-sub-list { display: flex; flex-direction: column; gap: .5rem; }
.reg-sub {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.reg-sub:hover { border-color: var(--border-strong); }
.reg-sub--off { opacity: .6; }
.reg-sub__main { min-width: 0; flex: 1 1 22rem; }
.reg-sub__name {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-weight: 600;
  margin-bottom: .5rem;
}

/* Filters are grouped per axis with a leading caption, so jurisdictions read
   as distinct from areas and industries instead of one undifferentiated run
   of pills. */
.reg-sub__filters { display: flex; flex-direction: column; gap: .25rem; }
.reg-sub__axis { display: flex; align-items: baseline; flex-wrap: wrap; gap: .35rem; }
.reg-sub__axis-label {
  flex: 0 0 5.5rem;
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-subtle);
}
.reg-sub__axis-any { font-size: .8rem; color: var(--text-subtle); }

.reg-sub__meta {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}
/* Remove is destructive and sits beside informational pills — keep it quiet
   until the row is hovered or the button itself is focused. */
.reg-sub__remove { opacity: .55; transition: opacity .12s ease; }
.reg-sub:hover .reg-sub__remove,
.reg-sub__remove:focus-within { opacity: 1; }

.reg-sub-empty {
  padding: 2rem 1rem;
  text-align: center;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text-subtle);
}

/* Feed "Item" column: regulatory headlines run long. Without a width bound the
   cell just widens the table until the whole thing scrolls sideways, so cap it
   and let the text wrap inside. The other columns carry fixed widths, so this
   one absorbs the remaining space. */
.reg-col-item { max-width: 46rem; min-width: 18rem; }

/* The context line (source · jurisdiction · areas · industries). Clipped to a
   single line so a heavily-tagged item can't push the row two lines taller than
   its neighbours; the full string is on the title attribute. */
.reg-item__meta {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 44rem;
}
.reg-matched {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
  font-size: .82rem;
  color: var(--text-subtle);
}
.reg-item { white-space: normal; }
.reg-item .cell-actor__name {
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.35;
}
.reg-item .cell-actor__meta { white-space: normal; overflow-wrap: anywhere; }

@media (max-width: 991.98px) {
  .reg-col-item { max-width: 20rem; min-width: 0; }
  .reg-item__meta { max-width: 20rem; }
}

/* Unread feed rows carry a leading accent bar. */
.reg-item--unread { position: relative; padding-left: .6rem; }
.reg-item--unread::before {
  content: "";
  position: absolute;
  left: 0; top: .15rem; bottom: .15rem;
  width: 3px;
  border-radius: 2px;
  background: var(--reg-accent);
}

/* Archived article text — preserve the extractor's paragraph breaks without
   letting a long unbroken URL blow out the column. */
.reg-item-text {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  line-height: 1.65;
  max-width: 68ch;
}

/* ------------------------------------------------------------- network map */
/* The map is a display canvas: it stays dark in BOTH app themes, so these are
 * literal values rather than theme variables. */
.reg-map-wrap { position: relative; }

.reg-map__filters {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  margin-bottom: .75rem;
}
.reg-map__select { width: auto; min-width: 12rem; }

.reg-map {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 14px;
  overflow: hidden;
  background: radial-gradient(120% 90% at 50% 0%, #0d1522 0%, #070b12 100%);
}
.reg-map svg { display: block; width: 100%; height: 100%; }

.reg-map__land { fill: #16202f; stroke: #25334a; stroke-width: .5px; }
.reg-map__land.is-source { cursor: pointer; }
.reg-map__land.is-source:hover { stroke: #2dd4bf; stroke-width: 1px; }
.reg-map__land.is-home { fill: #1e3a4a; stroke: #2dd4bf; stroke-width: 1px; }

.reg-map__halo { fill: #2dd4bf; fill-opacity: .18; pointer-events: none; }
.reg-map__node { fill: #7ff3e4; pointer-events: none; }

.reg-map__arc { fill: none; stroke: #2dd4bf; stroke-opacity: .5; stroke-width: 1.1px; }
.reg-map__arc--news { stroke: #f59e0b; stroke-opacity: .45; }
.reg-map__packet { fill: #7ff3e4; }
.reg-map__packet--news { fill: #fbbf24; }

.reg-map__tip {
  position: absolute;
  pointer-events: none;
  z-index: 5;
  min-width: 150px;
  background: rgba(8, 13, 23, .95);
  border: 1px solid #25334a;
  border-radius: 8px;
  padding: .5rem .6rem;
  color: #cbd5e1;
  font-size: 12px;
  line-height: 1.4;
  opacity: 0;
  transition: opacity .12s ease;
}
.reg-map__tip.on { opacity: 1; }
.reg-map__tip b { color: #f1f5f9; }

.reg-map__legend {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: .6rem;
  font-size: .8rem;
  opacity: .8;
}
.reg-map__key { display: inline-flex; align-items: center; gap: .35rem; }
.reg-map__swatch { width: 18px; height: 3px; border-radius: 2px; display: inline-block; }
.reg-map__swatch--reg { background: #2dd4bf; }
.reg-map__swatch--news { background: #f59e0b; }

.reg-map__empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 2rem;
  color: #94a3b8;
  font-size: .9rem;
}

@media (max-width: 767.98px) {
  .reg-map { aspect-ratio: 4 / 3; }
  .reg-map__legend { font-size: .72rem; gap: .6rem; }
  .reg-checkgrid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .reg-map__packet { display: none; }
}
