/* These styles are generated from project.scss. */

/* ========================================
   VIOLET DESIGN SYSTEM — Global Tokens
   ======================================== */

:root {
  /* Sidebar — estado activo derivado del color del tenant (var --color-primary) */
  --sidebar-bg: #160730;
  --sidebar-logo-bg: #0D0520;
  --sidebar-text: rgba(255,255,255,0.45);
  --sidebar-text-active: color-mix(in srgb, var(--color-primary) 35%, white);
  --sidebar-item-active-bg: color-mix(in srgb, var(--color-primary) 18%, transparent);
  --sidebar-item-active-border: var(--color-primary);
  --sidebar-icon: rgba(255,255,255,0.3);
  --sidebar-icon-active: var(--color-primary);
  --sidebar-separator: rgba(255,255,255,0.06);
  --sidebar-section-label: rgba(255,255,255,0.3);

  /* Page & Cards */
  /* Tinted canvas so white cards read as surfaces. Derived from the brand
     colour, not a fixed lavender, so a white-label tenant gets its own tint.

     6%, not 3%. At 3% the canvas sat 1.5% away from the white of a card,
     which is to say it was not a canvas at all: every card needed a grey
     hairline drawn around it to be seen, and ~200 rectangles outlined in
     #e5e7eb is what makes a product read as a form rather than a surface.
     At 6% the GROUND does the separating, the hairline comes off, and the
     sidebar (tinted from the same brand colour) stops floating on an almost
     white page. Measured against Perception Point's console, which does the
     same thing with a grey: the contrast between ground and card is the
     cheapest premium cue there is. Revert by putting 3% back. */
  --page-bg: color-mix(in srgb, var(--color-primary) 6%, #ffffff);
  --card-bg: #FFFFFF;
  /* A card has NO edge. The tinted canvas above is what separates it, so an
     outline would be the same boundary drawn twice — and a brand-tinted one
     would spend the accent on ~200 rectangles at once, which is how an accent
     stops meaning anything. The token stays (rather than the rules losing
     their `border` declaration) so the 1px still occupies its space and
     nothing shifts, and so `.v-card:hover` can still bring an edge back for
     the one card you are pointing at. Read by .v-card / .v-card-flat below
     and by two inline styles in violet/audit_detail.html. */
  --card-border: transparent;

  /* Buttons. The primary button is FLAT var(--color-primary) and carries no
     shadow: a brand-hued glow under the one filled button on a screen is
     decoration, and it is the loudest 'generated' tell there is.
     There are no --btn-outline-* tokens here: .btn-violet-outline, their only
     reader, is gone — it hard-coded the brand violet as a literal, which a
     white-labelled tenant cannot repaint, and lifted on hover. Nothing in the
     product referenced it. The outline button people actually use is
     components/button.html. */
  --btn-primary-bg: var(--color-primary);
  --btn-primary-shadow: none;
  --btn-primary-hover-shadow: none;

  /* Inputs */
  --input-border: #E5E7EB;
  --input-focus-border: var(--color-primary);
  --input-focus-ring: 0 0 0 3px color-mix(in srgb, var(--color-primary) 18%, transparent);

  /* Card extras */
  --card-radius: 12px;

  /* Severity — Very critical (above Critical) */
  --very-critical-bg: rgba(127,29,29,0.14);
  --very-critical-color: #7F1D1D;
  --very-critical-border: rgba(127,29,29,0.35);
  --very-critical-accent: #7F1D1D;

  /* Severity — Critical */
  --critical-bg: rgba(220,38,38,0.12);
  --critical-color: #DC2626;
  --critical-border: rgba(220,38,38,0.25);
  --critical-accent: #DC2626;

  /* Severity — High */
  --high-bg: rgba(234,88,12,0.12);
  --high-color: #EA580C;
  --high-border: rgba(234,88,12,0.25);
  --high-accent: #EA580C;

  /* Severity — Medium */
  --medium-bg: rgba(202,138,4,0.12);
  --medium-color: #CA8A04;
  --medium-border: rgba(202,138,4,0.25);
  --medium-accent: #CA8A04;

  /* Severity — Low */
  --low-bg: rgba(22,163,74,0.12);
  --low-color: #16A34A;
  --low-border: rgba(22,163,74,0.25);
  --low-accent: #16A34A;

  /* Severity — Info (antes morado) -> color del tenant */
  --info-bg: color-mix(in srgb, var(--color-primary) 10%, white);
  --info-color: color-mix(in srgb, var(--color-primary) 55%, black);
  --info-border: color-mix(in srgb, var(--color-primary) 20%, white);

  /* ── MODULE ACCENTS ──────────────────────────────────────────────────────
     Four hues, all mixed FROM the tenant's own --color-primary rather than
     fixed brand colours, so a white-labelled workspace gets four
     distinguishable modules in its own palette instead of somebody else's.
     oklch keeps the mix from going muddy the way an sRGB blend between
     distant hues does.

     They lived in an inline <style> inside sidebar.html, which meant the one
     other consumer — components/_module_deck_rows.html — depended on the
     sidebar having been rendered on the page to resolve its own colours.
     They are tokens; tokens live in the token file.

     --vm-accent is the CURRENT module's accent. It defaults to the brand, and
     the sidebar overrides it per module block, so anything that paints from
     it is correct without knowing which module it is in: an active row in the
     global spine, in Settings, or on a screen owned by no module is violet,
     and an active row inside GRC is GRC blue. Nothing is ever left with no
     accent at all. */
  --vm-accent-audit: var(--color-primary);
  --vm-accent-grc:   color-mix(in oklch, var(--color-primary) 55%, #0ea5e9);
  --vm-accent-ir:    color-mix(in oklch, var(--color-primary) 55%, #f43f5e);
  --vm-accent-tprm:  color-mix(in oklch, var(--color-primary) 55%, #10b981);

  --vm-accent-audit-soft: color-mix(in srgb, var(--vm-accent-audit) 15%, white);
  --vm-accent-grc-soft:   color-mix(in srgb, var(--vm-accent-grc) 15%, white);
  --vm-accent-ir-soft:    color-mix(in srgb, var(--vm-accent-ir) 15%, white);
  --vm-accent-tprm-soft:  color-mix(in srgb, var(--vm-accent-tprm) 15%, white);

  --vm-accent: var(--color-primary);
  --vm-accent-soft: color-mix(in srgb, var(--color-primary) 15%, white);

  /* Module accent colors */
  --module-vm: var(--color-primary);
  --module-vm-light: color-mix(in srgb, var(--color-primary) 50%, white);
  --module-tprm: #0D9488;
  --module-tprm-light: #5EEAD4;
  --module-threatintel: #DC2626;
  --module-threatintel-light: #FCA5A5;
  --module-governance: #854F0B;
  --module-governance-light: #FCD34D;
}

/* Severity badges — standardized.
   Single source of truth: the --*-bg/-color/-border tokens defined in :root above.
   Do NOT hardcode severity hex here — every class that paints a severity reads
   the same token, so a given severity renders identically everywhere. */
.severity-very-critical { background: var(--very-critical-bg); color: var(--very-critical-color); border: 1px solid var(--very-critical-border); }
.severity-critical { background: var(--critical-bg); color: var(--critical-color); border: 1px solid var(--critical-border); }
.severity-high { background: var(--high-bg); color: var(--high-color); border: 1px solid var(--high-border); }
.severity-medium { background: var(--medium-bg); color: var(--medium-color); border: 1px solid var(--medium-border); }
.severity-low { background: var(--low-bg); color: var(--low-color); border: 1px solid var(--low-border); }
.severity-info { background: var(--info-bg); color: var(--info-color); border: 1px solid var(--info-border); }

/* ======================================== */

/* Estilos personalizados para proyecto Trauma */

/* Modern, geometric font stack - Satoshi for cutting-edge SaaS applications */
* {
  font-family: 'Satoshi', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

/* Minimalist base styles */
body {
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: -0.01em;
}

/* Typography hierarchy */
h1, h2, h3, h4, h5, h6 {
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.25;
}

/* Minimalist button styles */
button, .btn {
  font-weight: 500;
  letter-spacing: -0.01em;
}

/* ========================================
   GLOBAL CURSOR STYLES FOR INTERACTIVE ELEMENTS
   ======================================== */

/* All clickable elements should have pointer cursor */
button,
.btn,
a[href],
[role="button"],
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"],
input[type="checkbox"],
input[type="radio"],
select,
option,
[onclick],
[x-on\:click],
[data-modal-target],
[data-modal-toggle],
[data-collapse-toggle],
[data-dropdown-toggle],
[data-tab-target],
.clickable,
.cursor-pointer {
  cursor: pointer !important;
}

/* HTMX verbs mean "clickable" only when the element reacts to a CLICK.
 *
 * `[hx-get]` used to be in the list above, and `cursor` is an INHERITED
 * property: every self-refreshing WRAPPER — the findings table container
 * (hx-trigger="listChanged"), the finding detail root, any hx-trigger="load"
 * skeleton — handed a pointer down to its entire subtree, so whole pages read
 * as one giant button. `hx-boost` was worse: it sits on containers precisely
 * to boost the links INSIDE them, and those links already match `a[href]`.
 *
 * HTMX's default trigger for a non-form element IS click, so: no hx-trigger
 * (on something that isn't a form/field) or a trigger that mentions click →
 * pointer. Anything driven by load / polling / a custom event → left alone.
 */
[hx-get]:not([hx-trigger]):not(form):not(input):not(select):not(textarea),
[hx-post]:not([hx-trigger]):not(form):not(input):not(select):not(textarea),
[hx-put]:not([hx-trigger]):not(form):not(input):not(select):not(textarea),
[hx-patch]:not([hx-trigger]):not(form):not(input):not(select):not(textarea),
[hx-delete]:not([hx-trigger]):not(form):not(input):not(select):not(textarea),
[hx-get][hx-trigger*="click"],
[hx-post][hx-trigger*="click"],
[hx-put][hx-trigger*="click"],
[hx-patch][hx-trigger*="click"],
[hx-delete][hx-trigger*="click"] {
  cursor: pointer !important;
}

/* Also apply to pseudo-elements and specific use cases */
.table tbody tr:hover,
.pagination li a,
.pagination li span,
.close,
[aria-label="Close"],
.sortable th,
[data-sort] {
  cursor: pointer !important;
}

/* Disabled states should show not-allowed cursor */
button:disabled,
.btn:disabled,
input:disabled,
select:disabled,
textarea:disabled,
[disabled],
.disabled {
  cursor: not-allowed !important;
}

/* Loading states */
.loading,
[data-loading] {
  cursor: wait !important;
}

/* ======================================== */

/* Clean focus states */
button:focus,
a:focus,
input:focus,
select:focus,
textarea:focus {
  outline: 2px solid rgba(59, 130, 246, 0.5);
  outline-offset: 2px;
}

/* Smooth transitions for all interactive elements */
button,
a,
input,
select,
textarea {
  transition: all 0.2s ease-in-out;
}

/* Minimalist scrollbar */
::-webkit-scrollbar {
  width: 6px;
}

::-webkit-scrollbar-track {
  background: #f1f5f9;
}

::-webkit-scrollbar-thumb {
  background: #cbd5e1;
  border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
  background: #94a3b8;
}

/* Estilos personalizados adicionales para el proyecto */
.prose img {
  max-width: 100%;
  height: auto;
  border-radius: 0.375rem;
}


/* Estilos que usan variables de branding */
.btn-primary {
  background-color: var(--color-primary);
  color: white;
}

.btn-primary:hover {
  background-color: var(--color-secondary);
}

/* Estilos de datepicker y elementos de formulario */
.flatpickr-day.selected {
  background: var(--color-primary) !important;
  border-color: var(--color-primary) !important;
}

.flatpickr-day.selected:hover {
  background: var(--color-secondary) !important;
  border-color: var(--color-secondary) !important;
}

.flatpickr-day.selected:focus {
  background: var(--color-secondary) !important;
  border-color: var(--color-secondary) !important;
}

.flatpickr-day.selected:active {
  background: var(--color-secondary) !important;
  border-color: var(--color-secondary) !important;
}

.flatpickr-day.selected:focus-visible {
  background: var(--color-secondary) !important;
  border-color: var(--color-secondary) !important;
}

.flatpickr-calendar {
  border-radius: 0.75rem;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}

.flatpickr-day.today {
  background: var(--color-accent) !important;
  color: white;
  border-radius: 9999px;
}

.flatpickr-months .flatpickr-month {
  font-weight: 600;
}

.flatpickr-weekday {
  color: #4b5563;
  font-size: 0.875rem;
}


/* ========================================
   ALPINE.JS & MODAL FIXES
   ======================================== */

/* Alpine.js - Ocultar elementos con x-cloak hasta que Alpine se inicialice */
[x-cloak] {
  display: none !important;
}

/* Mejorar rendimiento de transiciones */
.modal-backdrop {
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/* Prevenir scroll del body cuando el modal está abierto */
body.modal-open {
  overflow: hidden;
}

/* ========================================
   HTMX INDICATORS FOR FILTERS
   ======================================== */

/* Show loading indicator when HTMX request is in progress */
.htmx-request .filter-loading {
    display: inline !important;
}

/* Default state: the indicator is hidden until the request starts */
.filter-loading {
    display: none;
}

/* ========================================
   FORM FIELD ENHANCEMENTS
   ======================================== */

/* Custom Radio Button Styles */
input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  width: 1rem;
  height: 1rem;
  border: 2px solid #d1d5db;
  border-radius: 50%;
  outline: none;
  transition: all 0.2s ease-in-out;
  position: relative;
  background-color: white;
}

input[type="radio"]:hover {
  border-color: var(--color-primary, #3b82f6);
}

input[type="radio"]:checked {
  border-color: var(--color-primary, #3b82f6);
  background-color: var(--color-primary, #3b82f6);
}

input[type="radio"]:checked::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background-color: white;
}

input[type="radio"]:focus {
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
}

/* Custom Checkbox Styles */
input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  width: 1.25rem;
  height: 1.25rem;
  border: 2px solid #d1d5db;
  border-radius: 0.25rem;
  outline: none;
  transition: all 0.2s ease-in-out;
  position: relative;
  background-color: white;
}

input[type="checkbox"]:hover {
  border-color: var(--color-primary, #3b82f6);
}

input[type="checkbox"]:checked {
  border-color: var(--color-primary, #3b82f6);
  background-color: var(--color-primary, #3b82f6);
}

input[type="checkbox"]:checked::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(45deg);
  width: 5px;
  height: 9px;
  border: solid white;
  border-width: 0 2px 2px 0;
}

input[type="checkbox"]:focus {
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
}

/* Textarea Enhancement */
textarea {
  font-family: inherit;
  line-height: 1.5;
}

textarea:focus {
  outline: none;
}

/* Select Enhancement */
select {
  background-image: none;
}

select option {
  padding: 0.5rem;
}

/* File Input Enhancement */
input[type="file"]::file-selector-button {
  padding: 0.5rem 1rem;
  border: 1px solid #d1d5db;
  border-radius: 0.375rem;
  background-color: white;
  color: #374151;
  font-weight: 500;
  font-size: 0.875rem;
  cursor: pointer;
  transition: all 0.2s ease-in-out;
}

input[type="file"]::file-selector-button:hover {
  background-color: #f9fafb;
  border-color: var(--color-primary, #3b82f6);
}

/* Form Field Error States */
input.error,
textarea.error,
select.error {
  border-color: #ef4444 !important;
}

/* Form Field Success States */
input.success,
textarea.success,
select.success {
  border-color: #10b981 !important;
}

/* Disabled Field States */
input:disabled,
textarea:disabled,
select:disabled {
  background-color: #f3f4f6;
  cursor: not-allowed;
  opacity: 0.6;
}

/* Focus Within Enhancement for Textarea Container */
.focus-within\:border-\[var\(--color-primary\)\]:focus-within {
  border-color: var(--color-primary, #3b82f6);
}

/* Smooth Transitions for Form Elements */
input,
textarea,
select {
  transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
}

/* Better Number Input Appearance */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  opacity: 0.5;
}

input[type="number"]:hover::-webkit-inner-spin-button,
input[type="number"]:hover::-webkit-outer-spin-button {
  opacity: 1;
}

/* Placeholder Enhancement.
   `:not(.placeholder-transparent)` is not decoration: Tailwind v4 emits its
   utilities inside `@layer utilities`, and an UNLAYERED rule like this one
   beats a layered one whatever the specificity. So this bare ::placeholder was
   overriding `.placeholder-transparent` on every floating-label field, and the
   grey placeholder showed through underneath the label that was sitting on top
   of it — the two texts overlapped in every _field_box in the product. */
:not(.placeholder-transparent)::placeholder {
  color: #9ca3af;
  opacity: 1;
}

/* ========================================
   FASE 1: ENHANCED DESIGN SYSTEM
   ======================================== */

/* ── Typography Hierarchy ── */
.text-overline { font-size: 0.625rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; line-height: 1.6; }

/* ── Enhanced Card System ── */
.v-card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--vs-radius-lg);
  transition: border-color 0.15s ease;
}
.v-card:hover {
  border-color: var(--vs-rule-2);
}
.v-card-flat {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--vs-radius-lg);
  transition: border-color 0.15s ease;
}

/* KPI cards. Opaque, not glass: a card is not an overlay, and the blur cost
   a compositing layer on every dashboard tile. */
.v-glass {
  background: var(--vs-surface);
  /* Transparent, like every other card: the tinted canvas is the separation.
     See --card-border. Kept as a 1px so nothing shifts. */
  border: 1px solid transparent;
  border-radius: var(--vs-radius-lg);
}
html.dark .v-glass {
  background: #1e2130;
  border-color: rgba(255,255,255,0.06);
}

/* ── Badges ── */
/* Only the two shapes the markup actually renders survive: the info tint on
   the SLA list, and the count bubble on the bulk bar. */
.v-badge-info { background: var(--info-bg); color: var(--info-color); border: 1px solid var(--info-border); }
.v-badge-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.375rem;
  border-radius: 9999px;
  font-size: 0.625rem;
  font-weight: 700;
  background: var(--critical-color);
  color: #fff;
}

/* ── Animation ── */
/* Entrance animations (fade-up, count-up, fill, bounce-in) and the infinite
   badge/dot pulses are gone: content that slides in on every navigation reads
   as a demo, and a pulse that does not mean "loading" means nothing. The
   skeleton shimmer below is the one that survives, because it IS loading. */

/* Shimmer for skeleton loading */
@keyframes v-shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.v-skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: v-shimmer 1.5s ease-in-out infinite;
  border-radius: 6px;
}
html.dark .v-skeleton {
  background: linear-gradient(90deg, #252838 25%, #2d3148 50%, #252838 75%);
  background-size: 200% 100%;
}

/* ── Table Density Toggle ── */
.v-table-compact th { padding: 0.25rem 0.5rem !important; font-size: 0.625rem !important; }
.v-table-compact td { padding: 0.25rem 0.5rem !important; font-size: 0.8125rem !important; }
.v-table-comfortable th { padding: 0.625rem 0.75rem !important; }
.v-table-comfortable td { padding: 0.5rem 0.75rem !important; }

/* ── Enhanced Empty State ── */
.v-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 3rem 1.5rem;
  text-align: center;
}
.v-empty-state-icon {
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1rem;
  /* Flat tint from the brand colour: the diagonal purple gradient was the
     one thing on an empty screen, and it read as generated. */
  background: color-mix(in srgb, var(--color-primary) 8%, white);
}
.v-empty-state-icon i {
  font-size: 1.5rem;
  color: color-mix(in srgb, var(--color-primary) 55%, white);
}
.v-empty-state-title {
  font-size: 1rem;
  font-weight: 600;
  color: #374151;
  margin-bottom: 0.25rem;
}
.v-empty-state-text {
  font-size: 0.875rem;
  color: #9CA3AF;
  max-width: 320px;
  margin-bottom: 1.25rem;
}
.v-empty-state-action {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1.25rem;
  border-radius: 10px;
  font-size: 0.875rem;
  font-weight: 500;
  background: var(--btn-primary-bg);
  color: #fff;
  box-shadow: var(--btn-primary-shadow);
  transition: all 0.2s;
}
.v-empty-state-action:hover {
  background-color: color-mix(in srgb, var(--color-primary) 92%, black);
}

/* One LINE, for a panel that happens to be empty. The block above is the
   right answer for a whole screen with nothing on it; on an area detail with
   five roll-up panels it was five 200px voids stacked down the page. */
.v-empty-state--line {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 0.5rem;
  padding: 0.625rem 1rem;
  text-align: left;
}
.v-empty-state--line i { font-size: 0.8125rem; }
.v-empty-state--line .v-empty-state-title {
  font-size: 0.8125rem;
  font-weight: 500;
  color: #6b7280;
  margin-bottom: 0;
}
.v-empty-state--line .v-empty-state-text {
  font-size: 0.8125rem;
  max-width: none;
  margin-bottom: 0;
}
.v-empty-state--line .v-empty-state-action {
  margin-left: auto;
  padding: 0.25rem 0.75rem;
  font-size: 0.75rem;
  border-radius: 8px;
  box-shadow: none;
}

/* ── Help Tooltip (?) ── */
.v-help-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-primary) 8%, white);
  color: var(--color-primary);
  font-size: 0.5625rem;
  font-weight: 700;
  cursor: help;
  transition: background 0.15s ease, border-color 0.15s ease;
  border: 1px solid color-mix(in srgb, var(--color-primary) 15%, white);
  vertical-align: middle;
  margin-left: 0.25rem;
}
.v-help-trigger:hover {
  background: color-mix(in srgb, var(--color-primary) 15%, white);
  border-color: color-mix(in srgb, var(--color-primary) 30%, white);
}

/* ── Bulk Selection Bar ── */
.v-bulk-bar {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%) translateY(100px);
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.625rem 1.25rem;
  background: #1e2130;
  color: #fff;
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.25), 0 0 0 1px rgba(255,255,255,0.1);
  font-size: 0.875rem;
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s linear 0.3s;
  /* Hidden means hidden: sliding it 100px down left a "0 selected" bar parked
     just under the fold — still focusable, still read out by screen readers, and
     it surfaced on top of the page in full-page captures and printing. */
  visibility: hidden;
  pointer-events: none;
}
.v-bulk-bar.visible {
  transform: translateX(-50%) translateY(0);
  visibility: visible;
  pointer-events: auto;
  transition-delay: 0s;
}
.v-bulk-bar-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.375rem 0.75rem;
  border-radius: 8px;
  font-size: 0.8125rem;
  font-weight: 500;
  background: rgba(255,255,255,0.1);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.15);
  transition: all 0.15s ease;
}
.v-bulk-bar-btn:hover {
  background: rgba(255,255,255,0.2);
  border-color: rgba(255,255,255,0.3);
}
.v-bulk-bar-divider {
  width: 1px;
  height: 1.5rem;
  background: rgba(255,255,255,0.15);
}

/* ── Command Palette ── */
.v-command-palette {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 15vh;
  background: rgba(0,0,0,0.4);
  backdrop-filter: blur(4px);
}
.v-command-box {
  width: 100%;
  max-width: 560px;
  background: #fff;
  border-radius: var(--vs-radius-lg);
  box-shadow: 0 16px 64px rgba(0,0,0,0.2);
  overflow: hidden;
  border: 1px solid var(--vs-rule);
}
html.dark .v-command-box {
  background: #1e2130;
  border-color: #2d3148;
}
.v-command-input {
  width: 100%;
  padding: 1rem 1.25rem 1rem 3rem;
  border: none;
  border-bottom: 1px solid var(--vs-rule);
  font-size: 1rem;
  font-weight: 400;
  background: transparent;
  outline: none;
}
.v-command-results {
  max-height: 360px;
  overflow-y: auto;
  padding: 0.5rem;
}
.v-command-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.625rem 0.75rem;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.1s ease;
}
.v-command-item:hover,
.v-command-item.active {
  background: color-mix(in srgb, var(--color-primary) 6%, white);
}
/* The icon keeps its 32px slot so every row lines up, but not the coloured
   rounded tile behind it: a tile on each row makes the list read as chrome. */
.v-command-item-icon {
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--vs-ink-3);
  font-size: 0.75rem;
  flex-shrink: 0;
}
.v-command-item-text {
  flex: 1;
  min-width: 0;
}
.v-command-item-title {
  font-size: 0.875rem;
  font-weight: 500;
  color: #374151;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
html.dark .v-command-item-title { color: #e2e8f0; }
.v-command-item-desc {
  font-size: 0.75rem;
  color: #9CA3AF;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.v-command-kbd {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.375rem;
  border-radius: 4px;
  font-size: 0.6875rem;
  font-weight: 500;
  background: rgba(107,114,128,0.1);
  color: #6B7280;
  border: 1px solid rgba(107,114,128,0.2);
  font-family: ui-monospace, monospace;
}

/* ── Accessibility ── */
*:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

/* A form control that asks for `sr-only` wants to be GONE, not shrunk.
   The custom checkbox and radio above are written as `input[type="checkbox"]`
   and `input[type="radio"]` — attribute selectors, which outrank a bare class
   whatever the order — so a screen-reader-only input kept its 20px box, its
   border, its hover colour and its tick, and `clip` does not apply to a
   `position: relative` element. The result was a second, fully visible control
   sitting next to the one it was meant to be hiding behind: that is what made
   the switches in Branding ▸ Modules read as two buttons on top of each other,
   with a different outcome depending on which pixel you hit.

   Same specificity as the rules above (0,1,1) and further down the file, so it
   wins without `!important`. */
input.sr-only,
select.sr-only,
textarea.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  border: 0;
  background: none;
  appearance: none;
  -webkit-appearance: none;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* ========================================
   #137 MINIMUM FONT SIZE 11px
   ======================================== */

/* Override text-[9px] and text-[10px] globally to enforce 11px minimum */
[class*="text-\[9px\]"] { font-size: 11px !important; }
[class*="text-\[10px\]"] { font-size: 11px !important; }

/* ========================================
   #141 HTMX SWAP TRANSITIONS
   ======================================== */
.htmx-swapping { opacity: 0; transition: opacity 150ms ease-out; }
.htmx-settling { opacity: 1; transition: opacity 150ms ease-in; }

/* ========================================
   #143 BUTTON TONE UNIFICATION
   ======================================== */
.v-btn-primary {
  background: var(--color-primary);
  color: white;
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
  font-weight: 500;
  font-size: 0.875rem;
  transition: all 0.2s;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.v-btn-primary:hover { filter: brightness(0.94); }

/* ── Global Table Consistency ──
   Ensures all tables inside #content-area have the same visual style,
   regardless of whether they use the generic table component or not.  */
#content-area table:not(.fc-scrollgrid):not(.flatpickr-calendar *) thead th {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--dm-muted, #6b7280);
  padding: 10px 12px;
  background: var(--dm-bg-alt, #f9fafb);
  border-bottom: 1px solid var(--dm-border, #e5e7eb);
  white-space: nowrap;
}
#content-area table:not(.fc-scrollgrid) tbody td {
  padding: 10px 12px;
  font-size: 13px;
  vertical-align: middle;
  border-bottom: 1px solid var(--dm-border-light, #f3f4f6);
}
#content-area table:not(.fc-scrollgrid) tbody tr {
  transition: background-color 0.1s ease;
}
#content-area table:not(.fc-scrollgrid) tbody tr:hover {
  background-color: var(--vs-surface-2);
}

/* ========================================
   MODERN SIDEBAR & TOPBAR ENHANCEMENTS
   ======================================== */

/* Scoped to #app-sidebar, NOT to every <aside>.
 *
 * These rules used to target the bare `aside` element, and `<aside>` is a
 * perfectly ordinary tag: the finding detail's right-hand column is one. So
 * `aside a[href] { position: relative }` beat Tailwind's `.absolute` on every
 * anchor inside it — that is why the "open in NVD" icon on the CVE card sat
 * outside its card instead of at its right edge. The nav styling belongs to
 * the navigation, so it now says which aside it means. */
#app-sidebar {
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

#app-sidebar nav {
  transition: all 0.2s ease-out;
}

/* Sidebar navigation item hover effects */
#app-sidebar a[href]:not([onclick]),
#app-sidebar button {
  position: relative;
  transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Tooltip improvements */
[x-data*="tooltipManager"] {
  z-index: 9999;
}

/* Modern rounded buttons */
#app-sidebar button,
header button {
  border-radius: 0.5rem;
  transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Topbar header styling */
header {
  transition: all 0.2s ease-out;
}

header button {
  transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Smooth chevron rotation */
.fa-chevron-down {
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Focus states for accessibility */
#app-sidebar button:focus,
#app-sidebar a:focus,
header button:focus,
header a:focus {
  outline: 2px solid transparent;
  outline-offset: 2px;
}

/* Icon color transitions */
i.fa-solid {
  transition: color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* User avatar styling */
[id="user-menu-button"] > div {
  background: var(--color-primary);
}

/* Dropdown shadow enhancement */
[id$="-dropdown"] {
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}

/* Responsive sidebar width on smaller screens */
@media (max-width: 768px) {
  aside {
    width: 16rem;
  }
}

/* ── Print styles ── */
@media print {
  aside, #topbar-header, .v-bulk-bar, .v-command-palette, #global-modal, #toast-container { display: none !important; }
  main { margin-left: 0 !important; }
  .v-card, .v-glass { box-shadow: none !important; border: 1px solid #ddd !important; }
}
