/* Copyright (C) 2026 Raymond Sun - All Rights Reserved */

/* Tokens are scoped rather than put on :root so the compare surface can carry its own palette
   without leaking into the rest of the tracker page. The notice and the export box are siblings
   of .compare-root, not children, and both are handed the same card and pill markup, so they
   have to be named here too. Scoped to .compare-root alone, every var() in a notice card falls
   back to nothing and the card draws as bare text with borderless buttons. The frame wraps all
   three and paints its own background once expanded, which is the same failure one level up:
   outside this list that background resolves to nothing and the page shows through the layer. */
.compare-frame,
.compare-root,
.compare-notice,
.compare-export {
  --cmp-surface: #ffffff;
  --cmp-raised: #f7f7f9;
  --cmp-raised-hover: #f0f0f4;
  --cmp-hairline: #e4e4e9;
  --cmp-hairline-soft: #f0f0f3;
  --cmp-text: #1c1c1e;
  --cmp-text-dim: #6b6b70;
  --cmp-text-faint: #9a9aa0;
  --cmp-accent: #0a84ff;
  --cmp-accent-soft: #eaf4ff;
  --cmp-ai: #7b3fe4;
  --cmp-ai-soft: #f6f1ff;
  --cmp-warn: #b3261e;
  --cmp-warn-soft: #fdf0ee;
  /* The caution family is separate from --cmp-warn, which is the red a refused question is
     written in inside a cell. A card above the table is a state of the surface, not a mistake
     the reader made, so it is tinted rather than told off. */
  --cmp-caution: #8a6100;
  --cmp-caution-soft: #fff8e2;
  --cmp-caution-line: #efd48a;
  --cmp-radius: 14px;
  --cmp-radius-sm: 10px;
  --cmp-radius-pill: 999px;
  --cmp-shadow-pop: 0 10px 34px rgba(0, 0, 0, 0.13), 0 1px 3px rgba(0, 0, 0, 0.08);
  --cmp-ease: cubic-bezier(0.32, 0.72, 0, 1);

  color: var(--cmp-text);
  font-size: 14px;
}

.compare-root { margin-top: 12px; }

/* The intro sits above .compare-root, so it cannot read the tokens scoped to it. */
.compare-intro {
  background: #f7f7f9;
  border: 1px solid #e4e4e9;
  border-radius: 10px;
  padding: 12px 16px;
  margin-bottom: 14px;
  color: #1c1c1e;
}

/* The margin moves here off the title so the pill sits on the title's own baseline row
   rather than being centred against the gap below it. */
.compare-intro-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
}

.compare-intro-title {
  font-size: 13px;
  font-weight: 650;
  letter-spacing: -0.01em;
}

/* Literal colours, not the --cmp tokens: those are scoped to .compare-root and the intro
   block is a sibling of it, so a var() here would resolve to nothing.
   Deliberately not the AI purple, which means "written by AI" everywhere else on this
   surface. A label about the feature must not read as a label about the data. */
.compare-beta {
  flex: none;
  padding: 1px 8px;
  border: 1px solid #d8d8de;
  border-radius: 999px;
  background: #ffffff;
  color: #6b6b70;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}

.compare-intro-steps {
  margin: 0;
  padding-left: 18px;
  font-size: 13px;
  line-height: 1.55;
  color: #6b6b70;
}

.compare-intro-steps li + li { margin-top: 3px; }

.compare-notice:empty { display: none; }
.compare-notice { margin-bottom: 12px; }

/* The persistent home of the add-column search input. The input is moved into the rail cell
   on demand and moved back here afterwards, so the SearchBar instance bound to it survives
   every table re-render. Destroying and recreating the node would drop that wiring. */
.compare-add-host { display: none; }

/*
  ---- the table surface ----
  A rounded, clipped card. The scroll container is the card itself so the sticky row header
  column has something to stick to.
*/
.compare-surface {
  border: 1px solid var(--cmp-hairline);
  border-radius: var(--cmp-radius);
  background: var(--cmp-surface);
  overflow: auto;
  max-height: 72vh;
}

/* The colgroup owns every column width and the table takes its width from their sum, so the
   surface scrolls sideways once the user drags past the card. `max-content` rather than
   `auto`: a table set to `auto` is capped at its container and scales the columns down to
   fit, which silently undoes a drag. Filling the card is the rail column's job. */
.compare-table {
  border-collapse: separate;
  border-spacing: 0;
  width: max-content;
  font-size: 14px;
  table-layout: fixed;
}

.compare-table th,
.compare-table td {
  border-bottom: 1px solid var(--cmp-hairline-soft);
  border-right: 1px solid var(--cmp-hairline-soft);
}

.compare-table tr:last-child > th,
.compare-table tr:last-child > td { border-bottom: none; }

/* ---- header row ---- */

.compare-corner,
.compare-col-header {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--cmp-raised);
  border-bottom: 1px solid var(--cmp-hairline);
  text-align: left;
  vertical-align: top;
  padding: 12px 14px;
}

.compare-corner {
  left: 0;
  z-index: 5;
  padding: 12px 14px;
  overflow: visible;
}

.compare-corner-label {
  font-weight: 650;
  font-size: 13px;
  color: var(--cmp-text-dim);
  letter-spacing: 0.02em;
}

.compare-col-header { position: sticky; }

/* ---- column resize ---- */

/* The grip straddles the border so the target is wide enough to hit without the border
   itself having to be thick. It stays invisible until the header is hovered, then reads as
   a thicker version of the hairline it sits on. */
.compare-col-grip {
  position: absolute;
  top: 0;
  right: -4px;
  width: 9px;
  height: 100%;
  cursor: col-resize;
  z-index: 6;
  touch-action: none;
}

.compare-col-grip::after {
  content: "";
  position: absolute;
  top: 6px;
  bottom: 6px;
  left: 3px;
  width: 3px;
  border-radius: 2px;
  background: var(--cmp-accent);
  opacity: 0;
  transition: opacity 120ms var(--cmp-ease);
}

.compare-corner:hover .compare-col-grip::after,
.compare-col-header:hover .compare-col-grip::after,
.compare-col-grip:hover::after { opacity: 0.55; }

/* A body cell is in normal flow, so the grip inside it has nothing to hang off until the cell
   is a containing block. Without this the grip anchors to the table and every one of them
   lands on the same edge. */
.compare-attr-cell,
.compare-row-label,
.compare-addrow-cell {
  position: relative;
}

/* Below the header, not over it. The header row is sticky, so as the table scrolls under it the
   grips of the rows passing behind would otherwise draw blue strips across the column names. */
.compare-attr-cell .compare-col-grip,
.compare-row-label .compare-col-grip,
.compare-addrow-cell .compare-col-grip {
  z-index: 1;
}


.compare-resizing { cursor: col-resize; }
.compare-resizing .compare-col-grip::after { opacity: 1; }
/* A drag that leaves the grip must not start selecting the cells it passes over. */
.compare-resizing .compare-table { user-select: none; }

.compare-col-name {
  font-weight: 650;
  font-size: 15px;
  letter-spacing: -0.01em;
  padding-right: 22px;
}

/* The column menu and the legacy remove control share a resting state: invisible until the
   column is hovered, so the header reads as data rather than as a toolbar. */
.compare-col-menu,
.compare-remove-col {
  position: absolute;
  top: 10px;
  right: 8px;
  border: none;
  background: transparent;
  color: var(--cmp-text-faint);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 3px 5px;
  border-radius: 6px;
  opacity: 0;
  transition: opacity 120ms var(--cmp-ease), background 120ms var(--cmp-ease);
}

.compare-col-header:hover .compare-col-menu,
.compare-col-header:hover .compare-remove-col,
.compare-col-menu:focus-visible { opacity: 1; }

.compare-col-menu:hover,
.compare-remove-col:hover { background: var(--cmp-raised-hover); color: var(--cmp-text); }

/* ---- body ---- */

.compare-row-label {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--cmp-surface);
  text-align: left;
  vertical-align: top;
  padding: 4px 6px 4px 8px;
  font-weight: 600;
  color: var(--cmp-text);
  border-right: 1px solid var(--cmp-hairline);
  overflow: visible;
}

.compare-attr-cell {
  vertical-align: top;
  padding: 12px 14px;
  transition: background 100ms linear;
}

/* The hovered row tints its own header and lifts its cells, so the eye can track one
   attribute across jurisdictions without losing the line. */
.compare-row:hover .compare-row-label { background: var(--cmp-accent-soft); }
.compare-row:hover .compare-attr-cell { background: #fbfbfd; }
.compare-attr-cell:hover { background: var(--cmp-accent-soft) !important; }

/* ---- editable row header ---- */

.compare-row-head {
  display: flex;
  align-items: flex-start;
  gap: 4px;
}

.compare-row-text {
  flex: 1;
  min-width: 0;
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.35;
  border: 1px solid transparent;
  background: transparent;
  border-radius: 8px;
  padding: 8px 8px;
  font: inherit;
  font-weight: 600;
  color: inherit;
  text-align: left;
  cursor: text;
  transition: background 120ms var(--cmp-ease), border-color 120ms var(--cmp-ease);
}

.compare-row-text:hover { background: var(--cmp-raised); border-color: var(--cmp-hairline); }

.compare-row-custom { color: var(--cmp-ai); }

.compare-row-menu {
  border: none;
  background: transparent;
  color: var(--cmp-text-faint);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 8px 4px;
  border-radius: 6px;
  opacity: 0;
  transition: opacity 120ms var(--cmp-ease);
}

.compare-row:hover .compare-row-menu,
.compare-row-menu:focus-visible { opacity: 1; }

.compare-row-menu:hover { background: var(--cmp-raised-hover); color: var(--cmp-text); }

.compare-row-editor { position: relative; }

/* A textarea rather than a text input, so the field grows down the row header as the question
   is typed instead of scrolling its own start out of view. Enter still confirms. The right
   padding is the close control's seat, so a long question never runs underneath it. */
.compare-row-input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--cmp-accent);
  border-radius: 8px;
  padding: 8px 28px 8px 9px;
  font: inherit;
  font-weight: 600;
  line-height: 1.35;
  color: var(--cmp-text);
  background: var(--cmp-surface);
  outline: none;
  box-shadow: 0 0 0 3px rgba(10, 132, 255, 0.16);
  resize: none;
  overflow: hidden;
  overflow-wrap: anywhere;
}

/* Everything under the field lives in one wrapper so a keystroke can replace the lot in a
   single splice. Without it the repaint replaces the first line and leaves the second behind. */
.compare-row-hints {
  display: block;
}

/* How to commit, stated where the typing is. Weight is reset because the row header is bold
   and a hint in the header's weight would read as part of the question. */
.compare-row-hint {
  margin: 5px 2px 0;
  font-size: 11px;
  font-weight: 400;
  line-height: 1.35;
  color: var(--cmp-text-faint);
}

.compare-row-hint-issue {
  color: var(--cmp-warn);
  font-weight: 500;
}

/* Carries the AI accent because the cost it names is an AI cost, which is also the one thing
   in this editor that spends something the reader cannot get back until tomorrow. */
.compare-row-cost {
  margin: 3px 2px 0;
  font-size: 11px;
  font-weight: 500;
  line-height: 1.35;
  color: var(--cmp-ai);
}

/* The node is rendered even when the balance is still in flight, so it has somewhere to land.
   Empty, it must take up no room at all. */
.compare-row-cost:empty {
  display: none;
}

/* ---- popovers ---- */

@keyframes compare-pop-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.compare-pop-label {
  padding: 6px 10px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--cmp-text-faint);
}

/* Every panel that opens over the grid seats its close control in the same corner. */
.compare-pop-close {
  position: absolute;
  top: 5px;
  right: 5px;
  z-index: 2;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  padding: 0;
  background: transparent;
  color: var(--cmp-text-faint);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  transition: background 120ms var(--cmp-ease), color 120ms var(--cmp-ease);
}

.compare-pop-close:hover { background: var(--cmp-raised-hover); color: var(--cmp-text); }

/* ---- the add rails ---- */

/* The rail column is always present, so revealing the control never reflows the grid. Its
   width comes from the colgroup: a width declared here would be read as the column's width
   under fixed layout and would stop the rail absorbing the leftover space. */
.compare-rail-head,
.compare-rail-cell {
  padding: 0;
  border-right: none;
  background: var(--cmp-surface);
}

/* Sticky rather than relative. Sticky already anchors the absolutely positioned panel below
   it, and a later position:relative would win and drop the rail out of the frozen header. */
.compare-rail-head {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--cmp-raised);
  border-bottom: 1px solid var(--cmp-hairline);
  vertical-align: middle;
  overflow: visible;
}

.compare-rail-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  margin: 0 auto;
  border: 1px solid var(--cmp-hairline);
  border-radius: 50%;
  background: var(--cmp-surface);
  color: var(--cmp-accent);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  /* Faint at rest rather than absent. A control nobody can see until they happen to sweep the
     right edge is a control nobody finds, and adding a jurisdiction is the first thing this
     table asks for. Hover still brings it to full strength. */
  opacity: 0.5;
  transform: scale(0.88);
  transition: opacity 140ms var(--cmp-ease), transform 140ms var(--cmp-ease), background 140ms var(--cmp-ease);
}

.compare-rail-head:hover .compare-rail-btn,
.compare-table:hover .compare-rail-btn,
.compare-rail-btn:focus-visible {
  opacity: 1;
  transform: scale(1);
}

.compare-rail-btn:hover { background: var(--cmp-accent); color: #fff; border-color: var(--cmp-accent); }

.compare-rail-open {
  position: absolute;
  top: calc(100% + 6px);
  right: 4px;
  width: 262px;
  z-index: 40;
  background: var(--cmp-surface);
  border: 1px solid var(--cmp-hairline);
  border-radius: var(--cmp-radius-sm);
  box-shadow: var(--cmp-shadow-pop);
  padding: 8px;
  animation: compare-pop-in 160ms var(--cmp-ease);
}

.compare-rail-open .compare-plan-card { border: none; padding: 8px; box-shadow: none; }

/* The add-row rail mirrors the add-column rail along the bottom edge. */
.compare-addrow-cell {
  padding: 0;
  background: var(--cmp-surface);
  border-right: 1px solid var(--cmp-hairline);
}

.compare-addrow-btn {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  border: none;
  background: transparent;
  border-radius: 8px;
  padding: 9px 12px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--cmp-text-faint);
  cursor: pointer;
  text-align: left;
  transition: color 120ms var(--cmp-ease), background 120ms var(--cmp-ease);
}

.compare-table:hover .compare-addrow-btn { color: var(--cmp-accent); }
.compare-addrow-btn:hover { background: var(--cmp-accent-soft); }

.compare-addrow-fill { background: var(--cmp-surface); }

/* ---- cells ---- */

.compare-cell { display: block; }
.compare-cell-gap { color: var(--cmp-text-dim); }
.compare-gap-copy { margin: 0 0 8px; font-style: italic; font-size: 13px; }

.compare-pill-row { display: flex; gap: 6px; flex-wrap: wrap; }

/* Worn by a button everywhere except the account link on the column gate. The card's action
   row is flex, so that anchor is blockified and the padding holds, but the underline a browser
   puts on a link is the one default that would still show through. */
.compare-pill {
  border: 1px solid var(--cmp-hairline);
  background: var(--cmp-surface);
  color: var(--cmp-text);
  border-radius: var(--cmp-radius-pill);
  padding: 4px 11px;
  font: inherit;
  font-size: 12px;
  text-decoration: none;
  cursor: pointer;
  transition: background 120ms var(--cmp-ease), border-color 120ms var(--cmp-ease);
}

.compare-pill:hover { background: var(--cmp-raised-hover); }

.compare-pill-ai { border-color: var(--cmp-ai); color: var(--cmp-ai); }
.compare-pill-ai:hover { background: var(--cmp-ai-soft); }

.compare-sources { margin: 0 0 6px; font-size: 13px; }
.compare-sources a { color: #1a56c4; text-decoration: none; }
.compare-sources a:hover { text-decoration: underline; }

/* Titles woven into the prose read as links, so they carry the same blue as the source lines,
   underlined here because in a run of text colour alone is easy to miss. */
.compare-comment a { color: #1a56c4; text-decoration: underline; }

/* The heading over the sources a title never named in the prose. Small and dim, so the list
   beneath it reads as a footnote to the answer rather than as a second answer. */
.compare-sources-head {
  margin: 10px 0 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--cmp-text-dim);
}

/* A cell reads as editable, so the prose takes a text cursor before the reader clicks into it. */
.compare-cell-body[data-editable] { cursor: text; }

/* The cell wrapper while its prose is open for editing. The pills and clamp fade out for the
   duration, so the field is the only thing in the cell and the reader is not editing prose with
   an expand control still hanging off it. */
.compare-cell-editing { width: 100%; }

/* A cell whose prose is being edited. The body becomes a plain text field, bordered so the edit
   surface is visible, with the derived links gone until the edit is committed and relinked. */
.compare-comment-edit {
  margin: 0;
  line-height: 1.45;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--cmp-ai);
  background: var(--cmp-surface);
  outline: none;
  min-height: 40px;
}

.compare-comment { margin: 0; line-height: 1.45; overflow-wrap: anywhere; }
.compare-cell-sourced .compare-comment { color: var(--cmp-text); }

/* A profile cell quotes the jurisdiction's own Regulation Status, which runs to several
   paragraphs. It keeps the breaks the author wrote and reads at a slightly smaller size, so a
   long quote does not drown the shorter cells beside it. */
.compare-cell-profile .compare-comment {
  color: var(--cmp-text);
  font-size: 13px;
}

.compare-cell-profile .compare-comment + .compare-comment { margin-top: 9px; }
.compare-cell-profile .compare-pill-row { margin-top: 11px; }

/* A scope caveat the profile author wrote about their own card. Set in a tinted rule so it reads
   as an aside about the source rather than as a finding about the jurisdiction. */
.compare-cell-profile .compare-comment-note {
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--cmp-raised);
  border-left: 3px solid var(--cmp-hairline);
  color: var(--cmp-text-dim);
  font-size: 12px;
}

/* A clamped quote is cut at a whole number of lines and faded out, so the cut reads as more
   text rather than as the end of the sentence. The height is a line multiple of the 13px
   text at 1.45, which is what keeps the fade landing on a line rather than through one. */
.compare-cell-clamped .compare-cell-body {
  max-height: 245px;
  overflow: hidden;
  position: relative;
}

.compare-cell-clamped .compare-cell-body::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 48px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), var(--cmp-surface));
  pointer-events: none;
}

/* The dated fence line below the answer is what marks it as AI assessed, so the cell itself is
   set like any other. A tint and a coloured rule made the answer read as a panel stuck onto the
   table rather than one of its cells, beside a Regulatory approach cell that quotes the
   jurisdiction's own record and is set plain. The size matches that neighbour for the same reason. */
.compare-cell-ai .compare-comment {
  color: var(--cmp-text);
  font-size: 13px;
}

.compare-ai-fence {
  margin: 7px 0 0;
  font-size: 11px;
  font-weight: 600;
  color: var(--cmp-ai);
}

/* The web disclosure sits at the top of a fallback cell, above the sources, so the reader meets
   it before the answer. Tinted in the AI colour on the AI soft ground so it reads as part of the
   assessment rather than as an alert, and set apart with a coloured rule for the same reason the
   profile caveat above it is. */
.compare-cell-ai .compare-web-note {
  margin: 0 0 9px;
  padding: 7px 10px;
  border-radius: 8px;
  background: var(--cmp-ai-soft);
  border-left: 3px solid var(--cmp-ai);
  color: var(--cmp-ai);
  font-size: 12px;
  font-weight: 600;
}

/* ---- pending cells ---- */

.compare-skeleton { display: block; }

/* Block, because these are spans. An inline box drops height, width and margin, which left the
   shimmer present in the DOM and invisible on screen. */
.compare-skeleton-line {
  display: block;
  height: 9px;
  border-radius: 5px;
  margin-bottom: 7px;
  background: linear-gradient(90deg, #ececf0 25%, #f7f7f9 37%, #ececf0 63%);
  background-size: 400% 100%;
  animation: compare-shimmer 1.5s ease infinite;
}

.compare-skeleton-line:nth-child(2) { width: 82%; animation-delay: 90ms; }
.compare-skeleton-line:nth-child(3) { width: 54%; margin-bottom: 0; animation-delay: 180ms; }

@keyframes compare-shimmer {
  from { background-position: 100% 50%; }
  to   { background-position: 0 50%; }
}

/* Cells that were asked and came back with something other than an answer. A check that ran
   is not a fault, so these read quietly rather than in the alert colours. Both carry a row of
   buttons underneath, so the gap to them is stated here and matches the gap cell above. */
.compare-cell-skipped,
.compare-cell-note {
  margin: 0 0 8px;
  color: var(--cmp-text-faint);
  font-size: 13px;
  font-style: italic;
}

/* A row still being written has no question, so its cells hold their height and say nothing.
   height, not min-height: on a table cell the former is read as a minimum, the latter is not
   defined at all. */
.compare-cell-draft { height: 40px; }

.compare-cell-error {
  color: var(--cmp-warn);
  background: var(--cmp-warn-soft);
  border-radius: 7px;
  padding: 7px 9px;
  font-size: 13px;
  line-height: 1.4;
}

.compare-cell-retry {
  margin-top: 6px;
  border: none;
  background: transparent;
  padding: 0;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--cmp-accent);
  cursor: pointer;
}

.compare-cell-retry:hover { text-decoration: underline; }

.compare-row-progress {
  display: block;
  font-size: 11px;
  font-weight: 600;
  color: var(--cmp-accent);
  padding: 0 8px 6px;
}

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

/* The empty state is the whole table until a column exists, so it carries the control that
   fills it rather than a line of prose pointing at a rail that has not been drawn yet. */
.compare-empty {
  position: relative;
  padding: 34px 28px 38px;
  text-align: center;
  color: var(--cmp-text-dim);
  border: 1px dashed var(--cmp-hairline);
  border-radius: var(--cmp-radius);
  background: var(--cmp-raised);
}

.compare-empty-line {
  margin: 0 0 14px;
  font-size: 13px;
}

.compare-empty-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 16px;
  border: 1px solid var(--cmp-accent);
  border-radius: 999px;
  background: var(--cmp-surface);
  color: var(--cmp-accent);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 140ms var(--cmp-ease), color 140ms var(--cmp-ease);
}

.compare-empty-btn span { font-size: 15px; line-height: 1; }
.compare-empty-btn:hover { background: var(--cmp-accent); color: #fff; }

/* Seated under the button rather than over it, so the search results never cover the control
   that opened them. */
.compare-empty-open {
  position: relative;
  width: 262px;
  margin: 12px auto 0;
  text-align: left;
  background: var(--cmp-surface);
  border: 1px solid var(--cmp-hairline);
  border-radius: var(--cmp-radius-sm);
  box-shadow: var(--cmp-shadow-pop);
  padding: 8px;
  animation: compare-pop-in 160ms var(--cmp-ease);
}

.compare-plan-card {
  border: 1px solid var(--cmp-hairline);
  border-radius: var(--cmp-radius);
  padding: 16px 18px;
  background: var(--cmp-surface);
  max-width: 460px;
}

/* Cards that report a refusal or a failure. They are read above the table, away from the cell
   or the control that caused them, so an untinted card is easy to walk straight past. Only
   these are tinted: colouring the loading and answer drawers too would spend the signal. */
.compare-plan-card-warn {
  background: var(--cmp-caution-soft);
  border-color: var(--cmp-caution-line);
}

.compare-plan-card-warn .compare-plan-card-title { color: var(--cmp-caution); }
.compare-plan-card-warn .compare-plan-card-body { color: #6d5412; }

/* The pill inherits .compare-surface white, which on the tint reads as a hole rather than as a
   button. It takes the card's own edge instead. */
.compare-plan-card-warn .compare-pill {
  border-color: var(--cmp-caution-line);
  background: rgba(255, 255, 255, 0.72);
}

.compare-plan-card-warn .compare-pill:hover { background: #ffffff; }

.compare-plan-card-title { margin: 0 0 8px; font-weight: 700; }
.compare-plan-card-body { margin: 0 0 12px; color: var(--cmp-text-dim); font-size: 13px; }
.compare-plan-card-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---- toolbar and export report ---- */

/* By class, like .compare-notice above. The id selector this replaced left the class on the
   page matching no rule at all, which is the one thing the coverage guard exists to catch. */
.compare-export:empty { display: none; }

/* Sits on the table rather than beside it: no bottom border of its own, so its lower edge and
   the surface's top border are one hairline and the two read as a single card. */
.compare-toolbar {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border: 1px solid var(--cmp-hairline);
  border-bottom: 0;
  border-radius: var(--cmp-radius) var(--cmp-radius) 0 0;
  background: var(--cmp-raised);
}

.compare-toolbar + .compare-surface {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

.compare-tool {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
}

/* Square, so the glyph sits in the middle of the pill rather than on the left of a box sized
   for the words the other two carry. */
.compare-tool-icon {
  gap: 0;
  padding: 4px;
  width: 28px;
  justify-content: center;
}

/* Reads as a change of kind rather than a gap: export leaves with a file, expand does not. */
.compare-tool-split {
  width: 1px;
  align-self: stretch;
  margin: 0 2px;
  background: var(--cmp-hairline);
}

.compare-icon {
  width: 14px;
  height: 14px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* What came of the last export, drawn under the table rather than in the box above it. The
   surface states no margin below itself, so without this the card touches the table. */
.compare-export .compare-plan-card { margin-top: 10px; }

/*
  ---- the expanded frame ----
  A layer over the page rather than a call to requestFullscreen(): that API is refused inside
  an embed and does nothing for a non-video element on iOS Safari, and it hands the styling of
  the backdrop to the browser. #header on this site is fixed at z-index 9997 and the mobile nav
  toggle at 9998, so a layer meant to cover the page has to clear both.
*/
.compare-frame.is-expanded {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 14px;
  background: var(--cmp-raised);
  overflow: auto;
  overscroll-behavior: contain;
}

/* The surface takes what the toolbar and the cards around it leave, and scrolls inside that,
   so the sticky header row and the sticky row label column still have a viewport to stick to.
   min-height: 0 because a flex child will not shrink below its content without it, which is
   what would push the export report off the bottom of the screen. */
.compare-frame.is-expanded .compare-root {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin-top: 0;
}

.compare-frame.is-expanded .compare-surface {
  flex: 1;
  min-height: 0;
  max-height: none;
}

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

@media (max-width: 640px) {
  .compare-surface { max-height: none; }
  .compare-attr-cell { padding: 10px 11px; }
  /* Touch has no hover, so the structure controls rest visible rather than never appearing. */
  .compare-rail-btn { opacity: 1; transform: scale(1); }
  .compare-col-menu, .compare-remove-col, .compare-row-menu { opacity: 1; }
  /* A drag grip is a mouse gesture. On touch it is only a strip that eats taps near the
     border, so it is taken out of the layout entirely. */
  .compare-col-grip { display: none; }
  /* The point of expanding on a phone is the screen the page chrome was using. Spending a
     quarter of the width back on a margin gives it away again. */
  .compare-frame.is-expanded { padding: 8px; }
}

/*
  ---- past reviews rail ----
  A right hand drawer over a backdrop, the same shape the AI search gives its past chats. Closed,
  compareHistory.js empties the node, so none of this paints. Fixed and above the expanded frame's
  z-index (10000) so it covers the table whether the table is inline or filling the screen.
*/
.compare-history:empty { display: none; }

.compare-history-backdrop {
  position: fixed;
  inset: 0;
  z-index: 10001;
  background: rgba(0, 0, 0, 0.32);
}

.compare-history-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 10002;
  width: min(360px, 90vw);
  display: flex;
  flex-direction: column;
  background: var(--cmp-surface);
  border-left: 1px solid var(--cmp-hairline);
  box-shadow: -12px 0 34px rgba(0, 0, 0, 0.18);
  color: var(--cmp-text);
}

.compare-history-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--cmp-hairline);
}

.compare-history-title { font-size: 15px; font-weight: 600; }

.compare-history-close { flex: none; }

.compare-history-list {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.compare-history-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 10px 12px;
  border: 1px solid transparent;
  border-radius: var(--cmp-radius-sm);
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: background 120ms var(--cmp-ease), border-color 120ms var(--cmp-ease);
}

.compare-history-item:hover { background: var(--cmp-raised-hover); }

.compare-history-item.is-active {
  border-color: var(--cmp-accent);
  background: var(--cmp-accent-soft);
}

.compare-history-item-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
}

.compare-history-item-date {
  flex: none;
  font-size: 11px;
  color: var(--cmp-text-faint);
}

.compare-history-empty {
  padding: 18px 14px;
  color: var(--cmp-text-dim);
  font-size: 13px;
  line-height: 1.5;
}

/* Naming each animated selector meant the list fell behind the stylesheet every time one was
   added, so the whole surface is stilled instead. Only the easing goes: every element still
   reaches the same end state, in one frame rather than over twelve. */
@media (prefers-reduced-motion: reduce) {
  .compare-root,
  .compare-root *,
  .compare-root *::before,
  .compare-root *::after {
    transition: none !important;
    animation: none !important;
  }
}
