/* ============================================================
   ACCESSIBILITÀ — WCAG 2.1 AA  (issue #162)
   ============================================================
   Caricato per ULTIMO in App.razor: le regole qui vincono a
   parità di specificità su app.css / modern-layout.css /
   responsive.css. Non ridefinire qui il layout: solo contrasto,
   focus, movimento e semantica visiva.

   I rapporti di contrasto in commento sono calcolati con la
   formula WCAG 2.x (relative luminance) e verificati dallo
   script in docs/accessibility.md.
   ============================================================ */


/* ------------------------------------------------------------
   1. TOKEN DERIVATI ACCESSIBILI                     (1.4.3 / 1.4.11)
   ------------------------------------------------------------
   La palette "warm terracotta" resta invariata come identità di
   marca: questi token NON la sostituiscono, la affiancano.
   Regola d'uso:
     --o365-<c>          → riempimenti, sfondi, decorazioni
     --o365-<c>-text     → QUALSIASI testo di quel colore
     --o365-primary-strong → fondo di bottone con testo bianco
     --o365-border-strong  → bordo di elemento INTERATTIVO (input,
                             bottone, checkbox): richiesto ≥3:1
   ------------------------------------------------------------ */
:root {
    /* Testo — tutti ≥4.5:1 su bianco, su --o365-gray-10 e sul
       rispettivo --tint-*-bg (il caso peggiore dei tre). */
    --o365-primary-text: #B74D28;  /* era #D97757 → 3.12:1  ora 5.11:1 */
    --o365-red-text:     #BF3E3A;  /* era #C4423E → 4.31:1* ora 5.30:1 */
    --o365-green-text:   #2A7D3C;  /* era #2E8540 → 4.09:1* ora 5.13:1 */
    --o365-yellow-text:  #966809;  /* era #D4950C → 2.59:1  ora 4.91:1 */
    --o365-purple-text:  #765FA5;  /* era #7C6BAB → 3.95:1* ora 5.32:1 */
    --o365-teal-text:    #2B776B;  /* era #2E7D6E → 4.27:1* ora 5.31:1 */
    --o365-muted-text:   #6B665C;  /* era gray-90 #9A9488 → 3.01:1  ora 5.71:1 */
    /*  * = valore misurato sul tint di sfondo, non su bianco */

    /* Fondo pieno che regge testo bianco a 4.5:1 */
    --o365-primary-strong: #C6522D; /* bianco su di esso: 4.52:1 */

    /* Bordi di controlli interattivi — ≥3:1 su white/gray-10/gray-20 */
    --o365-border-strong: #8E887C;  /* 3.52 / 3.27 / 3.04 */

    /* Focus ring — deve avere ≥3:1 con lo sfondo adiacente */
    --focus-ring-color: #B74D28;
    --focus-ring-width: 2px;
    --focus-ring-offset: 2px;
}

html[data-theme="dark"] {
    /* In dark la palette originale supera già 4.5:1 su tutti gli
       sfondi in uso (verificato): i token -text sono alias, così
       il markup può usarli senza condizionali sul tema. */
    --o365-primary-text: #E89070;  /* 7.25:1 */
    --o365-red-text:     #E87070;  /* 5.85:1 */
    --o365-green-text:   #6BBF5C;  /* 7.73:1 */
    --o365-yellow-text:  #E8C040;  /* 10.09:1 */
    --o365-purple-text:  #B08CD8;  /* 6.36:1 */
    --o365-teal-text:    #4DBFB0;  /* 7.87:1 */
    --o365-muted-text:   #B5AFA3;  /* 8.06:1 */

    --o365-primary-strong: #E89070; /* testo scuro sopra, vedi sotto */

    --o365-border-strong: #706B61;  /* 3.32 / 3.53 / 3.15 */

    --focus-ring-color: #F0A98C;
}


/* ------------------------------------------------------------
   2. FOCUS VISIBILE SU TUTTO                              (2.4.7)
   ------------------------------------------------------------
   Politica unica: :focus-visible → ring a 2px con offset.
   Usiamo :focus-visible (non :focus) così il ring non compare al
   click del mouse, che era la ragione originale degli
   `outline: none` sparsi in app.css/modern-layout.css.
   ------------------------------------------------------------ */
:where(a, button, input, select, textarea, summary, [tabindex], [role="button"],
       [role="link"], [role="tab"], [role="menuitem"], [role="option"],
       [role="checkbox"], [role="radio"], [role="switch"]):focus-visible {
    outline: var(--focus-ring-width) solid var(--focus-ring-color);
    outline-offset: var(--focus-ring-offset);
    border-radius: 2px;
}

/* Componenti DevExpress: il ring va sull'elemento focusabile reale,
   che spesso è un figlio interno, e non deve essere tagliato dagli
   overflow:hidden dei wrapper. */
.dxbl-btn:focus-visible,
.dxbl-text-edit:focus-within,
.dxbl-combobox:focus-within,
.dxbl-grid-table td:focus-visible,
.dxbl-grid-table th:focus-visible,
.dxbl-tabs .dxbl-tab:focus-visible,
.dxbl-listbox-item:focus-visible {
    outline: var(--focus-ring-width) solid var(--focus-ring-color);
    outline-offset: 1px;
    z-index: 3;
    position: relative;
}

/* Ripristino esplicito dove app.css / modern-layout.css avevano
   azzerato l'outline in modo incondizionato. */
.search-input:focus-visible,
.form-control-o365:focus-visible,
.login-input:focus-visible,
.cmd-palette-input:focus-visible,
.modern-content:focus-visible,
h1:focus-visible {
    outline: var(--focus-ring-width) solid var(--focus-ring-color);
    outline-offset: var(--focus-ring-offset);
}

/* La search-input vive su sfondo scuro (header): lì il ring
   terracotta non stacca abbastanza, si usa il bianco (≥3:1). */
.modern-header .search-input:focus-visible,
.page-topbar .search-input:focus-visible {
    outline-color: #FFFFFF;
}

/* Il target del skip-link non deve mostrare il ring quando riceve
   focus programmatico: è un contenitore, non un controllo.
   (`tabindex="-1"` non è mai raggiungibile da Tab.) */
main[tabindex="-1"]:focus,
main[tabindex="-1"]:focus-visible {
    outline: none;
}


/* ------------------------------------------------------------
   3. BORDI E CONFINI DEI CONTROLLI                      (1.4.11)
   ------------------------------------------------------------
   I grigi 30/40/50 stanno fra 1.2:1 e 1.8:1 sullo sfondo: vanno
   bene per separatori decorativi, NON per il bordo di un input,
   che è l'unico indicatore visivo del campo.
   ------------------------------------------------------------ */
.form-control-o365,
.login-input,
input.form-control,
textarea.form-control,
select.form-select,
.dxbl-text-edit,
.dxbl-combobox > .dxbl-edit-btn-prefix ~ *,
.dxbl-textbox {
    border-color: var(--o365-border-strong);
}

/* Stato disabilitato: WCAG esenta i controlli inattivi dal
   requisito di contrasto, ma un disabled illeggibile resta un
   problema d'uso. Portiamo il testo a ~4.5:1 mantenendolo
   chiaramente "spento" tramite sfondo e cursore. */
.form-control-o365:disabled,
input:disabled,
textarea:disabled,
select:disabled,
.btn:disabled,
.btn-o365:disabled,
.dxbl-btn:disabled {
    color: var(--o365-muted-text);
    opacity: 1;             /* l'opacity moltiplicava già il contrasto */
    background-color: var(--o365-gray-20);
    cursor: not-allowed;
}


/* ------------------------------------------------------------
   4. TESTO COLORATO E BADGE DI STATO                     (1.4.3)
   ------------------------------------------------------------
   209 occorrenze di .badge-* nel markup: correggendo qui il
   colore del testo si coprono tutte senza toccare i Razor.
   Lo sfondo (il tint) resta invariato → nessun cambio percepito
   di identità visiva, solo testo più scuro.
   ------------------------------------------------------------ */
.badge-blue   { color: var(--o365-primary-text); }
.badge-green  { color: var(--o365-green-text); }
.badge-yellow { color: var(--o365-yellow-text); }
.badge-red    { color: var(--o365-red-text); }
.badge-purple { color: var(--o365-purple-text); }
.badge-teal   { color: var(--o365-teal-text); }
.badge-orange { color: var(--o365-primary-text); }
.badge-gray   { color: var(--o365-muted-text); }

/* Le icone-tessera delle stat-card e della home Admin veicolano
   significato insieme al numero che accompagnano: 3:1 basta
   (1.4.11, contenuto non testuale), ma il glifo attuale scende
   sotto quella soglia sul proprio tint. */
.stat-icon.blue,   .admin-icon-blue   { color: var(--o365-primary-text); }
.stat-icon.green,  .admin-icon-green  { color: var(--o365-green-text); }
.stat-icon.yellow                     { color: var(--o365-yellow-text); }
.stat-icon.red,    .admin-icon-red    { color: var(--o365-red-text); }
.stat-icon.purple, .admin-icon-purple { color: var(--o365-purple-text); }
.stat-icon.teal,   .admin-icon-teal   { color: var(--o365-teal-text); }
.admin-icon-orange                    { color: var(--o365-primary-text); }

/* Testo secondario/"muted": gray-90 è 3.01:1 su bianco e 2.80:1
   su gray-10 → sotto soglia in entrambi i casi. */
.text-muted,
.o365-text-muted,
.notification-time,
.notification-meta {
    color: var(--o365-muted-text) !important;
}

/* I placeholder sono testo a tutti gli effetti. */
::placeholder,
.dxbl-text-edit input::placeholder {
    color: var(--o365-muted-text);
    opacity: 1;
}

/* Link testuali dentro il contenuto: il terracotta pieno è 3.12:1. */
.modern-content a:not(.btn):not(.btn-o365):not([class*="dxbl-"]):not(.rail-item):not(.dms-nav-item) {
    color: var(--o365-primary-text);
}

/* Rail di navigazione — trovati dalla suite axe, non dall'analisi statica:
   erano selettori che usavano --o365-primary direttamente e che la prima
   passata non aveva rimappato.
     .rail-avatar   bianco su #D97757 = 3.12:1
     .rail-item.active  #D97757 su #FDF0E9 = 2.79:1  */
.rail-avatar {
    background: var(--o365-primary-strong);
}
.rail-item.active,
.rail-item:focus,
.modern-nav-item.active {
    color: var(--o365-primary-text);
}
html[data-theme="dark"] .rail-avatar {
    /* In dark il primario è chiaro: il testo sopra dev'essere scuro. */
    color: #1A1915;
}

/* ── Trovati da axe sull'app in esecuzione ──────────────────
   Sono selettori che l'analisi statica non aveva rimappato perché
   usano la palette base o i colori di Bootstrap/DevExpress
   direttamente. Il valore in commento è quello misurato da axe. */

/* Voce di navigazione attiva: #D97757 su #FDF0E9 = 2.79:1 */
.dms-nav-item.active,
.dms-nav-item[aria-current] {
    color: #B94D2A;                       /* 4.53:1 sul tint, 5.05:1 su bianco */
}

/* badge grigio: --o365-muted-text regge su bianco ma non sul proprio
   sfondo --o365-gray-30 (#E8E0D3), dove scende a 4.35:1. */
.badge-gray { color: #68645A; }           /* 4.51:1 su #E8E0D3 */

/* Colori di Bootstrap lasciati al default: il blu dei link-button sta a
   4.38:1 e il grigio degli outline-secondary a 4.35:1. */
.btn-link,
.btn-outline-primary { color: #0266FA; }  /* 4.78–4.90:1 */
.btn-outline-secondary { color: #656D75; } /* 4.53–5.25:1 */

/* DevExpress ButtonRenderStyle.Info: testo BIANCO su ciano #0DCAF0 =
   1.96:1, il peggiore di tutta l'app. Il ciano è riconoscibile e resta:
   a cambiare è il testo, che in scuro arriva a 8.98:1. È anche ciò che
   fa Bootstrap 5 col proprio .btn-info. */
.dxbl-btn-info,
.btn-info {
    color: #1A1915 !important;
}

/* Bottone primario pieno: bianco su #D97757 è 3.12:1. */
.btn-o365-primary,
.btn-primary {
    background-color: var(--o365-primary-strong);
    border-color: var(--o365-primary-strong);
}
html[data-theme="dark"] .btn-o365-primary,
html[data-theme="dark"] .btn-primary {
    /* In dark il primario è chiaro: il testo sopra dev'essere scuro. */
    color: #1A1915;
}


/* ------------------------------------------------------------
   5. MOVIMENTO E ANIMAZIONI                     (2.2.2 / 2.3.1)
   ------------------------------------------------------------
   Spinner e transizioni si fermano quando l'utente ha chiesto
   meno movimento a livello di sistema. Gli spinner restano
   visibili (non `display:none`) perché comunicano "sto
   caricando"; smettono solo di ruotare.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    .spinner-border,
    .spinner-grow,
    .wf-node-spinner {
        animation: none !important;
        border-right-color: currentColor;  /* resta leggibile da fermo */
    }
}


/* ------------------------------------------------------------
   6. AREA DI TOCCO MINIMA                                (2.5.5)
   ------------------------------------------------------------
   I bottoni icon-only delle DxGrid sono ~24px. Allarghiamo
   l'area attiva senza spostare la grafica, usando un
   pseudo-elemento: la cella non cambia altezza.
   ------------------------------------------------------------ */
@media (pointer: coarse) {
    .dxbl-grid .dxbl-btn,
    .btn-icon,
    .btn-close,
    .o365-icon-btn {
        position: relative;
    }
    .dxbl-grid .dxbl-btn::after,
    .btn-icon::after,
    .btn-close::after,
    .o365-icon-btn::after {
        content: "";
        position: absolute;
        inset: 50% auto auto 50%;
        transform: translate(-50%, -50%);
        min-width: 44px;
        min-height: 44px;
    }
}


/* ------------------------------------------------------------
   7. SPAZIATURA DEL TESTO                                (1.4.12)
   ------------------------------------------------------------
   Il criterio richiede che l'utente possa forzare line-height
   1.5em, letter-spacing .12em, word-spacing .16em e spaziatura
   fra paragrafi 2em senza perdita di contenuto. Il rischio nel
   markup di Kartiq sono i contenitori con `height` fissa che
   tagliano il testo: li rendiamo elastici.
   ------------------------------------------------------------ */
.badge-o365,
.stat-card,
.o365-card-header,
.dms-nav-item,
.modern-nav-item,
.notification-item {
    min-height: initial;
    height: auto;
    overflow: visible;
}


/* ------------------------------------------------------------
   8. MODALITÀ A COLORI FORZATI / ALTO CONTRASTO
   ------------------------------------------------------------
   In Windows High Contrast i bordi disegnati con background o
   box-shadow scompaiono: li riportiamo come bordi reali.
   ------------------------------------------------------------ */
@media (forced-colors: active) {
    .badge-o365,
    .stat-card,
    .o365-card,
    .btn-o365,
    .modal-content,
    .kartiq-modal-dialog {
        border: 1px solid CanvasText;
    }

    :focus-visible {
        outline: 2px solid Highlight !important;
        outline-offset: 2px;
    }

    /* Le icone bootstrap sono glifi di font: restano visibili. Gli
       stati resi solo con background pieno no. */
    .stat-icon,
    .admin-icon {
        forced-color-adjust: none;
    }
}


/* ------------------------------------------------------------
   9. UTILITY
   ------------------------------------------------------------ */

/* Testo per sole tecnologie assistive. Bootstrap fornisce già
   .visually-hidden; questo alias serve a chi legge il markup
   Kartiq senza sapere che Bootstrap è in gioco. */
.sr-only,
.a11y-sr-only {
    position: absolute !important;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Reso visibile quando riceve focus (pattern skip-link). */
.a11y-sr-only-focusable:not(:focus):not(:focus-within) {
    position: absolute !important;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
}
