/* Algoable component layer — hand-authored plain-CSS translation of the
   Algoable design system's JSX component specs, for use in server-rendered
   Django templates (no build step / no React in this project). */

/* ---------- Core: buttons, badges, tags ---------- */

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  font-family:var(--font-body);font-weight:var(--fw-medium);font-size:var(--text-sm);
  padding:9px 16px;border-radius:var(--radius-md);cursor:pointer;
  border:1px solid transparent;white-space:nowrap;letter-spacing:var(--ls-normal);
  transition:background var(--duration-fast) var(--ease-standard),
             border-color var(--duration-fast) var(--ease-standard),
             opacity var(--duration-fast);
  text-decoration:none;
}
.btn[disabled],.btn.is-disabled{opacity:.4;cursor:not-allowed;}
.btn:active:not([disabled]):not(.is-disabled){transform:translateY(1px);}
.btn i[data-lucide]{width:15px;height:15px;}

.btn-sm{padding:6px 12px;font-size:var(--text-xs);gap:6px;}
.btn-lg{padding:13px 22px;font-size:var(--text-base);gap:8px;}
.btn-block{width:100%;}

.btn-primary{background:var(--accent-1);color:var(--text-on-accent);border-color:var(--accent-1);}
.btn-primary:hover:not([disabled]):not(.is-disabled){background:var(--accent-2);border-color:var(--accent-2);}

.btn-secondary{background:var(--surface-card);color:var(--text-primary);border-color:var(--border-strong);}
.btn-secondary:hover:not([disabled]):not(.is-disabled){background:var(--surface-card-hover);border-color:var(--border-hairline);}

.btn-ghost{background:transparent;color:var(--text-secondary);}
.btn-ghost:hover:not([disabled]):not(.is-disabled){background:var(--surface-card);color:var(--text-primary);}

.btn-danger{background:var(--negative);color:#160b0b;border-color:var(--negative);}
.btn-danger:hover:not([disabled]):not(.is-disabled){background:#f37a7a;border-color:#f37a7a;}

.icon-btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;border-radius:var(--radius-md);
  background:transparent;border:1px solid transparent;color:var(--text-secondary);
  cursor:pointer;transition:background var(--duration-fast) var(--ease-standard),color var(--duration-fast);
}
.icon-btn:hover{background:var(--surface-card);color:var(--text-primary);}
.icon-btn.is-filled{background:var(--surface-card);border-color:var(--border-default);}
.icon-btn i[data-lucide]{width:16px;height:16px;}

/* Theme toggle: render both icons and let CSS pick the right one for the
   current theme, rather than mutating data-lucide + re-invoking Lucide
   (Lucide only converts <i data-lucide> once and won't re-render an
   already-converted <svg> on a second createIcons() call). */
[data-theme-toggle] .theme-icon-light{display:none;}
[data-theme="light"] [data-theme-toggle] .theme-icon-dark{display:none;}
[data-theme="light"] [data-theme-toggle] .theme-icon-light{display:inline-flex;}

.badge{
  display:inline-flex;align-items:center;gap:5px;
  font-family:var(--font-mono);font-size:var(--text-2xs);font-weight:var(--fw-medium);
  letter-spacing:var(--ls-wide);text-transform:uppercase;
  padding:3px 8px;border-radius:var(--radius-full);
  background:var(--surface-elevated);color:var(--text-secondary);
}
.badge-positive{background:var(--positive-soft);color:var(--positive);}
.badge-negative{background:var(--negative-soft);color:var(--negative);}
.badge-info{background:var(--info-soft);color:var(--info);}
.badge-neutral{background:var(--surface-elevated);color:var(--text-tertiary);}
.badge-dot::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor;}

.tag{
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--font-body);font-size:var(--text-xs);font-weight:var(--fw-medium);
  padding:6px 12px;border-radius:var(--radius-full);cursor:pointer;
  background:var(--surface-card);color:var(--text-secondary);border:1px solid var(--border-default);
  transition:background var(--duration-fast),color var(--duration-fast),border-color var(--duration-fast);
}
.tag:hover{background:var(--surface-card-hover);}
.tag.is-active{background:var(--accent-soft);color:var(--accent-1);border-color:var(--accent-1);}
.tag-remove{margin-left:2px;line-height:1;opacity:.7;}
.tag-remove:hover{opacity:1;}

.spin{animation:algoable-spin 1s linear infinite;}
@keyframes algoable-spin{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}

/* ---------- Forms ---------- */

.field{display:flex;flex-direction:column;gap:6px;}
.field-label{font-size:var(--text-xs);font-weight:var(--fw-medium);color:var(--text-secondary);}
.field-help{font-size:var(--text-2xs);color:var(--text-tertiary);}
.field-error{font-size:var(--text-2xs);color:var(--negative);}

.input,.select{
  font-family:var(--font-body);font-size:var(--text-sm);color:var(--text-primary);
  background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-md);
  padding:9px 12px;line-height:var(--lh-normal);
  transition:border-color var(--duration-fast) var(--ease-standard),box-shadow var(--duration-fast);
}
.input::placeholder{color:var(--text-tertiary);}
.input:focus,.select:focus{outline:none;border-color:var(--accent-1);box-shadow:var(--shadow-focus);}
.input:disabled,.select:disabled{opacity:.5;cursor:not-allowed;}
.input-with-icon{position:relative;display:flex;align-items:center;}
.input-with-icon>i[data-lucide]{position:absolute;left:12px;width:15px;height:15px;color:var(--text-tertiary);pointer-events:none;}
.input-with-icon>.input{padding-left:36px;width:100%;}

.select{appearance:none;background-image:linear-gradient(45deg,transparent 50%,var(--text-tertiary) 50%),linear-gradient(135deg,var(--text-tertiary) 50%,transparent 50%);background-position:calc(100% - 18px) 15px,calc(100% - 13px) 15px;background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:32px;}

.checkbox,.radio{
  display:inline-flex;align-items:center;gap:8px;font-size:var(--text-sm);color:var(--text-secondary);cursor:pointer;
}
.checkbox input,.radio input{
  appearance:none;width:16px;height:16px;flex-shrink:0;
  border:1px solid var(--border-strong);background:var(--surface-card);cursor:pointer;
  position:relative;transition:background var(--duration-fast),border-color var(--duration-fast);
}
.checkbox input{border-radius:4px;}
.radio input{border-radius:50%;}
.checkbox input:checked,.radio input:checked{background:var(--accent-1);border-color:var(--accent-1);}
.checkbox input:checked::after{
  content:'';position:absolute;left:4px;top:1px;width:4px;height:8px;
  border:solid var(--text-on-accent);border-width:0 2px 2px 0;transform:rotate(45deg);
}
.radio input:checked::after{
  content:'';position:absolute;left:4px;top:4px;width:6px;height:6px;border-radius:50%;background:var(--text-on-accent);
}

.switch{display:inline-flex;align-items:center;gap:8px;font-size:var(--text-sm);color:var(--text-secondary);cursor:pointer;}
.switch-track{
  width:36px;height:20px;border-radius:var(--radius-full);background:var(--surface-elevated);
  border:1px solid var(--border-default);position:relative;transition:background var(--duration-base) var(--ease-standard);
  flex-shrink:0;
}
.switch-thumb{
  position:absolute;top:1px;left:1px;width:16px;height:16px;border-radius:50%;background:var(--fg-2);
  transition:transform var(--duration-base) var(--ease-standard),background var(--duration-base);
}
.switch input{position:absolute;opacity:0;width:0;height:0;}
.switch input:checked ~ .switch-track{background:var(--accent-soft-strong);border-color:var(--accent-1);}
.switch input:checked ~ .switch-track .switch-thumb{transform:translateX(16px);background:var(--accent-1);}

/* ---------- Feedback ---------- */

.tooltip{position:relative;}
.tooltip[data-tooltip]::after{
  content:attr(data-tooltip);position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);
  background:var(--surface-elevated);color:var(--text-primary);font-size:var(--text-2xs);
  padding:4px 8px;border-radius:var(--radius-sm);white-space:nowrap;box-shadow:var(--shadow-md);
  opacity:0;pointer-events:none;transition:opacity var(--duration-fast);
}
.tooltip[data-tooltip]:hover::after,.tooltip[data-tooltip]:focus::after{opacity:1;}

.toast-container{position:fixed;bottom:24px;right:24px;display:flex;flex-direction:column;gap:8px;z-index:1000;}
.toast{
  display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:var(--radius-lg);
  background:var(--surface-elevated);color:var(--text-primary);box-shadow:var(--shadow-lg);
  border:1px solid var(--border-default);font-size:var(--text-sm);min-width:240px;
}
.toast-success{border-left:2px solid var(--positive);}
.toast-error{border-left:2px solid var(--negative);}
.toast-info{border-left:2px solid var(--info);}

.dialog-overlay{
  position:fixed;inset:0;background:var(--surface-overlay);display:flex;align-items:center;justify-content:center;
  z-index:1000;
}
.dialog-panel{
  background:var(--surface-elevated);border:1px solid var(--border-default);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-lg);max-width:480px;width:100%;
}
.dialog-header{padding:20px 20px 0;font-family:var(--font-display);font-size:var(--text-md);font-weight:var(--fw-semibold);}
.dialog-body{padding:16px 20px;color:var(--text-secondary);font-size:var(--text-sm);}
.dialog-footer{padding:0 20px 20px;display:flex;justify-content:flex-end;gap:8px;}

/* ---------- Navigation ---------- */

.navbar{
  display:flex;align-items:center;justify-content:space-between;
  padding:0 24px;height:64px;background:var(--surface-bg);border-bottom:1px solid var(--border-default);
  font-family:var(--font-body);position:sticky;top:0;z-index:100;
}
.navbar-brand{display:flex;align-items:center;gap:9px;color:var(--text-primary);text-decoration:none;}
.navbar-brand-name{font-family:var(--font-display);font-size:var(--text-lg);font-weight:var(--fw-semibold);letter-spacing:var(--ls-tight);}
.navbar-inner{display:flex;align-items:center;gap:16px;}

.navbar-nav{display:flex;align-items:center;gap:4px;list-style:none;margin:0;padding:0;}
.nav-link{
  display:flex;align-items:center;gap:8px;padding:9px 14px;border-radius:var(--radius-md);
  color:var(--text-secondary);font-size:var(--text-sm);text-decoration:none;white-space:nowrap;
  transition:background var(--duration-fast),color var(--duration-fast);
}
.nav-link:hover,.nav-link.is-active{background:var(--surface-card);color:var(--text-primary);}
.nav-link i[data-lucide]{width:15px;height:15px;}
.nav-group-label{
  padding:14px 14px 4px;font-family:var(--font-mono);font-size:var(--text-2xs);
  text-transform:uppercase;letter-spacing:var(--ls-wide);color:var(--text-tertiary);
}

.navbar-toggle{
  display:none;width:36px;height:36px;align-items:center;justify-content:center;
  background:transparent;border:1px solid var(--border-default);border-radius:var(--radius-md);
  color:var(--text-primary);cursor:pointer;flex-shrink:0;
}

.dropdown{position:relative;}
.dropdown-toggle{cursor:pointer;display:flex;align-items:center;gap:6px;}
.dropdown-menu{
  position:absolute;top:calc(100% + 6px);right:0;min-width:180px;
  background:var(--surface-elevated);border:1px solid var(--border-default);border-radius:var(--radius-md);
  box-shadow:var(--shadow-md);padding:6px;display:none;z-index:200;
}
.dropdown-menu.is-open{display:block;}
.dropdown-menu ul,.dropdown-menu{list-style:none;margin:0;}
.dropdown-menu li{list-style:none;}
.dropdown-menu .nav-link{color:var(--text-secondary);}

.accordion-item{border-bottom:1px solid var(--border-default);}
.accordion-trigger{
  display:flex;align-items:center;justify-content:space-between;width:100%;
  padding:10px 14px;background:transparent;border:none;color:var(--text-secondary);
  font-size:var(--text-sm);cursor:pointer;text-align:left;font-family:var(--font-body);
}
.accordion-trigger:hover{color:var(--text-primary);}
.accordion-panel{display:none;padding-left:8px;}
.accordion-panel.is-open{display:block;}
.accordion-chevron{transition:transform var(--duration-base) var(--ease-standard);}
.accordion-trigger[aria-expanded="true"] .accordion-chevron{transform:rotate(180deg);}

.search-widget{position:relative;}
.search-input{
  width:220px;font-family:var(--font-body);font-size:var(--text-sm);color:var(--text-primary);
  background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-md);
  padding:8px 12px;
}
.search-input:focus{outline:none;border-color:var(--accent-1);box-shadow:var(--shadow-focus);}
.search-results{
  position:absolute;top:calc(100% + 6px);left:0;right:0;max-height:320px;overflow-y:auto;
  background:var(--surface-elevated);border:1px solid var(--border-default);border-radius:var(--radius-md);
  box-shadow:var(--shadow-md);z-index:200;
}
.search-result-item{
  display:flex;flex-direction:column;gap:2px;padding:8px 12px;cursor:pointer;
  font-size:var(--text-sm);color:var(--text-primary);border-bottom:1px solid var(--border-default);
}
.search-result-item:last-child{border-bottom:none;}
.search-result-item:hover,.search-result-item.is-highlighted{background:var(--surface-card);}
.search-result-title{font-family:var(--font-mono);font-weight:var(--fw-semibold);}
.search-result-meta{font-size:var(--text-2xs);color:var(--text-tertiary);}
.search-result-empty,.search-result-error{padding:12px;font-size:var(--text-sm);color:var(--text-tertiary);}

.tabs{display:flex;gap:4px;border-bottom:1px solid var(--border-default);list-style:none;margin:0;padding:0;}
.tab{
  padding:10px 16px;font-size:var(--text-sm);color:var(--text-tertiary);cursor:pointer;
  border-bottom:2px solid transparent;margin-bottom:-1px;background:transparent;border-top:none;border-left:none;border-right:none;
  font-family:var(--font-body);
}
.tab:hover{color:var(--text-primary);}
.tab.is-active{color:var(--text-primary);border-bottom-color:var(--accent-1);}

@media (max-width:768px){
  .navbar .navbar-toggle{display:inline-flex;}
  .navbar .navbar-nav{display:none;}
}

/* ---------- Dashboard app shell (fixed sidebar + topbar, mirrors Algoable's
   own trading-dashboard UI kit and the site's existing SB-Admin-style layout) ---------- */

.app-shell{display:flex;min-height:100vh;}
/* overflow:visible, not auto. The search results and the user menu are absolutely
   positioned popovers that must escape the sidebar's 220px -- a scroll container
   would clip them. The scrolling moves to .sidebar-nav, which is the only part
   that can actually get long. */
.app-sidebar{
  width:220px;flex-shrink:0;background:var(--surface-bg);border-right:1px solid var(--border-default);
  display:flex;flex-direction:column;padding:20px 12px;position:fixed;top:0;bottom:0;left:0;overflow:visible;z-index:150;
  transition:transform var(--duration-base) var(--ease-standard);
}
.sidebar-brand{display:flex;align-items:center;gap:9px;padding:0 10px 20px;color:var(--text-primary);text-decoration:none;flex-wrap:wrap;}
.sidebar-brand-name{font-family:var(--font-display);font-size:var(--text-lg);font-weight:var(--fw-semibold);letter-spacing:var(--ls-tight);}
/* The only part that can grow past the viewport, so the only part that scrolls.
   min-height:0 because a flex child will not shrink below its content otherwise
   and the footer would be pushed off the bottom instead. */
.sidebar-nav{display:flex;flex-direction:column;gap:2px;flex:1 1 auto;overflow-y:auto;min-height:0;}

/* Search sits directly under the brand: it is the most-used control on the site
   and it used to be the first thing in the header. */
.sidebar-search{padding:0 10px 14px;}
.app-sidebar .search-widget{width:100%;}
.app-sidebar .search-input{width:100%;}
/* Wider than the sidebar and opening over the content, because a 196px-wide
   result row cannot show a code, a name and a category. */
.app-sidebar .search-results{left:0;right:auto;width:min(340px,calc(100vw - 32px));}

.sidebar-footer{
  margin-top:auto;padding:12px 10px 0;border-top:1px solid var(--border-default);
  display:flex;align-items:center;gap:8px;flex-shrink:0;
}
.sidebar-user{flex:1 1 auto;min-width:0;}
.sidebar-user .dropdown-toggle{
  width:100%;padding:8px 10px;border-radius:var(--radius-md);color:var(--text-secondary);
  font-size:var(--text-sm);text-decoration:none;
}
.sidebar-user .dropdown-toggle:hover{background:var(--surface-card);color:var(--text-primary);}
.sidebar-user-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;}

/* The footer is at the bottom of the viewport, so its menu has to open upward
   and to the right -- the default (top:100%;right:0) would drop it off-screen. */
.dropup .dropdown-menu{top:auto;bottom:calc(100% + 6px);left:0;right:auto;}

.app-main{flex:1 1 auto;margin-left:220px;display:flex;flex-direction:column;min-width:0;}
.app-content{padding:24px;flex:1 1 auto;}

/* Edge-to-edge: for a page that *is* one canvas, where the gutter is just a
   band of background around the thing you came to look at. Set with
   {% block content_class %}is-flush{% endblock %}. */
.app-content.is-flush{padding:0;}

/* Opens the sidebar once it is off-canvas. Replaces the toggle that used to
   live in the header; floats over the content rather than reserving a bar. */
.sidebar-fab{
  display:none;position:fixed;top:12px;left:12px;z-index:160;
  width:38px;height:38px;align-items:center;justify-content:center;
  background:var(--surface-elevated);border:1px solid var(--border-default);
  border-radius:var(--radius-md);color:var(--text-primary);cursor:pointer;
  box-shadow:var(--shadow-md);
}
.sidebar-fab i[data-lucide]{width:18px;height:18px;}

@media (max-width:900px){
  .app-sidebar{transform:translateX(-100%);}
  .app-sidebar.is-open{transform:translateX(0);}
  .app-main{margin-left:0;}
  .sidebar-fab{display:inline-flex;}
  /* Clear the floating toggle. Repeated at .is-flush's specificity, or the
     flush rule (0,2,0) would beat this one (0,1,0) and the toggle would sit on
     top of the page's own controls. */
  .app-content{padding-top:62px;}
  .app-content.is-flush{padding:62px 0 0;}
}

/* ---------- Data ---------- */

.ds-table{width:100%;border-collapse:collapse;font-family:var(--font-body);font-size:var(--text-sm);}
.ds-table th{
  text-align:left;padding:10px 14px;font-size:var(--text-2xs);text-transform:uppercase;
  letter-spacing:var(--ls-wide);color:var(--text-tertiary);font-weight:var(--fw-medium);
  border-bottom:1px solid var(--border-strong);font-family:var(--font-mono);
}
.ds-table td{padding:11px 14px;color:var(--text-secondary);border-bottom:1px solid var(--border-default);}
.ds-table td.is-mono{font-family:var(--font-mono);color:var(--text-primary);}
.ds-table td.is-positive{color:var(--positive);}
.ds-table td.is-negative{color:var(--negative);}
.ds-table--striped tbody tr:nth-child(even){background:var(--surface-card);}
.ds-table--hover tbody tr:hover{background:var(--surface-card-hover);}

.chart-container{
  background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-lg);
  padding:20px;box-shadow:var(--inset-hairline);
}
.chart-container-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:14px;}
.chart-container-title{font-family:var(--font-display);font-size:var(--text-md);color:var(--text-primary);font-weight:var(--fw-semibold);}
.chart-container-subtitle{font-size:var(--text-xs);color:var(--text-tertiary);margin-top:2px;}
.chart-container-body{
  border-radius:var(--radius-md);
  background-image:repeating-linear-gradient(to top,var(--grid-line-color) 0,var(--grid-line-color) 1px,transparent 1px,transparent 44px);
  position:relative;overflow:hidden;
}

.kpi-stat{
  background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-lg);
  padding:18px 20px;font-family:var(--font-body);display:flex;flex-direction:column;gap:10px;flex:1 1 0;min-width:0;
}
.kpi-stat-label{font-size:var(--text-2xs);text-transform:uppercase;letter-spacing:var(--ls-wide);color:var(--text-tertiary);font-family:var(--font-mono);}
.kpi-stat-value{
  font-family:var(--font-display);font-size:var(--text-xl);font-weight:var(--fw-semibold);color:var(--text-primary);
  font-feature-settings:'tnum' 1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;
}
.kpi-stat-delta{font-family:var(--font-mono);font-size:var(--text-xs);font-weight:var(--fw-medium);color:var(--text-tertiary);}
.kpi-stat-delta.is-positive{color:var(--positive);}
.kpi-stat-delta.is-negative{color:var(--negative);}

.signal-card{
  background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-lg);
  padding:16px;font-family:var(--font-body);display:flex;align-items:center;gap:14px;min-width:0;
}
.signal-card.is-long{border-left:2px solid var(--positive);}
.signal-card.is-short{border-left:2px solid var(--negative);}
.signal-card-icon{
  width:34px;height:34px;border-radius:var(--radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;
}
.signal-card.is-long .signal-card-icon{background:var(--positive-soft);color:var(--positive);}
.signal-card.is-short .signal-card-icon{background:var(--negative-soft);color:var(--negative);}
.signal-card-body{flex:1 1 auto;min-width:0;overflow:hidden;}
.signal-card-symbol{font-family:var(--font-mono);font-size:var(--text-sm);font-weight:var(--fw-semibold);color:var(--text-primary);}
.signal-card-direction{font-size:var(--text-2xs);text-transform:uppercase;font-family:var(--font-mono);letter-spacing:var(--ls-wide);}
.signal-card.is-long .signal-card-direction{color:var(--positive);}
.signal-card.is-short .signal-card-direction{color:var(--negative);}
.signal-card-meta{font-size:var(--text-xs);color:var(--text-tertiary);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.signal-card-price{text-align:right;flex-shrink:0;font-family:var(--font-mono);font-size:var(--text-sm);color:var(--text-primary);}
.signal-card-confidence{font-size:var(--text-2xs);color:var(--text-tertiary);text-align:right;}

/* ---------- Card primitive ---------- */

.card{background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-lg);}
.card-header{padding:16px 20px;border-bottom:1px solid var(--border-default);font-family:var(--font-display);font-weight:var(--fw-semibold);}
/* .card-title was already used by several templates but never defined, so every
   card header was styled only by whatever heading level it happened to use.
   Defining it makes the headers match across the site regardless of tag. */
.card-title{margin:0;font-size:var(--text-lg);font-weight:var(--fw-semibold);display:flex;align-items:center;gap:8px;}
.card-title [data-lucide],.card-title svg{width:18px;height:18px;flex-shrink:0;}
.card-subtitle{margin:4px 0 0;font-family:var(--font-body);font-size:var(--text-sm);font-weight:var(--fw-regular);color:var(--text-tertiary);}
.card-body{padding:20px;}

/* A card with nothing in it reads as broken. Say why it is empty instead of
   leaving a blank rectangle -- "no signals yet today" is information, an empty
   box is a bug report. */
.empty-state{
  display:flex;align-items:center;justify-content:center;gap:8px;
  min-height:88px;margin:0;padding:16px;text-align:center;
  color:var(--text-tertiary);font-size:var(--text-sm);
}
.empty-state i[data-lucide],.empty-state svg{width:16px;height:16px;flex-shrink:0;}
.card-footer{padding:16px 20px;border-top:1px solid var(--border-default);}
.card--danger .card-header{color:var(--negative);border-bottom-color:var(--negative-soft);background:var(--negative-soft);}

/* ---------- Alerts (Django messages framework) ---------- */

.alert{padding:12px 16px;border-radius:var(--radius-md);border:1px solid var(--border-default);font-size:var(--text-sm);}
.alert-success{background:var(--positive-soft);color:var(--positive);border-color:var(--positive-soft);}
.alert-error{background:var(--negative-soft);color:var(--negative);border-color:var(--negative-soft);}
.alert-info{background:var(--info-soft);color:var(--info);border-color:var(--info-soft);}
.alert-warning{background:var(--accent-soft);color:var(--accent-1);border-color:var(--accent-soft-strong);}
.alert-debug{background:var(--surface-elevated);color:var(--text-tertiary);}

/* ---------- Layout primitives (mechanical Bootstrap-grid replacement) ---------- */

/* No padding-inline: .app-content already supplies the horizontal gutter, and
   having both meant every container page was inset 48px a side while the pages
   without a container were inset 24px. One gutter, one source. */
.layout-container{max-width:var(--container-max);margin-inline:auto;}

/* Opt out of the cap entirely. For the pages whose whole job is a canvas that
   scrolls -- charts, TPO grids -- where "readable line length" is not a concept
   that applies and every pixel is chart. */
.layout-container.is-full{max-width:none;}

/* CSS Grid rather than a percentage-based flex row: fr tracks divide the
   remaining space exactly, so N equal columns can't round up and overflow
   into an unwanted wrap the way flex-basis percentages can (e.g. three
   33.33% flex columns summing to just over 100% after rounding). */
.layout-row{display:grid;grid-template-columns:repeat(12,1fr);gap:var(--grid-col-gap);align-items:start;}
[class*="layout-col-"]{grid-column:span 12;margin-bottom:0;}

.layout-col-1{grid-column:span 1;} .layout-col-2{grid-column:span 2;} .layout-col-3{grid-column:span 3;}
.layout-col-4{grid-column:span 4;} .layout-col-5{grid-column:span 5;} .layout-col-6{grid-column:span 6;}
.layout-col-7{grid-column:span 7;} .layout-col-8{grid-column:span 8;} .layout-col-9{grid-column:span 9;}
.layout-col-10{grid-column:span 10;} .layout-col-11{grid-column:span 11;} .layout-col-12{grid-column:span 12;}

@media (min-width:768px){
  [class*="layout-col-md-"]{grid-column:span 12;}
  .layout-col-md-1{grid-column:span 1;} .layout-col-md-2{grid-column:span 2;} .layout-col-md-3{grid-column:span 3;}
  .layout-col-md-4{grid-column:span 4;} .layout-col-md-5{grid-column:span 5;} .layout-col-md-6{grid-column:span 6;}
  .layout-col-md-7{grid-column:span 7;} .layout-col-md-8{grid-column:span 8;} .layout-col-md-9{grid-column:span 9;}
  .layout-col-md-10{grid-column:span 10;} .layout-col-md-11{grid-column:span 11;} .layout-col-md-12{grid-column:span 12;}
}

.stack-1>*+*{margin-top:var(--space-1);} .stack-2>*+*{margin-top:var(--space-2);}
.stack-3>*+*{margin-top:var(--space-3);} .stack-4>*+*{margin-top:var(--space-4);}
.stack-5>*+*{margin-top:var(--space-5);} .stack-6>*+*{margin-top:var(--space-6);}
.stack-8>*+*{margin-top:var(--space-8);}
.cluster{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-3);}

/* ---------- Fallback element-level styling ----------
   Several pages render forms via Django's Form.as_p() (bare <input>/<select>
   with no classes) and tables via server-side HTML generation (e.g. pandas
   DataFrame.to_html()) that this project doesn't control per-template. Class
   selectors above always win on specificity, so this is a safe base layer
   rather than a conflict. */
form p{margin-bottom:12px;}
form p label{display:block;font-size:var(--text-xs);color:var(--text-secondary);margin-bottom:4px;}
input[type="text"],input[type="password"],input[type="email"],input[type="number"],
input[type="search"],input[type="date"],input[type="tel"],input[type="url"],
textarea,select{
  font-family:var(--font-body);font-size:var(--text-sm);color:var(--text-primary);
  background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-md);
  padding:9px 12px;
}
input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,
input[type="number"]:focus,input[type="search"]:focus,textarea:focus,select:focus{
  outline:none;border-color:var(--accent-1);box-shadow:var(--shadow-focus);
}
input[type="submit"],input[type="button"]{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  font-family:var(--font-body);font-weight:var(--fw-medium);font-size:var(--text-sm);
  padding:9px 16px;border-radius:var(--radius-md);cursor:pointer;
  background:var(--accent-1);color:var(--text-on-accent);border:1px solid var(--accent-1);
}
input[type="submit"]:hover,input[type="button"]:hover{background:var(--accent-2);border-color:var(--accent-2);}

table:not([class]),table.dataframe{width:100%;border-collapse:collapse;font-family:var(--font-body);font-size:var(--text-sm);}
table:not([class]) th,table.dataframe th{
  text-align:left;padding:10px 14px;font-size:var(--text-2xs);text-transform:uppercase;
  letter-spacing:var(--ls-wide);color:var(--text-tertiary);font-weight:var(--fw-medium);
  border-bottom:1px solid var(--border-strong);font-family:var(--font-mono);
}
table:not([class]) td,table.dataframe td{padding:11px 14px;color:var(--text-secondary);border-bottom:1px solid var(--border-default);}
table:not([class]) tbody tr:hover,table.dataframe tbody tr:hover{background:var(--surface-card-hover);}
