/* ============================================
   MyEnergy SQL - Global Styles
   Modern, Clean Design System
   ============================================ */

:root {
    /* Typography tokens — added 2026-08-21.
       Components built outside the standard .table class were each choosing
       their own sizes (.85, .87, .83, .8, .76, .74rem …), so new screens looked
       subtly different from the rest of the app. These name the sizes .table
       already uses, so a custom table can match without copying magic numbers.
       --fs-table-head matches .table th, --fs-table-cell matches .table td. */
    --fs-table-head: 0.75rem;
    --fs-table-cell: 0.875rem;
    --fs-meta: 0.75rem;      /* timestamps, counts, secondary labels */
    --fs-pill: 0.6875rem;    /* status chips */

    /* Primary Colors */
    --primary: #4f46e5;
    --primary-dark: #4338ca;
    --primary-light: #818cf8;
    
    /* Secondary Colors */
    --secondary: #0ea5e9;
    --secondary-dark: #0284c7;
    
    /* Status Colors */
    --success: #10b981;
    --warning: #f59e0b;
    --danger: #ef4444;
    --info: #3b82f6;
    
    /* Neutrals */
    --gray-50: #f9fafb;
    --gray-100: #f3f4f6;
    --gray-200: #e5e7eb;
    --gray-300: #d1d5db;
    --gray-400: #9ca3af;
    --gray-500: #6b7280;
    --gray-600: #4b5563;
    --gray-700: #374151;
    --gray-800: #1f2937;
    --gray-900: #111827;
    
    /* Layout */
    --sidebar-width: 260px;
    --header-height: 64px;
    --border-radius: 8px;
    --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
    --shadow: 0 4px 6px -1px rgba(0,0,0,0.1);
    --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1);
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    background: var(--gray-100);
}

body {
    font-family: var(--app-font, 'Inter'), -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: var(--gray-100);
    color: var(--gray-800);
    line-height: 1.6;
    margin: 0;
    min-height: 100vh;
}

a {
    color: var(--primary);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

/* ============================================
   Typography
   ============================================ */
h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    color: var(--gray-900);
    margin-bottom: 0.5rem;
}

h1 { font-size: 2rem; }
h2 { font-size: 1.5rem; }
h3 { font-size: 1.25rem; }
h4 { font-size: 1.125rem; }

.text-muted { color: var(--gray-500); }
.text-success { color: var(--success); }
.text-warning { color: var(--warning); }
.text-danger { color: var(--danger); }
.text-primary { color: var(--primary); }

/* ============================================
   Buttons
   ============================================ */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.625rem 1.25rem;
    font-size: 0.875rem;
    font-weight: 500;
    border-radius: var(--border-radius);
    border: none;
    cursor: pointer;
    transition: all 0.2s;
}

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

.btn-secondary {
    background: var(--gray-200);
    color: var(--gray-700);
}
.btn-secondary:hover {
    background: var(--gray-300);
}

.btn-success {
    background: var(--success);
    color: white;
}

.btn-danger {
    background: var(--danger);
    color: white;
}

.btn-outline {
    background: transparent;
    border: 1px solid var(--gray-300);
    color: var(--gray-700);
}
.btn-outline:hover {
    background: var(--gray-100);
}

.btn-sm {
    padding: 0.375rem 0.75rem;
    font-size: 0.8125rem;
    line-height: 1;
}

.btn-lg {
    padding: 0.875rem 1.75rem;
    font-size: 1rem;
}

.btn-icon {
    width: 36px;
    height: 36px;
    padding: 0;
    border-radius: 50%;
}

/* ============================================
   Forms
   ============================================ */
/* Tightened 2026-06-04: forms were bulky with too much vertical air.
   margin-bottom + row gap both reduced; flex-basis 180px lets ~4 narrow
   fields fit on a row in wide modals (1920+) and gracefully wraps on
   smaller widths. */
.form-group {
    margin-bottom: 0.6rem;
}
.form-row {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.form-row > .form-group {
    flex: 1 1 180px;
    min-width: 0;
}
@media (max-width: 560px) {
    .form-row > .form-group { flex-basis: 100%; }
}

.form-label {
    display: block;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--gray-700);
    margin-bottom: 0.375rem;
}

.form-control {
    width: 100%;
    padding: 0.625rem 0.875rem;
    font-size: 0.9375rem;
    border: 1px solid var(--gray-300);
    border-radius: var(--border-radius);
    background: white;
    transition: border-color 0.2s, box-shadow 0.2s;
}

.form-control:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}

.form-control::placeholder {
    color: var(--gray-400);
}

.form-select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%236b7280'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 1rem;
    padding-right: 2.5rem;
}

.form-check {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.form-check-input {
    width: 1rem;
    height: 1rem;
    accent-color: var(--primary);
}

.form-error {
    color: var(--danger);
    font-size: 0.8125rem;
    margin-top: 0.25rem;
}

/* ============================================
   Cards
   ============================================ */
.card {
    background: white;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--gray-200);
}

.card-header {
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--gray-200);
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.card-body {
    padding: 1.25rem;
}

.card-footer {
    padding: 1rem 1.25rem;
    border-top: 1px solid var(--gray-200);
    background: var(--gray-50);
}

/* ============================================
   Tables
   ============================================ */
.table-container,
.table-scroll {
    overflow-x: auto;
    overflow-y: auto;
    flex: 1;
    min-height: 0;
    max-width: 100%;
}

/* Table wrapper divs (#dataTable etc.) participate in flex chain */
#dataTable,
#brandsTable,
#modelsTable,
#providersTable,
#plansTable,
[id$="Table"]:not(.table) {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: auto;
}

/* When wrapper contains .table-container, only .table-container should scroll.
   This prevents two nested overflow:auto from breaking position:sticky */
#dataTable:has(> .table-container),
[id$="Table"]:not(.table):has(> .table-container) {
    overflow: hidden;
}

/*
 * A sticky header sticks to the container's PADDING box, not its border box.
 *
 * These scrolling containers are usually .card-body, which pads 1.25rem all
 * round -- so the header parked 20px below the container's top edge and the
 * rows scrolling past showed through the strip above it, looking like a row
 * drawn above the header. The same happened under a sticky pagination bar at
 * the bottom.
 *
 * The vertical padding goes, and the table carries the same breathing space as
 * a margin instead: it scrolls away like content, and the header lands flush
 * against the edge with nothing to peek through.
 */
[id$="Table"]:not(.table) {
    padding-top: 0;
    padding-bottom: 0;
}
[id$="Table"]:not(.table) > .table,
[id$="Table"]:not(.table) > .table-container,
[id$="Table"]:not(.table) > .table-scroll {
    margin-top: 1.25rem;
}

.table-scroll .table thead th,
.table-container .table thead th,
[id$="Table"]:not(.table) > .table thead th {
    position: sticky;
    z-index: 10;
    background: var(--gray-50);
}
.table-scroll .table thead tr:first-child th,
.table-container .table thead tr:first-child th,
[id$="Table"]:not(.table) > .table thead tr:first-child th {
    top: 0;
}
.table-scroll .table thead tr:nth-child(2) th,
.table-container .table thead tr:nth-child(2) th,
[id$="Table"]:not(.table) > .table thead tr:nth-child(2) th {
    top: var(--header-row-h, 37px);
    z-index: 9;
}

.table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
}

/* Global .table cell padding — driven by CSS vars written by
   AppSettings so each user can pick their preferred row density
   from the ⚙️ Settings panel (Comfortable / Default / Compact /
   Tight). Fallbacks match the "Default" preset so tables render
   correctly even if settings.js hasn't run yet. */
.table th {
    background: var(--gray-50);
    padding: var(--table-cell-pad-y, 0.60rem) var(--table-cell-pad-x, 0.80rem);
    text-align: left;
    /* The token, not the literal: Settings > Header Font Size overrides it
       app-wide. The fallback is the value this rule used to hard-code. */
    font-size: var(--fs-table-head, 0.75rem);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--gray-600);
    border-bottom: 1px solid var(--gray-200);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.table td {
    padding: var(--table-cell-pad-y, 0.60rem) var(--table-cell-pad-x, 0.80rem);
    border-bottom: 1px solid var(--gray-100);
    font-size: 0.875rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.table tbody tr:hover {
    background: var(--gray-50);
}

/* Keep <td class="table-actions"> as a table-cell so the row's height-syncing
   still applies. `display:flex` on the <td> itself breaks that — the cell
   stops stretching to match the row and buttons cluster at the top.
   Layout buttons inline with vertical-align:middle instead. */
.table-actions {
    text-align: center;
    vertical-align: middle;
    white-space: nowrap;
    overflow: visible;
}

.table-actions .btn,
.table-actions a {
    margin-right: 4px;
    vertical-align: middle;
}
.table-actions .btn:last-child,
.table-actions a:last-child {
    margin-right: 0;
}

.table-actions .btn.btn-sm,
.table td .btn.btn-sm {
    width: 32px;
    height: 32px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.85rem;
    flex-shrink: 0;
}

/* ============================================
   Date Inputs
   ============================================ */
input[type="date"],
input[type="month"] {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--gray-300);
    border-radius: var(--border-radius);
    font-size: 0.875rem;
    background: white;
    color: var(--gray-800);
    transition: border-color 0.2s, box-shadow 0.2s;
}
input[type="date"]:focus,
input[type="month"]:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator {
    cursor: pointer;
    opacity: 0.6;
    transition: opacity 0.2s;
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="month"]::-webkit-calendar-picker-indicator:hover {
    opacity: 1;
}

/* ============================================
   Badges
   ============================================ */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.625rem;
    font-size: 0.75rem;
    font-weight: 500;
    border-radius: 9999px;
}

.badge-success {
    background: #d1fae5;
    color: #065f46;
}

.badge-warning {
    background: #fef3c7;
    color: #92400e;
}

.badge-danger {
    background: #fee2e2;
    color: #991b1b;
}

.badge-info {
    background: #dbeafe;
    color: #1e40af;
}

.badge-gray {
    background: var(--gray-200);
    color: var(--gray-700);
}

/* ============================================
   Alerts
   ============================================ */
.alert {
    padding: 1rem 1.25rem;
    border-radius: var(--border-radius);
    margin-bottom: 1rem;
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

.alert-success {
    background: #d1fae5;
    color: #065f46;
    border: 1px solid #a7f3d0;
}

.alert-warning {
    background: #fef3c7;
    color: #92400e;
    border: 1px solid #fcd34d;
}

.alert-danger {
    background: #fee2e2;
    color: #991b1b;
    border: 1px solid #fca5a5;
}

.alert-info {
    background: #dbeafe;
    color: #1e40af;
    border: 1px solid #93c5fd;
}

/* ============================================
   Modal
   ============================================ */

/* Page frozen while a modal is open.
   Without this the page keeps its own scrollbar at the window edge while the
   modal body grows a second one just inside it -- two bars side by side, and
   the outer one scrolls the page behind the dialog. The padding stands in for
   the scrollbar that was just removed, so the page does not jump wider. */
body.modal-scroll-lock {
    overflow: hidden;
}


/* Fields only an administrator may change.
   The badge sits in the label so it reads as part of the field's name, and
   carries its explanation in title= so hovering says why. */
.restricted-badge {
    display: inline-block;
    margin-left: 6px;
    font-size: 0.78em;
    line-height: 1;
    cursor: help;
    vertical-align: middle;
    opacity: 0.75;
}
.restricted-badge:hover { opacity: 1; }
.restricted-badge.is-admin { opacity: 0.5; }

.form-control.field-restricted,
select.field-restricted {
    background: #f1f5f9;
    color: #64748b;
    border-color: #e2e8f0;
    cursor: not-allowed;
}


/* Date, time and datetime inputs need a predictable amount of room and no
   more. Left to stretch they take a full grid column for a value that is
   never longer than "31/12/2026 23:59", pushing everything else narrower. */
/* !important is deliberate here.
   .modal-body carries a deliberately broad rule --
     .modal-body input:not([type=checkbox]):not([type=radio]):not([type=file])
                      :not([type=color]):not([type=range])
   -- whose five :not() clauses give it a specificity of (0,6,1) and a
   max-width of 100%. No reasonable selector for "date inputs" outranks that,
   and widening the :not() chain to exclude dates too would make the general
   rule harder to read for the sake of a narrower one. */

/* Short fields: trimmed padding so the box can shrink to its contents.
   14px a side is generous for a paragraph and wasteful for "MI". */
.modal-body .form-control[type="date"],
.modal-body .form-control[type="time"],
.modal-body .form-control[type="datetime-local"],
.modal-body .form-control[type="month"],
.modal-body .form-control[type="week"],
.modal-body .form-control[name="latitude"],
.modal-body .form-control[name="longitude"],
.modal-body .form-control[name="cap"],
.modal-body .form-control[name="address_zip"],
.modal-body .form-control[name="postal_code"],
.modal-body .form-control[name="province"],
.modal-body .form-control[name="provincia"],
.modal-body .form-control[name="address_province"] {
    padding-left: 6px !important;
    padding-right: 6px !important;
}

/* date 76px of text + 12 padding + 2 border + 18 picker = 108 */
.form-control[type="date"],
.modal-body .form-control[type="date"],
.form-control[type="month"],
.modal-body .form-control[type="month"],
.form-control[type="week"],
.modal-body .form-control[type="week"],
/* Coordinates are 93px of text and no picker, so they land on the same
   number -- which is what makes a row of dates and coordinates line up. */
.modal-body .form-control[name="latitude"],
.modal-body .form-control[name="longitude"] {
    max-width: 110px !important;
}

/* 38px + 12 + 2 + 18 = 70 */
.form-control[type="time"],
.modal-body .form-control[type="time"] {
    max-width: 74px !important;
}

/* 132px + 12 + 2 + 18 = 164.
   Measured IN a datetime-local, not on a text input holding the same string:
   the native control lays its segments out with its own spacing and needs
   132px where the plain text measures 117. */
.form-control[type="datetime-local"],
.modal-body .form-control[type="datetime-local"] {
    max-width: 166px !important;
}

/* "20139-1234" is 81px + 12 + 2 = 95 */
.modal-body .form-control[name="cap"],
.modal-body .form-control[name="address_zip"],
.modal-body .form-control[name="postal_code"] {
    max-width: 98px !important;
}

/* Province is a two or three letter code: 26px + 12 + 2 = 40. Kept at 62 so
   the box is still comfortable to click and can show a placeholder. */
.modal-body .form-control[name="province"],
.modal-body .form-control[name="provincia"],
.modal-body .form-control[name="address_province"] {
    max-width: 62px !important;
}

/* Filter bars set their own widths inline; do not fight them. */
.filters .form-control[type="date"] { max-width: none !important; }
.filters .form-control[type="date"] { max-width: none !important; }

/* A form hint folded into its label. The text lives in title=, so it costs
   no vertical space but is still reachable. */
.field-hint {
    display: inline-block;
    margin-left: 5px;
    font-size: 0.85em;
    line-height: 1;
    color: var(--gray-500, #64748b);
    cursor: help;
    vertical-align: middle;
}
.field-hint:hover { color: var(--primary, #2563eb); }

/* With the hints out of the flow the rows can sit closer together. */
.modal-body .form-group { margin-bottom: 0.6rem; }
.modal-body .form-row   { gap: 0.75rem; }


/* Page title: icon, name, and the help / edit buttons on one line.
   The icon is a 45px image inside what was a bare inline <span>, so it
   overflowed the line box and sat on top of the text. A flex row lets the
   image keep its size while everything stays vertically centred. */
.page-header h1 {
    display: flex;
    align-items: center;
    gap: 8px;
    /* nowrap, so a long title wraps INSIDE its own span and the icon stays
       beside it. With wrap the icon sat alone on the first line and the title
       dropped underneath it, which is worse than a two-line title. */
    flex-wrap: nowrap;
    margin: 0;
}
.page-header h1 > span:not(.page-title-icon) {
    /* The title does not break.
       Tuning a flex-basis so every title fits at every width is unwinnable --
       "Plants Management" and "Gestione Impianti Fotovoltaici" want different
       numbers. Making the title unbreakable instead pushes the decision to
       flexbox: the row's min-content now includes the whole title, so the
       action buttons wrap BELOW rather than squeezing it onto two lines. */
    white-space: nowrap;
}

/* Give the title the room it needs before the buttons take it.
   .page-header is space-between, and .page-actions measured 816px of a 1600px
   header on plants.html -- wide enough to push "Plants Management" onto a
   second line under its icon. Letting the row wrap means the buttons drop
   below the title instead of crushing it. */
.page-header {
    flex-wrap: wrap;
    gap: 0.75rem;
    row-gap: 0.5rem;
}
.page-header > div:first-child {
    /* auto basis and no min-width override, so the item keeps its min-content
       width -- which, with a nowrap title, is the whole title. That is what
       makes the row wrap instead of the text. */
    flex: 1 1 auto;
}
.page-header > .page-actions,
.page-header > .page-actions-stack {
    flex: 0 1 auto;
}

/* Narrow screens have no spare width to hand the title, so let it wrap there
   rather than push the page into a horizontal scroll. */
@media (max-width: 640px) {
    .page-header h1 > span:not(.page-title-icon) {
        white-space: normal;
        min-width: 0;
    }
}
.page-header h1 > .page-title-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    line-height: 1;
    /* The inline margin-right in the markup predates this rule; gap handles
       the spacing now, so cancel it or the icon sits 6px off-centre. */
    margin-right: 0 !important;
}
.page-header h1 > .page-title-icon img {
    display: block;       /* kills the inline baseline gap under the image */
}
/* The two round buttons keep their own size next to a large icon. */
.page-header h1 > .help-icon {
    flex: 0 0 auto;
    align-self: center;
}


/* Badges and legend swatches for the three statuses added 2026-08-27. */
.plant-status-badge.faulty          { background: #fee2e2; color: #b91c1c; }
.plant-status-badge.waiting-customs { background: #f3e8ff; color: #7e22ce; }
.plant-status-badge.waiting-grid    { background: #e0f2fe; color: #0369a1; }
.legend-marker.faulty           { background: #dc2626; }
.legend-marker.waiting_customs  { background: #a855f7; }
.legend-marker.waiting_grid     { background: #0ea5e9; }

.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s;
}

.modal-overlay.active {
    opacity: 1;
    visibility: visible;
}

.modal {
    /* 2026-06-04: default width is now responsive — fills up to 720px or 95% of
       viewport, whichever is smaller. resize:both gives the user a corner-grip
       to drag-resize; saved dimensions (per modal × resolution bucket) are
       restored by js/modal-prefs.js on open and persisted on resize-end.
       Pages with explicit inline max-width (e.g. bulk-upload 1200px) override
       this without conflict — inline styles win over the cascade. */
    background: white;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow-lg);
    width: 90%;
    max-width: min(95vw, 720px);
    max-height: 92vh;
    min-width: 320px;
    min-height: 240px;
    overflow: hidden;
    resize: both;
    transform: scale(0.9);
    transition: transform 0.3s;

    /* Column layout so the footer cannot be pushed out of the modal.
       Previously this was block layout with `overflow: hidden`, and
       .modal-body carried a hard `max-height: calc(92vh - 110px)`. That
       arithmetic only holds at the natural height -- give the modal an
       explicit, shorter height (which the saved-size restore does) and the
       body kept its full height, shoved the footer past the bottom edge and
       `overflow: hidden` clipped it. Save and Cancel disappeared. */
    display: flex;
    flex-direction: column;
}

/* Header and footer keep their natural height; the body absorbs the rest.
   min-height:0 is required -- without it a flex item refuses to shrink below
   its content and the overflow reappears exactly as before.

   39 of the 177 modals wrap the body and footer in a <form>, so the body is a
   GRANDCHILD of .modal, not a child. A `.modal > .modal-body` selector matched
   none of them and left those dialogs laying out as a single unsized flex item.
   The wrapper therefore becomes a flex column itself and passes the height
   through. */
.modal > .modal-header,
.modal .modal-footer { flex: 0 0 auto; }

.modal > form,
.modal > .modal-content {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.modal .modal-body { flex: 1 1 auto; min-height: 0; }

.modal-overlay.active .modal {
    transform: scale(1);
}

.modal-header {
    padding: 0.65rem 1rem;
    border-bottom: 1px solid var(--gray-200);
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.modal-body {
    padding: 0.85rem 1rem;
    overflow-y: auto;
    overflow-x: hidden;    /* never horizontal scroll the form */
    max-height: calc(92vh - 110px);
}

/* ============================================================
   Modal form auto-fit (added 2026-06-23)
   Many pages render Add/Edit forms with inline
       style="display:grid;grid-template-columns:1fr 1fr;…"
   which doesn't collapse when the user resizes the modal smaller
   than ~640 px. The rules below:
     - make every direct grid container inside .modal-body
       responsive (auto-fit, min-column 220 px)
     - force form-row/form-group children to min-width: 0 so they
       can shrink instead of pushing the modal wider
     - inputs/selects/textareas fill their slot, never overflow
     - inline 2-column grids become 1 column under 640 px wide
   ============================================================ */
.modal-body [style*="display:grid"],
.modal-body [style*="display: grid"] {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)) !important;
    gap: 0.6rem !important;
}
.modal-body .form-group,
.modal-body .form-row,
.modal-body .form-row > .form-group { min-width: 0; }
/* width:100% on text-style inputs lets the form fill the modal column.
   Checkboxes / radios / file inputs / color pickers / range sliders MUST
   be excluded — otherwise they balloon to full width and crush siblings.
   (Concrete symptom: plants.html Groups multiselect rendered each option
   as a giant centred checkbox with no visible label text, because the
   <input type="checkbox"> stole all the flex room from its label span.) */
.modal-body input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=color]):not([type=range]),
.modal-body select,
.modal-body textarea,
.modal-body .form-control {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
}
/* On a narrow modal the auto-fit min still allows 2 columns at 440 px
   wide. Drop to a single column when the BODY (not viewport) is below
   480 px — container query so user-resized modals also adapt. */
.modal-body { container-type: inline-size; container-name: modalBody; }
@container modalBody (max-width: 480px) {
    .modal-body [style*="display:grid"],
    .modal-body [style*="display: grid"] {
        grid-template-columns: 1fr !important;
    }
    .modal-body .form-row { flex-direction: column; }
}

/* Make the resize grip visible — by default `resize: both` only shows a
   subtle bottom-right corner that operators often miss. */
.modal::after {
    content: '';
    position: absolute;
    right: 0; bottom: 0;
    width: 14px; height: 14px;
    background: linear-gradient(135deg, transparent 50%,
                                #94a3b8 50%, #94a3b8 60%, transparent 60%,
                                transparent 70%, #94a3b8 70%, #94a3b8 80%,
                                transparent 80%);
    pointer-events: none;   /* don't intercept the corner-drag */
    opacity: 0.55;
}
.modal:hover::after { opacity: 0.85; }

.modal-footer {
    padding: 0.6rem 1rem;
    border-top: 1px solid var(--gray-200);
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
}

/* ============================================
   Flatpickr — month/year navigation polish
   ============================================ */
/*
 * The header reads  ‹ Month ›   ‹ Year › .
 *
 * flatpickr's own layout puts .flatpickr-current-month in an absolutely
 * positioned 75%-wide box and pins the month arrows to the far edges of the
 * header. Anything added beside the year therefore ended up under the
 * next-month arrow: drawn, covered, unclickable -- which is why the year's
 * right arrow could not be seen. settings.js moves both arrow pairs into the
 * header row; these rules take the absolute positioning off them so the row
 * can lay itself out.
 */
/*
 * EVERY rule below is prefixed with .flatpickr-calendar on purpose.
 *
 * settings.js injects js/flatpickr.min.css at runtime, which lands in <head>
 * AFTER this stylesheet — so at equal specificity flatpickr wins and these
 * rules do nothing at all. The prefix adds a class to each selector, which is
 * enough to take precedence. Without it the header still laid out absolutely
 * and the year group wrapped down onto the weekday row, which is where the
 * missing arrow had gone.
 */
.flatpickr-calendar .flatpickr-months {
    display: flex;
    justify-content: center;
    align-items: center;
    height: auto;
}
.flatpickr-calendar .flatpickr-months .flatpickr-month {
    overflow: visible;
    height: auto;
}
.flatpickr-calendar .flatpickr-current-month {
    position: static;
    width: auto;
    left: auto;
    height: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    padding: 6px 4px;
}
.flatpickr-calendar .flatpickr-current-month .fp-nav-group {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}
/* The month arrows, no longer pinned to the header's edges. */
.flatpickr-calendar .flatpickr-current-month .flatpickr-prev-month,
.flatpickr-calendar .flatpickr-current-month .flatpickr-next-month {
    position: static;
    padding: 0;
    height: 22px;
    width: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
}
.flatpickr-calendar .flatpickr-current-month .flatpickr-prev-month:hover,
.flatpickr-calendar .flatpickr-current-month .flatpickr-next-month:hover {
    background: #eef2ff;
}
.flatpickr-calendar .flatpickr-current-month .cur-month,
.flatpickr-calendar .flatpickr-current-month .flatpickr-monthDropdown-months {
    min-width: 5.6em;
    text-align: center;
    margin: 0;
}
.flatpickr-calendar .flatpickr-current-month .numInputWrapper { width: 4.4ch; }

/* Custom ‹ / › buttons injected by settings.js onReady around the year input
   (one-click ±1 year — default flatpickr only paginates by month). */
.flatpickr-calendar .flatpickr-current-month .fp-year-nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin: 0 2px;
    border-radius: 4px;
    font-size: 1.1rem;
    line-height: 1;
    color: var(--gray-700, #475569);
    cursor: pointer;
    user-select: none;
    transition: background 0.15s, color 0.15s;
}
.flatpickr-calendar .flatpickr-current-month .fp-year-nav:hover {
    background: #eef2ff;
    color: #4f46e5;
}
/* Hide flatpickr's built-in vertical year spin arrows — our ← → replace them. */
.flatpickr-calendar .flatpickr-current-month .numInputWrapper span.arrowUp,
.flatpickr-calendar .flatpickr-current-month .numInputWrapper span.arrowDown { display: none; }
/* Give the month dropdown room to render properly — default style has it
   cramped, which compounds the visibility issue inside resizable modals. */
.flatpickr-calendar .flatpickr-current-month .flatpickr-monthDropdown-months {
    padding: 2px 6px;
}

.modal-close {
    background: none;
    border: none;
    font-size: 1.5rem;
    color: var(--gray-400);
    cursor: pointer;
}

/* ============================================
   Utilities
   ============================================ */
.d-flex { display: flex; }
.d-none { display: none; }
.flex-column { flex-direction: column; }
.align-center { align-items: center; }
.justify-between { justify-content: space-between; }
.justify-center { justify-content: center; }
.gap-1 { gap: 0.25rem; }
.gap-2 { gap: 0.5rem; }
.gap-3 { gap: 0.75rem; }
.gap-4 { gap: 1rem; }

.mt-1 { margin-top: 0.25rem; }
.mt-2 { margin-top: 0.5rem; }
.mt-3 { margin-top: 0.75rem; }
.mt-4 { margin-top: 1rem; }
.mb-1 { margin-bottom: 0.25rem; }
.mb-2 { margin-bottom: 0.5rem; }
.mb-3 { margin-bottom: 0.75rem; }
.mb-4 { margin-bottom: 1rem; }

.p-2 { padding: 0.5rem; }
.p-3 { padding: 0.75rem; }
.p-4 { padding: 1rem; }

.w-100 { width: 100%; }
.text-center { text-align: center; }
.text-right { text-align: right; }

/* ============================================
   Loading Spinner
   ============================================ */
.spinner {
    width: 24px;
    height: 24px;
    border: 3px solid var(--gray-200);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

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

.loading-overlay {
    position: fixed;
    inset: 0;
    background: rgba(255, 255, 255, 0.8);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 9999;
}

/* ============================================
   Pagination
   ============================================ */
.pagination {
    display: flex;
    gap: 0.25rem;
    list-style: none;
}

.pagination li a,
.pagination li span {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 36px;
    padding: 0 0.5rem;
    border: 1px solid var(--gray-300);
    border-radius: var(--border-radius);
    font-size: 0.875rem;
    color: var(--gray-700);
    transition: all 0.2s;
}

.pagination li a:hover {
    background: var(--gray-100);
    text-decoration: none;
}

.pagination li.active span,
.pagination li.active a {
    background: var(--primary);
    border-color: var(--primary);
    color: white;
}

.pagination li.disabled span,
.pagination li.disabled a {
    color: var(--gray-400);
    cursor: not-allowed;
}

/* ============================================
   Search & Filters
   ============================================ */
.search-box {
    position: relative;
}

.search-box input {
    padding-left: 2.5rem;
}

.search-box .search-icon {
    position: absolute;
    left: 0.875rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--gray-400);
}

.filters-row {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}

.filters-row .form-control,
.filters-row .form-select {
    width: auto;
    min-width: 150px;
}

/* ============================================
   Stats Cards
   ============================================ */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.stat-card {
    background: white;
    border-radius: var(--border-radius);
    padding: 1.25rem;
    border: 1px solid var(--gray-200);
}

.stat-card .stat-icon {
    width: 48px;
    height: 48px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    margin-bottom: 0.75rem;
}

.stat-card .stat-value {
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--gray-900);
}

.stat-card .stat-label {
    font-size: 0.875rem;
    color: var(--gray-500);
}

.stat-card.primary .stat-icon {
    background: rgba(79, 70, 229, 0.1);
    color: var(--primary);
}

.stat-card.success .stat-icon {
    background: rgba(16, 185, 129, 0.1);
    color: var(--success);
}

.stat-card.warning .stat-icon {
    background: rgba(245, 158, 11, 0.1);
    color: var(--warning);
}

.stat-card.danger .stat-icon {
    background: rgba(239, 68, 68, 0.1);
    color: var(--danger);
}

/* ============================================
   Grid Utilities
   ============================================ */
.grid {
    display: grid;
    gap: 1rem;
}

.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-5 { grid-template-columns: repeat(5, 1fr); }
.grid-6 { grid-template-columns: repeat(6, 1fr); }

@media (max-width: 1200px) {
    .grid-4, .grid-5, .grid-6 { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 900px) {
    .grid-3, .grid-4, .grid-5, .grid-6 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
    .grid-2, .grid-3, .grid-4, .grid-5, .grid-6 { grid-template-columns: 1fr; }
}

/* ============================================
   Clickable Summary Cards (Filter Buttons)
   ============================================ */
.summary-filter-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px;
    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
    border-radius: 10px;
    cursor: pointer;
    transition: all 0.2s ease;
    border: 2px solid transparent;
}

.summary-filter-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(0,0,0,0.12);
}

.summary-filter-card.active {
    border-color: var(--primary);
    background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);
}

.summary-filter-card .filter-icon {
    font-size: 1.8rem;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 12px;
}

.summary-filter-card .filter-value {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--gray-900);
    line-height: 1.2;
}

.summary-filter-card .filter-label {
    font-size: 0.8rem;
    color: var(--gray-500);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.summary-filter-card.total { background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%); }
.summary-filter-card.success { background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%); }
.summary-filter-card.warning { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); }
.summary-filter-card.danger { background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); }
.summary-filter-card.info { background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); }

/* ============================================
   Sortable Table Headers
   ============================================ */
.table th.sortable {
    cursor: pointer;
    user-select: none;
    position: relative;
    padding-right: 24px;
}

.table th.sortable:hover {
    background: var(--gray-100);
}

/*
 * The corner arrow this class used to draw is gone.
 *
 * js/table-features.js now draws the indicator for every sortable column, on
 * every page, in one place -- beside the label rather than pinned to the corner,
 * and reading the direction from whichever mechanism performed the sort. Left
 * in, this rule would put a second arrow in the corner of the same cell,
 * pointing the other way half the time. The reserved padding goes with it.
 */
.table th.sortable { padding-right: var(--table-cell-pad-x, 0.80rem); }
.table th.sortable::after,
.table th.sortable.asc::after,
.table th.sortable.desc::after { content: none; }

/* The one sorted-column treatment, applied wherever the sort is performed.
   .tf-sortable / .tf-sorted are set by table-features.js.

   The long selectors and the !important are not decoration: settings.js
   injects a sticky-header rule at runtime that paints every th
   `background: var(--gray-50) !important`, and it lands later in the cascade.
   Without matching it, the highlight was computed away and a sorted column
   looked exactly like an unsorted one. */
.table thead th.tf-sortable:hover,
.table-scroll .table thead th.tf-sortable:hover,
.table-container .table thead th.tf-sortable:hover { background: #f0f4ff !important; }

.table thead th.tf-sorted,
.table-scroll .table thead th.tf-sorted,
.table-container .table thead th.tf-sorted {
    color: #1e40af;
    background: #eff6ff !important;
}

.mb-4 { margin-bottom: 1rem; }

/* ============================================================
   RESPONSIVE / MOBILE (added 2026-05-19) — components layer.
   Scoped to <=1024 / <=640 only; desktop unchanged. Pairs with
   the shell rules appended to layout.css.
   ============================================================ */
@media (max-width: 1024px) {
    /* Modals: large but inside the viewport, body scrolls */
    .modal { max-width: 96vw !important; max-height: 92vh; }
    .modal-body { max-height: 78vh; overflow-y: auto; }
    /* Toolbars / filter bars wrap instead of overflowing */
    .alarm-filter-bar, .ov-toolbar, .topo-toolbar, .table-features-toolbar {
        flex-wrap: wrap !important; row-gap: 6px;
    }
    /* Maps / topology / charts: fluid width, sane height */
    #alarmMapCanvas, #cesiumMapDiv, #mapsMapDiv, #plantsMap, #cesiumFullMap,
    .leaflet-container, .cesium-viewer { max-width: 100% !important; }
    .topo-container { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}
@media (max-width: 640px) {
    /* iOS zooms the page when focusing an <16px input — force 16px */
    input, select, textarea, .form-control { font-size: 16px !important; }
    /* WCAG 2.5.5 / 2.5.8 — comfortable tap targets */
    .btn, .form-control, select, input, textarea,
    .csd-wrap > button, .dropdown > button, .table-actions .btn {
        min-height: 44px;
    }
    .btn-sm { min-height: 40px; padding-top: 6px; padding-bottom: 6px; }
    /* Full-screen modals (standard mobile pattern) */
    .modal-overlay { padding: 0 !important; align-items: stretch; }
    .modal {
        max-width: 100vw !important; width: 100vw !important;
        max-height: 100vh; height: auto; border-radius: 0; margin: 0;
    }
    .modal-body { max-height: calc(100vh - 116px); }
    /* Stack the common inline 2/3-col form grids into one column.
       (Targets inline style="...grid-template-columns:1fr 1fr..." etc.) */
    [style*="grid-template-columns:1fr 1fr"],
    [style*="grid-template-columns: 1fr 1fr"],
    [style*="grid-template-columns:repeat(2"],
    [style*="grid-template-columns: repeat(2"],
    [style*="grid-template-columns:repeat(3"],
    [style*="grid-template-columns: repeat(3"] {
        grid-template-columns: 1fr !important;
    }
    /* Filter search inputs go full width so they're usable */
    .alarm-filter-bar input[type="search"],
    .alarm-filter-bar > input, .ov-toolbar input[type="search"] {
        width: 100% !important; flex: 1 1 100%;
    }
    /* Custom zoom-proof dropdown menus must fit the screen */
    .csd-menu { max-width: 92vw; }
    .dropdown-menu { max-width: 92vw; right: auto !important; }
    /* Denser table cells so more fits before horizontal scroll */
    .table th, .table td, .ov-table th, .ov-table td {
        padding: 6px 8px; font-size: 0.8rem;
    }
    /* Tabs / pill rows scroll instead of wrapping into a tall block */
    .ov-tabs, .tabs, .ownership-tabs {
        overflow-x: auto; -webkit-overflow-scrolling: touch; flex-wrap: nowrap;
    }
    .page-header h1, .page-header h2 { font-size: 1.1rem; }
}

/* ---------------------------------------------------------------------------
   In-app dialogs (ui.alert / ui.confirm / ui.prompt).

   Replaces window.alert/confirm/prompt. Beyond looking like the rest of the
   app, this avoids Chrome's "prevent this page from creating additional
   dialogs" suppression — once that kicks in, a native confirm() stops
   appearing and silently returns false, so a confirmation the code relies on
   never reaches the user.
--------------------------------------------------------------------------- */
.ui-dlg-back {
    position: fixed; inset: 0; background: rgba(15, 23, 42, 0.55);
    display: flex; align-items: center; justify-content: center;
    z-index: 12000; padding: 1rem;
}
.ui-dlg {
    background: #fff; border-radius: 12px; width: min(460px, 94vw);
    padding: 1.15rem 1.25rem; box-shadow: 0 22px 55px rgba(0, 0, 0, 0.32);
}
.ui-dlg-title { margin: 0 0 0.5rem; font-size: 1rem; font-weight: 600; color: var(--gray-900); }
.ui-dlg-body { font-size: 0.875rem; line-height: 1.5; color: var(--gray-700); }
.ui-dlg-input {
    width: 100%; box-sizing: border-box; margin-top: 0.8rem;
    padding: 0.55rem 0.65rem; font-size: 0.9rem;
    border: 1px solid var(--gray-300); border-radius: 7px;
}
.ui-dlg-input:focus { outline: 2px solid var(--primary, #2563eb); outline-offset: -1px; }
.ui-dlg-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1rem; }

/* Language switcher — login screens and portal headers.
   Small on purpose: it is a way out of the wrong language, not a feature. */
.lang-switch { display:flex; gap:.25rem; }
.lang-switch .lang-pick {
    border:1px solid rgba(148,163,184,.55); background:transparent; color:inherit;
    border-radius:6px; padding:.15rem .45rem; font-size:.6875rem; font-weight:600;
    cursor:pointer; line-height:1.4; opacity:.72;
}
.lang-switch .lang-pick:hover { opacity:1; }
.lang-switch .lang-pick.on { background:currentColor; opacity:1; }
.lang-switch .lang-pick.on { color:inherit; box-shadow:inset 0 0 0 2em rgba(255,255,255,.16); }

/* ── Inclined column headers ──────────────────────────────────────────────
   Opt-in per user and per table (Columns ▸ Header angle, or right-click the
   header row). Off by default: a table nobody enables it on is untouched.

   Only the LABEL rotates. The <th> box stays upright, which is what keeps the
   filter lens, the search input, the resize grip and the sticky header all
   working -- rotating the cell itself tips every one of those over.

   The label is taken out of flow (position:absolute) on purpose. A rotated
   inline-block still reserves its horizontal box, so the column would stay as
   wide as its text and the tilt would buy nothing.

   --tf-tilt-h is measured from the real labels after render; the fallback is
   only for the frame before that runs. */
table.tf-tilt thead tr:first-child th {
    height: var(--tf-tilt-h, 110px);
    vertical-align: bottom;
    position: relative;          /* also set inline by the resize layer */
    overflow: visible;
}
table.tf-tilt thead tr:first-child th > div {
    /* The label is taken out of flow, so the lens is the only child left in
       this row -- without an end-justify it collapses to the left edge. */
    align-items: flex-end;
    justify-content: flex-end;
}
table.tf-tilt .tf-th-label {
    position: absolute;
    bottom: 6px;
    /* --tf-tilt-lift is the label height x sin(angle): rotating about the
       bottom-left corner swings the text that far to the LEFT, and without
       the offset the first column hangs outside the scroll box. Measured in
       JS because it depends on the rendered line height. */
    left: calc(10px + var(--tf-tilt-lift, 0px));
    transform-origin: 0 100%;
    transform: rotate(calc(-1 * var(--tf-tilt-deg, 0deg)));
    white-space: nowrap;
    display: inline-block;
    flex: none;
    pointer-events: auto;
}

/*
 * One rotation per heading, whatever the markup does.
 *
 * A label nested inside another label compounds the transforms -- 40 degrees
 * inside 40 degrees renders at 80, so two columns with the same setting showed
 * two different angles. The cause is fixed in table-features.js; this makes the
 * geometry impossible to get wrong again from any future path.
 */
table.tf-tilt .tf-th-label .tf-th-label {
    transform: none;
    position: static;
    left: auto;
    bottom: auto;
}

/* The lens and the filter input stay upright at the foot of the cell. */
table.tf-tilt thead tr:first-child th .cf-lens { align-self: flex-end; }
table.tf-tilt thead tr:first-child th .col-filter-input { position: relative; }

/* A tilted label would be clipped by a scroll container that hides overflow. */
table.tf-tilt thead { overflow: visible; }

/* A chain of dependent selects — class > sub class > brand > model — reads as
   one row or not at all: wrapped, the last one sits alone beside a gap the
   width of the form. The default .form-group basis of 180px fits three across
   a narrow modal, so this row asks for less and keeps its four together. The
   controls are short (a word each), so the narrower basis costs nothing. */
.form-row.form-row-chain > .form-group { flex: 1 1 120px; }

/* ---------------------------------------------------------------------------
   Sized tables wrap.

   .table th/td clip to one line with an ellipsis, which is the right default
   while the browser is choosing widths: one long note would otherwise stretch
   the table off the screen. Once a person has set the widths themselves —
   dragged a column, or restored a saved layout — the opposite is true. They
   have said how wide the column should be, and hiding the text inside it is
   not what they asked for. js/table-features.js adds .tf-sized when that
   happens.

   The header label carries an inline white-space:nowrap from the same file, so
   the override has to be !important to reach it. Action cells stay on one line:
   wrapping a row of buttons stacks them and makes the row jump.
   ------------------------------------------------------------------------ */
/* The HEADING always wraps once the table is sized -- it is two or three words
   and its column was measured to hold them. The CELLS do not: see .tf-wrap. */
.table.tf-sized th {
    white-space: normal;
    /* `anywhere`, not break-word. break-word was half of a pair: it only kept
       a word whole because columnFloor() refused to let a column be narrower
       than its longest heading word. That floor was reverted on request, so a
       column can now be as narrow as its reader wants -- and a heading that no
       longer fits has to break somewhere rather than overflow its cell. */
    overflow-wrap: anywhere;
    word-break: normal;
    text-overflow: clip;
    overflow: hidden;
}

/* ---------------------------------------------------------------------------
   Wrapping is per column, and it is asked for.

   A cell stays on one line and clips, which is what keeps rows the height of a
   row. Widening a column by dragging it is the way to say "I want to read this
   one" -- that column, and only that one, wraps. js/table-features.js adds
   .tf-wrap to the cells of those columns and takes it off again when the table
   is fitted to its headings.
   ------------------------------------------------------------------------ */
.table td.tf-wrap,
.table th.tf-wrap {
    white-space: normal !important;
    overflow-wrap: break-word;
    word-break: normal;
    text-overflow: clip;
}

.table.tf-sized th > span:not(.tf-caret):not(.sort-arrow) {
    white-space: normal !important;
    overflow: visible !important;
    text-overflow: clip !important;
}

/* Wrapped headers grow downwards; keep the label sitting on the baseline the
   sort arrows and resize handles are positioned against. */
.table.tf-sized th { vertical-align: bottom; }

/* A tilted header is rotated and its height is measured from the label's own
   width, so wrapping it would fold the text across its own rotation and break
   that measurement. .tf-tilt is set by applyTilt() whenever the angle is not 0;
   those headers keep the single-line treatment. */
.table.tf-sized.tf-tilt th > span {
    white-space: nowrap !important;
}
