/* ============================================================
   SiteArchitect — app layer
   Loads AFTER brand.css (the PixelChefs system), which already
   provides the shell, cards, tables, buttons, pills, KPI tiles,
   forms and modals. This file adds only what SiteArchitect needs
   on top and reuses the brand tokens throughout.
   ============================================================ */

/* ---------- status colours mapped onto the brand palette ----------
   Yellow is not in play here; the brand primary is the pink gradient
   and it stays reserved for actions. A redirect reads blue because it
   is information, not a warning. */
:root{
  --st-live:var(--green);        --st-live-soft:var(--green-soft);
  --st-redirect:var(--blue);     --st-redirect-soft:var(--blue-soft);
  --st-broken:var(--red);        --st-broken-soft:var(--red-soft);
  --st-planned:var(--muted);     --st-planned-soft:var(--surface-2);
  --st-unchecked:#B9B4C4;        --st-unchecked-soft:var(--surface-2);
}

/* ---------- small utilities brand.css scopes to .page-head / .field ---------- */
.h-eyebrow{
  font-size:11px;text-transform:uppercase;letter-spacing:.16em;color:var(--pink);
  font-weight:600;margin-bottom:8px;display:inline-block;
}
.help{font-size:11.5px;color:var(--muted)}

/* Inline flash / validation line. Quiet by default, red when it matters. */
.alert-line{
  display:flex;gap:9px;align-items:flex-start;padding:11px 15px;border-radius:10px;
  font-size:13.5px;margin-bottom:18px;border:1px solid;
}
.alert-line.ok{background:var(--green-soft);border-color:rgba(20,160,107,.22);color:#0C6B45}
.alert-line.bad{background:var(--red-soft);border-color:rgba(220,40,65,.22);color:var(--red)}

/* ---------- small metadata actions (Edit / Delete beside a title) ----------
   These sit inline with the domain and spend pills, so they are quiet by
   default and only take colour on hover. Full reset included: without the
   base .btn class the browser's own button chrome shows through. */
.meta-actions{display:inline-flex;gap:6px;align-items:center}
.meta-btn{
  display:inline-flex;align-items:center;gap:5px;
  appearance:none;-webkit-appearance:none;
  background:var(--surface);border:1px solid var(--line);
  color:var(--muted);font-family:"DM Sans",sans-serif;font-size:12px;font-weight:500;
  line-height:1;padding:5px 11px;border-radius:var(--radius-pill);
  cursor:pointer;text-decoration:none;white-space:nowrap;
  transition:background .15s,border-color .15s,color .15s,transform .06s;
}
.meta-btn svg{width:12px;height:12px;flex:0 0 auto}
.meta-btn:hover{
  background:var(--pink-faint);border-color:rgba(234,37,125,.35);color:var(--pink);
}
.meta-btn:active{transform:translateY(1px)}
.meta-btn:focus-visible{outline:2px solid var(--pink);outline-offset:2px}
.meta-btn.is-danger:hover{
  background:var(--red-soft);border-color:rgba(220,40,65,.35);color:var(--red);
}

/* ---------- client avatar (favicon over initials) ---------- */
.clientmark{
  position:relative;display:grid;place-items:center;flex:0 0 auto;
  border-radius:10px;overflow:hidden;color:#fff;font-weight:700;
  font-family:"Plus Jakarta Sans",sans-serif;letter-spacing:-.02em;
}
.clientmark .ini{position:absolute;inset:0;display:grid;place-items:center}
/* The favicon sits on a white ground so dark icons stay legible on the
   coloured tile. If the image 404s it removes itself and the initials show. */
.clientmark img{
  position:relative;width:100%;height:100%;object-fit:contain;
  background:#fff;padding:14%;
}

/* ---------- workspace shell ---------- */
.ws{display:flex;align-items:flex-start;gap:16px}
.ws .ws-main{flex:1;min-width:0}

/* ---------- category rail ---------- */
.rail{
  width:236px;flex:0 0 236px;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-sm);padding:14px 12px;
  max-height:74vh;overflow-y:auto;position:sticky;top:80px;
}
.rail-label{
  font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.12em;
  color:var(--muted);padding:2px 10px 10px;
}
.rail-item{
  display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:10px;
  text-decoration:none;color:var(--heading);font-size:13px;font-weight:500;
  border:1px solid transparent;margin-bottom:2px;transition:all .15s;
}
.rail-item:hover{background:var(--surface-2)}
.rail-item.active{background:var(--pink-soft);color:var(--heading)}
.rail-item.is-drop{background:var(--pink-soft);border-color:var(--pink);border-style:dashed}
.rail-item .nm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rail-item .n{font-family:"JetBrains Mono",monospace;font-size:11px;color:var(--muted)}
.rail-item .ed{
  border:0;background:none;color:var(--muted);cursor:pointer;padding:0 2px;
  opacity:0;font-size:12px;line-height:1;
}
.rail-item:hover .ed,.rail-item .ed:focus-visible{opacity:1}
.rail-item .ed:hover{color:var(--pink)}
.rail-add{
  width:100%;margin-top:8px;padding:8px;background:none;
  border:1.5px dashed var(--line-strong);border-radius:10px;
  color:var(--muted);cursor:pointer;font-size:12.5px;font-family:"DM Sans",sans-serif;
  transition:all .2s;
}
.rail-add:hover{border-color:var(--pink);color:var(--pink);background:var(--pink-faint)}

/* ---------- toolbar ---------- */
.toolbar{
  display:flex;gap:10px;align-items:center;flex-wrap:wrap;
  padding:14px 20px;border-bottom:1px solid var(--line);
}
.toolbar .search{width:auto;flex:1 1 220px;min-width:0}
.toolbar .select{width:auto;padding:8px 12px;font-size:13px;border-radius:var(--radius-pill)}
.toolbar .count{
  margin-left:auto;font-family:"JetBrains Mono",monospace;
  font-size:12px;color:var(--muted);white-space:nowrap;
}
/* Live filtering: dim the rows while a request is in flight rather than
   flashing them away, so the table does not jump under the cursor. */
#rowsHost{transition:opacity .12s}
#rowsHost.loading{opacity:.45;pointer-events:none}
.toolbar .count.working{color:var(--pink)}

.bulkbar{
  display:flex;gap:10px;align-items:center;flex-wrap:wrap;
  padding:11px 20px;background:var(--pink-faint);
  border-bottom:1px solid var(--line);font-size:13px;
}
.bulkbar .n{font-weight:600;color:var(--heading);font-family:"Plus Jakarta Sans",sans-serif}
.bulkbar .select{width:auto;padding:6px 12px;font-size:12.5px;border-radius:var(--radius-pill)}

/* ---------- progress ---------- */
.progress-card{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:16px 20px;margin-bottom:20px;box-shadow:var(--shadow-sm);
}
.progress-card .track{height:6px;background:var(--surface-2);border-radius:999px;overflow:hidden}
.progress-card .track i{display:block;height:100%;width:0;background:var(--gradient);
  border-radius:999px;transition:width .3s ease}
.progress-card .cap{display:flex;align-items:center;gap:12px;margin-top:10px;
  font-size:13px;color:var(--body)}
.progress-card .cap .btn{margin-left:auto}

/* ---------- the URL table ---------- */
/* The table scrolls inside this, so a wide row never widens the page. */
.tablewrap{overflow:auto;max-height:74vh;-webkit-overflow-scrolling:touch}

/* Column budget. The data on the right — volume, CPC, ranks — is the
   reason the table exists, so URL and keyword are capped rather than
   allowed to push it off the edge. Full values live in title tooltips. */
.table.sheet td,.table.sheet th{padding:10px 12px}
.table.sheet thead th{position:sticky;top:0;z-index:3}
.table.sheet tbody tr{cursor:default}
.table.sheet tbody tr:hover{background:var(--pink-faint)}
.table.sheet tbody tr.selected{background:var(--pink-soft)}
.table.sheet tbody tr.planned{background:var(--surface-2)}
.table.sheet tbody tr.planned .path{color:var(--muted)}
.table.sheet tbody tr.dragging{opacity:.4}
.table.sheet th:last-child{text-align:center}

.c-check{width:32px}
.c-grip{width:22px;text-align:center;color:var(--line-strong);cursor:grab;user-select:none}
.c-grip:active{cursor:grabbing}
.c-url{max-width:250px;width:250px}
.c-kw{width:190px;min-width:190px}
.c-meta{max-width:108px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.c-num{width:74px}
.c-act{width:40px;text-align:center}

.path{
  display:inline-block;max-width:100%;vertical-align:bottom;
  font-family:"JetBrains Mono",monospace;font-size:12px;color:var(--heading);
  text-decoration:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
a.path:hover{color:var(--pink);text-decoration:underline}
.redir{
  font-family:"JetBrains Mono",monospace;font-size:10.5px;color:var(--blue);
  margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:290px;
}
.tpl{
  font-family:"JetBrains Mono",monospace;font-size:10.5px;color:var(--muted);
  background:var(--surface-2);padding:3px 8px;border-radius:6px;white-space:nowrap;
}
.tpl em{font-style:normal;color:var(--pink);font-weight:500}

.kwin{
  width:100%;border:1px solid transparent;background:transparent;padding:6px 9px;
  border-radius:8px;font-size:13px;font-family:"DM Sans",sans-serif;color:var(--heading);
  transition:all .15s;
}
.kwin::placeholder{color:var(--muted)}
.kwin:hover{border-color:var(--line);background:var(--surface)}
.kwin:focus{outline:none;border-color:var(--pink);background:#fff;box-shadow:0 0 0 4px var(--pink-faint)}
.kwin.saved{border-color:var(--green);background:var(--green-soft)}
.kwsrc{
  font-size:9.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;
  font-weight:600;margin-left:9px;
}
/* Points at the select-all box when someone asks for rankings with nothing
   ticked — shows them where to click rather than just refusing. */
@keyframes nudge{0%,100%{box-shadow:0 0 0 0 rgba(234,37,125,0)}
  40%{box-shadow:0 0 0 6px rgba(234,37,125,.35)}}
.nudge{animation:nudge .8s ease-out 2;border-radius:4px}
.kwsrc.ranked{color:var(--green)}

.vol{font-family:"JetBrains Mono",monospace;font-size:12.5px;color:var(--muted)}
.vol.has{color:var(--heading);font-weight:600}
.rk{
  border:0;background:var(--blue-soft);color:var(--blue);cursor:pointer;
  font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:500;
  padding:3px 9px;border-radius:999px;
}
.rk:hover{background:rgba(37,99,235,.18)}

/* ---------- coverage map ---------- */
.mapgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));gap:16px}
.mcard{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-sm);display:flex;flex-direction:column;overflow:hidden;
  transition:border-color .15s,box-shadow .15s;
}
.mcard.is-drop{border-color:var(--pink);box-shadow:0 0 0 4px var(--pink-faint)}
.mcard .hd{padding:14px 16px 10px;display:flex;align-items:baseline;gap:8px}
.mcard .hd h4{
  font-size:13.5px;font-weight:700;font-family:"Plus Jakarta Sans",sans-serif;
  color:var(--heading);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.mcard .hd .n{
  margin-left:auto;font-family:"JetBrains Mono",monospace;font-size:11px;
  color:var(--pink);background:var(--pink-soft);padding:2px 9px;border-radius:999px;flex:0 0 auto;
}
.mcard .tplline{
  font-family:"JetBrains Mono",monospace;font-size:10.5px;color:var(--muted);
  padding:0 16px 10px;overflow-wrap:anywhere;
}
.mcard .tplline em{font-style:normal;color:var(--pink);font-weight:500}
.mcard .list{padding:8px;max-height:250px;overflow-y:auto;border-top:1px solid var(--line)}
.mrow{
  display:flex;gap:8px;align-items:center;padding:5px 8px;border-radius:8px;
  font-size:12.5px;cursor:grab;
}
.mrow:hover{background:var(--surface-2)}
.mrow.planned{color:var(--muted);background:var(--surface-2);margin-bottom:2px}
.mrow .dot{width:7px;height:7px;border-radius:50%;flex:0 0 auto}
.mrow .p{
  font-family:"JetBrains Mono",monospace;font-size:11px;flex:1;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.mrow .v{font-family:"JetBrains Mono",monospace;font-size:10.5px;color:var(--heading);flex:0 0 auto}

/* ---------- import picker ---------- */
.picklist{border:1px solid var(--line);border-radius:12px;max-height:290px;overflow-y:auto}
.picklist label{
  display:flex;gap:12px;align-items:center;padding:12px 14px;
  border-bottom:1px solid var(--line);cursor:pointer;margin:0;transition:background .15s;
}
.picklist label:last-child{border-bottom:0}
.picklist label:hover{background:var(--pink-faint)}
.picklist .meta{flex:1;min-width:0}
.picklist .meta b{
  display:block;font-size:13px;font-weight:600;color:var(--heading);
  font-family:"Plus Jakarta Sans",sans-serif;
}
.picklist .meta span{
  display:block;font-family:"JetBrains Mono",monospace;font-size:10.5px;
  color:var(--muted);overflow-wrap:anywhere;margin-top:1px;
}
.picklist .when{
  font-family:"JetBrains Mono",monospace;font-size:10.5px;color:var(--muted);flex:0 0 auto;
}
.impmsg{
  margin-top:12px;padding:11px 14px;border-radius:10px;font-size:13px;
  background:var(--surface-2);border:1px solid var(--line);color:var(--body);
}
.impmsg.bad{background:var(--red-soft);border-color:rgba(220,40,65,.2);color:var(--red)}
.impmsg.ok{background:var(--green-soft);border-color:rgba(20,160,107,.2);color:var(--green)}

/* ---------- rankings + spend ---------- */
.klist{max-height:340px;overflow-y:auto;border:1px solid var(--line);border-radius:12px}
.klist .kr{
  display:flex;gap:12px;padding:10px 14px;border-bottom:1px solid var(--line);font-size:13px;
}
.klist .kr:last-child{border-bottom:0}
.klist .kr:hover{background:var(--surface-2)}
.klist .kp{
  margin-left:auto;font-family:"JetBrains Mono",monospace;color:var(--muted);flex:0 0 auto;
}
.spendbox{border:1px solid var(--line);border-radius:12px;overflow:hidden}
.spendbox div{
  display:flex;padding:11px 15px;border-bottom:1px solid var(--line);font-size:13px;
}
.spendbox div:last-child{border-bottom:0;background:var(--pink-faint)}
.spendbox b{
  margin-left:auto;font-family:"Plus Jakarta Sans",sans-serif;color:var(--heading);font-weight:700;
}

/* ---------- environment checks on the setup screen ---------- */
.checks{border:1px solid var(--line);border-radius:12px;overflow:hidden;margin:6px 0 18px}
.checkrow{
  display:flex;gap:10px;align-items:flex-start;padding:10px 14px;
  border-bottom:1px solid var(--line);font-size:13px;
}
.checkrow:last-child{border-bottom:0}
.checkrow .mk{font-weight:700;flex:0 0 auto;line-height:1.45}
.checkrow.ok .mk{color:var(--green)}
.checkrow.bad .mk{color:var(--red)}
.checkrow em{display:block;font-style:normal;color:var(--muted);font-size:11.5px;margin-top:1px}

/* ============================================================
   RESPONSIVE
   Targets: 375–430 phones · 768–1024 tablets · 1280–1512 13–14"
   laptops · 1600–1920 15–17" · 2560+ external displays.
   ============================================================ */

/* Nothing may push the page sideways. Wide things scroll inside their own
   container instead — see .tablewrap and .actionbar below.
   `clip` not `hidden`: overflow-x:hidden turns html/body into a scroll
   container, which silently breaks every position:sticky on the page — the
   sidebar, the topbar and the table header all stop sticking. `clip` trims
   the same overflow without creating that scroll container. */
html,body{max-width:100%;overflow-x:clip}
.main{min-width:0;max-width:100%}
.page{max-width:100%}
.page-head>*{min-width:0}

/* The action row. On a phone it becomes one swipeable strip rather than four
   stacked rows of buttons, which keeps the table above the fold. */
.actionbar{display:flex;gap:8px;flex-wrap:wrap;min-width:0}

/* Off-canvas navigation -------------------------------------------------- */
/* The column carries the dark ground too. The sidebar inside it is 100vh and
   sticky, so on a page taller than the viewport the column extends past it —
   without this, that strip renders as white. */
.sidebar-col{width:264px;background:var(--ink)}
.nav-toggle{display:none;flex:0 0 auto;margin-right:4px}
.nav-scrim{
  position:fixed;inset:0;background:rgba(15,14,20,.5);z-index:59;
  opacity:0;pointer-events:none;transition:opacity .22s;
}
.nav-scrim.open{opacity:1;pointer-events:auto}

@media (max-width:991.98px){
  .sidebar-col{
    position:fixed;left:0;top:0;bottom:0;z-index:60;width:264px;
    transform:translateX(-100%);transition:transform .26s cubic-bezier(.4,0,.2,1);
  }
  .sidebar-col.open{transform:none;box-shadow:24px 0 60px rgba(15,14,20,.28)}
  .nav-toggle{display:grid}
  .topbar{padding:0 16px;gap:12px}
  .page{padding:18px 16px 40px}
  .page-head{margin-bottom:20px}
  .page-head h1{font-size:26px}

  /* One row, swipeable. The scrollbar is hidden but the gesture still works. */
  .actionbar{
    flex-wrap:nowrap;overflow-x:auto;padding-bottom:4px;
    scrollbar-width:none;-ms-overflow-style:none;
  }
  .actionbar::-webkit-scrollbar{display:none}
  .actionbar>*{flex:0 0 auto}

  /* align-items:flex-start is right for the two-column desktop layout, but in
     a column flex container it stops children stretching — they size to their
     content instead, and the table's 724px min-content dragged the whole page
     wider than the phone. Stretch is what we want once stacked. */
  .ws{flex-direction:column;align-items:stretch;gap:12px}
  .rail{width:100%;flex:1 1 auto;max-height:340px;position:static}
  .kpi-grid{grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px}
  .kpi-tile{padding:14px 16px}
  .kpi-tile .val{font-size:24px}
  .toolbar{padding:12px 14px;gap:8px}
  .toolbar .search{flex:1 1 100%}
  .toolbar .count{margin-left:0}
  .modal-head,.modal-body,.modal-foot{padding-left:18px;padding-right:18px}
  .modal-foot{flex-wrap:wrap}
  .modal-foot .btn{flex:1 1 auto;justify-content:center}
}

/* Phones ------------------------------------------------------------------ */
@media (max-width:575.98px){
  .page{padding:16px 12px 36px}
  .page-head h1{font-size:23px}
  .topbar{height:58px;padding:0 12px}
  .crumbs{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .kpi-grid{grid-template-columns:repeat(2,1fr)}
  .kpi-tile .val{font-size:21px}
  .mapgrid{grid-template-columns:1fr}
  .rail{max-height:260px}
  .btn{padding:9px 15px}
  .btn-lg{padding:12px 20px;font-size:14px}
  /* The table keeps its own horizontal scroll; trim the widest columns. */
  .c-url{max-width:190px;width:190px}
  .c-kw{width:170px;min-width:170px}
  .auth-form-side{padding:28px 20px}
}

/* Hide-on-narrow helpers. Category and Template are context, not data, so they
   are the first to go; Volume, CPC and Ranks always survive. */
@media (max-width:1400px){ .hide-lg{display:none} }
@media (max-width:1100px){ .hide-md{display:none} }

/* Large displays ---------------------------------------------------------- */
@media (min-width:1600px){
  .c-url{max-width:340px;width:340px}
  .c-kw{width:240px;min-width:240px}
  .c-meta{max-width:150px}
}
@media (min-width:2000px){
  /* Beyond ~2000px an unbounded table just stretches whitespace. Cap the
     reading width and centre it rather than letting rows span a metre. */
  .page{max-width:1860px;margin-inline:auto;width:100%}
  .c-url{max-width:420px;width:420px}
}

@media (prefers-reduced-motion:reduce){
  .sidebar-col,.nav-scrim{transition:none}
}

/* Ranked-keyword lookup that ran and legitimately found nothing. Visually
   distinct from the em dash, which means "never looked up". */
.rk-none{
  font-family:"JetBrains Mono",monospace;font-size:11px;color:var(--muted);
  background:var(--surface-2);border:1px solid var(--line);
  padding:2px 8px;border-radius:999px;cursor:help;
}

/* ---------- ranking movement ---------- */
.mv{
  font-family:"JetBrains Mono",monospace;font-size:12px;font-weight:600;
  padding:2px 9px;border-radius:999px;display:inline-block;
}
.mv-up{background:var(--green-soft);color:var(--green)}
.mv-down{background:var(--red-soft);color:var(--red)}
.mv-flat{background:var(--surface-2);color:var(--muted)}
.mv-tag{
  font-size:9.5px;text-transform:uppercase;letter-spacing:.08em;font-weight:600;
  padding:2px 7px;border-radius:999px;margin-left:8px;vertical-align:middle;
}
.mv-new{background:var(--blue-soft);color:var(--blue)}
.mv-lost{background:var(--red-soft);color:var(--red)}
/* The summary tiles double as filters. */
a.kpi-tile{display:block;transition:border-color .15s,transform .12s}
a.kpi-tile:hover{border-color:var(--pink);transform:translateY(-1px)}

/* ---------- snapshot comparison picker ----------
   One row. Not built from .field, which is flex-direction:column and would
   stack the label above each select and fight the row it sits in. */
.snapshot-picker{
  /* Explicit columns rather than wrapping flex: the row keeps its shape at any
     width instead of collapsing into a centred stack the moment something is
     a few pixels too wide. */
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto minmax(0,1fr) auto;
  align-items:center;column-gap:12px;
  padding:12px 18px;margin-bottom:18px;
}
.snapshot-picker .lbl{
  font-family:"Plus Jakarta Sans",sans-serif;
  font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;
  color:var(--muted);white-space:nowrap;
}
.snapshot-picker .select{
  width:100%;min-width:0;max-width:280px;
  padding:8px 32px 8px 14px;font-size:13px;border-radius:var(--radius-pill);
}
.snapshot-picker .arrow{
  color:var(--muted);font-size:15px;line-height:1;
  justify-self:center;
}
.snapshot-picker .count{
  font-family:"JetBrains Mono",monospace;
  font-size:11px;color:var(--muted);white-space:nowrap;justify-self:end;
}
/* Every item is placed by hand. Auto-placement let the <noscript> — which is an
   empty grid item when scripting is on — eat column five and bump the count
   onto a second row. */
.snapshot-picker .lbl{grid-column:1}
.snapshot-picker select:first-of-type{grid-column:2}
.snapshot-picker .arrow{grid-column:3}
.snapshot-picker select:last-of-type{grid-column:4}
.snapshot-picker .count{grid-column:5}
.snapshot-picker noscript{grid-column:1/-1;grid-row:2}

@media (max-width:720px){
  .snapshot-picker{
    grid-template-columns:auto minmax(0,1fr);
    row-gap:10px;
  }
  .snapshot-picker .select{max-width:none}
  .snapshot-picker .arrow{display:none}
  .snapshot-picker .lbl{grid-column:1;grid-row:1}
  .snapshot-picker select:first-of-type{grid-column:2;grid-row:1}
  .snapshot-picker select:last-of-type{grid-column:2;grid-row:2}
  .snapshot-picker .count{grid-column:1/-1;grid-row:3;justify-self:start}
  .snapshot-picker noscript{grid-row:4}
}

/* ---------- link from the movement page to the written report ---------- */
.report-cta{
  display:flex;align-items:center;gap:14px;
  padding:16px 20px;margin-bottom:18px;
  background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);text-decoration:none;
  transition:border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.report-cta:hover{
  border-color:var(--pink);
  box-shadow:0 4px 14px rgba(234,37,125,.10);
  transform:translateY(-1px);
}
.rc-ico{
  flex:0 0 auto;width:38px;height:38px;border-radius:11px;
  background:var(--gradient);color:#fff;
  display:flex;align-items:center;justify-content:center;
}
.rc-ico svg{width:18px;height:18px}
.rc-txt{display:flex;flex-direction:column;gap:2px;min-width:0}
.rc-txt strong{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;
  font-size:14px;color:var(--heading);letter-spacing:-.01em;
}
.rc-txt span{font-size:12.5px;color:var(--muted)}
.rc-go{margin-left:auto;color:var(--pink);font-size:18px;flex:0 0 auto}
@media (max-width:560px){
  .rc-go{display:none}
}

/* ---------- table totals bar ----------
   A sibling of the scroll container, not a sticky <tfoot>. A sticky footer
   inside an overflow:auto table leaves a strip of container visible beneath it
   once the rows stop short — this cannot, because it is simply the next
   element and the card ends with it. */
.sheet-total-bar{
  display:flex;align-items:center;gap:22px;flex-wrap:wrap;
  padding:12px 20px;
  background:var(--surface-2);
  border-top:1px solid var(--line);
  font-size:12.5px;color:var(--body);
}
.sheet-total-bar .n strong{
  font-family:"JetBrains Mono",monospace;color:var(--heading);font-weight:600;
}
.sheet-total-bar .sp{flex:1 1 auto}
.sheet-total-bar .fig{display:inline-flex;align-items:baseline;gap:7px;white-space:nowrap}
.sheet-total-bar .fig i{
  font-style:normal;font-size:10px;text-transform:uppercase;letter-spacing:.08em;
  color:var(--muted);
}
.sheet-total-bar .fig strong{
  font-family:"JetBrains Mono",monospace;font-size:13.5px;font-weight:600;color:var(--heading);
}
@media (max-width:575.98px){
  .sheet-total-bar{gap:14px;padding:11px 14px}
  .sheet-total-bar .sp{display:none}
  .sheet-total-bar .n{flex:1 1 100%}
}

/* ---------- section headers inside flush cards ----------
   A bare table butting straight against a heading reads as unfinished. This
   gives every table a proper header band with its own rule, so the card has a
   deliberate top edge rather than the heading resting on the column labels. */
.section-head{
  display:flex;align-items:flex-start;gap:16px;
  padding:20px 24px 18px;
  border-bottom:1px solid var(--line);
}
.section-head.bare{border-bottom:0;padding:0 0 18px}
.section-head h2{
  font-family:"Plus Jakarta Sans",sans-serif;font-size:15px;font-weight:700;
  color:var(--heading);letter-spacing:-.01em;margin:0 0 4px;
}
.section-head p{
  margin:0;font-size:12.5px;line-height:1.55;color:var(--muted);max-width:62ch;
}
.section-count{
  margin-left:auto;flex:0 0 auto;
  font-family:"JetBrains Mono",monospace;font-size:11px;
  color:var(--pink);background:var(--pink-soft);
  padding:4px 11px;border-radius:var(--radius-pill);white-space:nowrap;
}

/* Bootstrap sets .table{margin-bottom:1rem}, which brand.css never resets —
   that is the strip of empty card under every table. Not scrollbars, not
   padding. Do NOT put overflow:hidden on .tablewrap here: it would kill the
   horizontal scrolling the wide workspace table depends on. */
.table{margin-bottom:0}
.card.flush table.sheet tbody tr:last-child td{border-bottom:0}

/* ===========================================================================
   Ranking report
   A single reading column rather than a dashboard. Sized for prose (about 70
   characters) so it stays legible on a 32" monitor and survives being printed.
   =========================================================================== */
/* --- masthead --- */
.report-head{
  border-bottom:1px solid var(--line);
  padding-bottom:22px;
  margin-bottom:28px;
}
/* .rh-brand is gone from the markup: the report names itself in the title. */
.rh-mark{
  width:20px;height:20px;border-radius:6px;
  background:var(--gradient);flex:0 0 auto;
}
.rh-name{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;
  font-size:13px;letter-spacing:-.01em;color:var(--heading);
}
.rh-title{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;
  font-size:34px;line-height:1.15;letter-spacing:-.025em;
  color:var(--heading);margin:0 0 8px;
}
.rh-meta{
  margin:0;font-size:13px;color:var(--muted);
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
}
.rh-meta strong{color:var(--heading);font-weight:600}
.rh-tag{
  font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;
  padding:3px 9px;border-radius:var(--radius-pill);
  background:var(--pink-soft);color:var(--pink);
}

/* --- prose --- */
.report-lede{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:600;
  font-size:20px;line-height:1.45;letter-spacing:-.015em;
  color:var(--heading);margin:0 0 20px;
}
.report-p{
  font-size:15px;line-height:1.7;color:var(--body);
  margin:0 0 14px;max-width:66ch;
}
.report-p:last-of-type{margin-bottom:0}

/* --- sections --- */
.report-sec{margin-top:38px}
.report-sec > h2{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;
  font-size:17px;letter-spacing:-.015em;color:var(--heading);
  margin:0 0 4px;
  padding-bottom:10px;border-bottom:1px solid var(--line);
}
.report-sec .sec-note{
  font-size:13px;color:var(--muted);margin:12px 0 18px;max-width:64ch;
}
.report-sec > h2 + .vis-bar,
.report-sec > h2 + .chg-grid{margin-top:20px}

/* --- visibility bands --- */
.vis-bar{
  display:grid;grid-template-columns:repeat(4,1fr);
  gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:var(--radius-sm);
  overflow:hidden;
}
.vis-cell{
  background:var(--surface);padding:16px 18px;
  display:flex;flex-direction:column;gap:2px;
}
.vis-cell .v{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;
  font-size:26px;line-height:1.1;letter-spacing:-.02em;color:var(--heading);
}
.vis-cell .l{font-size:12.5px;font-weight:600;color:var(--heading)}
.vis-cell .s{font-size:11px;color:var(--muted)}
/* Position quality reads left to right: strongest band carries the brand. */
.vis-cell.is-top3 .v{color:var(--pink)}
.vis-cell.is-top3{background:var(--pink-faint)}

/* --- change counters --- */
.chg-grid{
  display:grid;grid-template-columns:repeat(5,1fr);
  gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden;
}
.chg{background:var(--surface);padding:14px 16px;display:flex;flex-direction:column;gap:1px}
.chg .v{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;
  font-size:22px;line-height:1.15;color:var(--heading);
}
.chg .v.green{color:#12805C}
.chg .v.red{color:#C4374F}
.chg .v.blue{color:#2563C9}
.chg .l{font-size:11.5px;color:var(--muted)}

/* --- named movers --- */
.mover-grid{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:16px;margin-top:20px;
}
.mover{
  border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:16px 18px;background:var(--surface-2);
}
.mover h3{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;
  font-size:12px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--muted);margin:0 0 10px;
}
.mover ul{list-style:none;margin:0;padding:0}
.mover li{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:6px 0;border-bottom:1px solid var(--line);font-size:13px;
}
.mover li:last-child{border-bottom:0;padding-bottom:0}
.mover .kw{color:var(--heading);font-weight:500;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mover .pos{
  font-family:"JetBrains Mono",monospace;font-size:11.5px;
  color:var(--muted);flex:0 0 auto;
}
.mover-up   .pos{color:#12805C}
.mover-down .pos{color:#C4374F}
.mover-new  .pos{color:#2563C9}

/* --- recommendations --- */
/* ---------------------------------------------------------------------------
   Evidence rows under a recommendation.

   Three kinds of information, three visual registers, so the eye can run down
   one column without reading the others: the keyword is the subject and gets
   weight; the URL is supporting detail and goes mono and quiet; the position
   and volume are figures and sit right-aligned in fixed columns where they can
   be compared line to line.
   --------------------------------------------------------------------------- */
.ev{
  list-style:none;margin:14px 0 0;padding:12px 0 0;
  border-top:1px solid var(--line);
}
.ev-row{
  display:grid;
  grid-template-columns:minmax(0,1fr) 116px 92px;
  align-items:baseline;column-gap:16px;
  padding:8px 0;
  border-bottom:1px solid var(--line);
}
.ev-row:last-child{border-bottom:0;padding-bottom:0}

/* --- subject column: keyword above, URL beneath --- */
.ev-main{display:flex;flex-direction:column;gap:2px;min-width:0}
.ev-kw{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:600;
  font-size:13.5px;letter-spacing:-.008em;color:var(--heading);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.ev-url{
  font-family:"JetBrains Mono",monospace;
  font-size:11px;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  direction:ltr;
}
/* A URL with no keyword above it is the subject, so it takes the weight. */
.ev-main > .ev-url:first-child{font-size:12px;color:var(--body)}
.ev-note{
  font-size:11px;color:var(--muted);font-style:italic;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* A count that can be opened should look like it can be opened, so it takes the
   brand colour and a chevron rather than sitting there as quiet italic text. */
button.ev-note{
  all:unset;
  display:inline-flex;align-items:center;gap:3px;
  /* .ev-main is a flex column, so a child stretches the full width unless told
     otherwise — which painted the pill right across the row. Hug the text. */
  align-self:flex-start;
  max-width:100%;
  font-family:"DM Sans",sans-serif;font-size:11px;font-style:normal;font-weight:600;
  color:var(--pink);cursor:pointer;
  padding:1px 5px 1px 6px;border-radius:var(--radius-pill);
  background:var(--pink-faint);
  transition:background .14s ease, color .14s ease;
}
button.ev-note svg{width:9px;height:9px;flex:0 0 auto;opacity:.75}
button.ev-note:hover{background:var(--pink-soft)}
button.ev-note:focus-visible{outline:2px solid var(--pink);outline-offset:2px}

/* --- the dialog those counts open --- */
.ev-dlg-label{
  font-family:"JetBrains Mono",monospace;font-size:11.5px;
  color:var(--muted);margin:0;word-break:break-all;
}
.ev-dlg{
  margin:0;padding:0;border-top:0;
  max-height:52vh;overflow-y:auto;
}
.ev-dlg .ev-row{grid-template-columns:minmax(0,1fr) 64px 88px}

/* --- position column --- */
.ev-pos{
  font-family:"JetBrains Mono",monospace;font-size:12px;
  text-align:right;white-space:nowrap;color:var(--muted);
}
.ev-was{color:var(--muted)}
.ev-arrow{color:var(--line-strong);margin:0 2px}
.ev-now{color:var(--heading);font-weight:600}

/* --- volume column --- */
.ev-vol{
  font-family:"JetBrains Mono",monospace;font-size:12px;
  font-variant-numeric:tabular-nums;
  text-align:right;white-space:nowrap;color:var(--heading);font-weight:600;
}
.ev-vol i{font-style:normal;font-weight:400;color:var(--muted);font-size:10px;margin-left:1px}
.ev-dash{color:var(--line-strong);font-weight:400}

.ev-more{
  margin:10px 0 0;font-size:11.5px;color:var(--muted);font-style:italic;
}

/* Tighten to two columns before the figures start colliding with the subject. */
@media (max-width:700px){
  .ev-row{grid-template-columns:minmax(0,1fr) auto;row-gap:2px}
  .ev-pos{grid-column:2;text-align:right}
  .ev-vol{grid-column:2;text-align:right;font-size:11px}
}

/* --- footer --- */
.report-foot{
  margin-top:38px;padding-top:18px;border-top:1px solid var(--line);
  display:flex;justify-content:space-between;align-items:center;gap:16px;
  font-size:11.5px;color:var(--muted);flex-wrap:wrap;
}
.rf-by{font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;color:var(--heading)}

/* ---------------------------------------------------------------------------
   "Last run" line in the spend dialog.

   Two registers on purpose: an old run is a neutral fact and stays quiet, while
   a run inside the last day is the case worth interrupting for — that is the
   one where confirming buys the same answer a second time.
   --------------------------------------------------------------------------- */
.spend-last{
  display:flex;align-items:flex-start;gap:9px;
  padding:11px 13px;margin-bottom:14px;
  border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface-2);
  font-size:12.5px;line-height:1.5;color:var(--body);
}
.spend-last .sl-ico{flex:0 0 auto;display:flex;color:var(--muted);margin-top:1px}
.spend-last .sl-ico svg{width:15px;height:15px}
.spend-last.is-recent{
  border-color:var(--amber);
  background:var(--amber-soft);
  color:var(--heading);
}
.spend-last.is-recent .sl-ico{color:var(--amber)}

/* ===========================================================================
   Report — full width.

   The card fills the page, but prose does not: a line of text 1900px wide is
   unreadable, so the writing keeps a measure while the data blocks spread out
   and use the room. Wide screens gain columns, not longer lines.
   =========================================================================== */
.report{
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius);
  padding:44px 52px 32px;
  max-width:none;
  box-shadow:0 1px 2px rgba(15,14,20,.04);
}
@media (min-width:1600px){
  .report{padding:52px 64px 40px}
}

/* Prose holds its measure no matter how wide the card gets. */
.report-lede{max-width:34ch}
.report-p{max-width:76ch}
.report-sec .sec-note{max-width:76ch}

@media (min-width:1200px){
  /* The headline sits beside the detail rather than above a long empty gap. */
  .report-lede{max-width:52ch}
}

/* --- data blocks use the extra room --- */
@media (min-width:1500px){
  .mover-grid{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
}

/* One finding per row at every width. Each card carries a title, an action and
   a table of evidence — splitting that into columns made two dense blocks
   compete side by side instead of reading in order of importance. */
.rec-list{display:grid;gap:14px}

/* ===========================================================================
   Recommendations — brand-led.

   The accent bar is the PixelChefs gradient by default. Severity still reads,
   but through a tint and the badge rather than four competing border colours,
   so a page of findings looks like one system instead of a traffic light.
   =========================================================================== */
.rec{
  position:relative;
  border:1px solid var(--line);
  border-radius:var(--radius-sm);
  padding:18px 20px 18px 23px;
  margin:0;
  background:var(--surface);
  overflow:hidden;
  transition:border-color .15s ease, box-shadow .15s ease;
}
.rec:hover{
  border-color:var(--line-strong);
  box-shadow:0 4px 16px rgba(15,14,20,.05);
}
/* The accent bar: brand gradient, recoloured per severity. */
.rec::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--gradient);
}
.rec.is-bad::before{background:var(--red)}
.rec.is-warn::before{background:var(--amber)}
.rec.is-good::before{background:var(--green)}

.rec-hd{display:flex;align-items:flex-start;gap:11px;margin-bottom:8px}
.rec-n{
  flex:0 0 auto;width:24px;height:24px;border-radius:50%;
  background:var(--gradient);color:#fff;
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;font-size:11px;
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 2px 6px rgba(234,37,125,.28);
}
.rec.is-bad .rec-n{background:var(--red);box-shadow:0 2px 6px rgba(220,40,65,.28)}
.rec.is-warn .rec-n{background:var(--amber);box-shadow:0 2px 6px rgba(213,138,14,.28)}
.rec.is-good .rec-n{background:var(--green);box-shadow:0 2px 6px rgba(20,160,107,.28)}

.rec-hd h3{
  font-family:"Plus Jakarta Sans",sans-serif;font-weight:700;
  font-size:15px;letter-spacing:-.012em;color:var(--heading);
  margin:0;line-height:1.35;
}
.rec-dt{font-size:13.5px;line-height:1.6;color:var(--body);margin:0 0 10px;max-width:88ch}

/* The action is the point of the card, so it is set apart rather than left as
   another paragraph the eye can skim past. */
.rec-ac{
  font-size:13.5px;line-height:1.6;color:var(--heading);margin:0;
  padding:9px 12px;border-radius:8px;
  background:var(--pink-faint);
  border:1px solid rgba(234,37,125,.14);
}
.rec-ac strong{font-weight:700;color:var(--pink)}
.rec.is-bad .rec-ac{background:var(--red-soft);border-color:rgba(220,40,65,.16)}
.rec.is-bad .rec-ac strong{color:var(--red)}
.rec.is-warn .rec-ac{background:var(--amber-soft);border-color:rgba(213,138,14,.18)}
.rec.is-warn .rec-ac strong{color:var(--amber)}
.rec.is-good .rec-ac{background:var(--green-soft);border-color:rgba(20,160,107,.16)}
.rec.is-good .rec-ac strong{color:var(--green)}

/* --- narrow screens --- */
@media (max-width:900px){
  .report{padding:28px 22px 24px}
  .rh-title{font-size:26px}
  .report-lede{font-size:17px}
  .vis-bar{grid-template-columns:repeat(2,1fr)}
  .chg-grid{grid-template-columns:repeat(3,1fr)}
  .mover-grid{grid-template-columns:1fr}
}
@media (max-width:560px){
  .report{padding:22px 16px 20px;border-radius:var(--radius-sm)}
  .rh-title{font-size:22px}
  .report-lede{font-size:16px}
  .report-p{font-size:14px}
  .chg-grid{grid-template-columns:repeat(2,1fr)}
}

/* ===========================================================================
   Print — the report is the page. Everything else is app chrome and goes away.
   Colours are forced on because a report with grey-on-grey bands reads as a
   printer fault, not a design choice.
   =========================================================================== */
@media print{
  @page{margin:14mm}
  html,body{background:#fff!important}
  .sidebar-col,.topbar,.nav-scrim,.no-print,.alert-line,.modal-backdrop{display:none!important}
  /* A count that opens a dialog cannot be clicked on paper — show it plainly. */
  button.ev-note{background:none;color:var(--muted);padding:0;font-style:italic;font-weight:400}
  button.ev-note svg{display:none}
  .app,.row,.col.main,.page{display:block!important;padding:0!important;margin:0!important}
  .report{
    border:0;border-radius:0;box-shadow:none;
    padding:0;max-width:none;
  }
  .report *{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  /* Never split a recommendation or a mover list across a page break. */
  .rec,.mover,.report-sec > h2,.vis-bar,.chg-grid,.ev-row{break-inside:avoid}
  .report-sec > h2{break-after:avoid}
  .report-foot{break-inside:avoid}
}

/* ---------------------------------------------------------------------------
   Sortable category rail.

   The grip only appears on hover: at rest the rail should read as a list of
   filters, not a control panel. It holds its width either way so nothing
   shifts sideways when the pointer arrives.
   --------------------------------------------------------------------------- */
.rail-item .grip{
  flex:0 0 auto;width:10px;height:16px;margin-right:2px;
  display:flex;align-items:center;justify-content:center;
  color:var(--line-strong);opacity:0;
  cursor:grab;transition:opacity .12s ease, color .12s ease;
}
.rail-item .grip svg{width:8px;height:13px;pointer-events:none}
.rail-item:hover .grip{opacity:1}
.rail-item .grip:hover{color:var(--pink)}
.rail-item .grip:active{cursor:grabbing}

.rail-item.cat-dragging{
  opacity:.55;
  background:var(--pink-faint);
  box-shadow:0 4px 14px rgba(15,14,20,.10);
}
/* While reordering, the pointer is over the grip and every other item is a
   drop position — a text caret there just looks like a mistake. */
.rail-sortable:has(.cat-dragging) .rail-item{cursor:grabbing}

/* Touch devices get no hover, so the grip would never appear. */
@media (hover:none){
  .rail-item .grip{opacity:.55}
}
