Plugin Directory

Changeset 3344806


Ignore:
Timestamp:
08/14/2025 05:41:42 PM (8 months ago)
Author:
bdplugins
Message:

Release version 1.0.1

Location:
accessimate/trunk
Files:
253 added
1 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • accessimate/trunk/assets/css/accessimate-admin.css

    r3332446 r3344806  
    11/**
    22 * AccessiMate Admin CSS
    3  * Modern admin interface styling
     3 * Optimized modern admin interface styling
    44 */
    55
    66/* CSS Variables for admin interface */
    77:root {
    8     --ap-admin-primary: #2563eb;
    9     --ap-admin-primary-hover: #1d4ed8;
    10     --ap-admin-secondary: #64748b;
    11     --ap-admin-success: #10b981;
    12     --ap-admin-warning: #f59e0b;
    13     --ap-admin-danger: #ef4444;
    14     --ap-admin-white: #ffffff;
    15     --ap-admin-gray-50: #f8fafc;
    16     --ap-admin-gray-100: #f1f5f9;
    17     --ap-admin-gray-200: #e2e8f0;
    18     --ap-admin-gray-300: #cbd5e1;
    19     --ap-admin-gray-400: #94a3b8;
    20     --ap-admin-gray-500: #64748b;
    21     --ap-admin-gray-600: #475569;
    22     --ap-admin-gray-700: #334155;
    23     --ap-admin-gray-800: #1e293b;
    24     --ap-admin-gradient: linear-gradient(135deg, var(--ap-admin-primary) 0%, #3b82f6 100%);
    25     --ap-admin-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
    26     --ap-admin-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
    27     --ap-admin-radius: 0.5rem;
    28     --ap-admin-radius-lg: 0.75rem;
    29     --ap-admin-transition: all 0.15s ease-in-out;
     8    /* Light Theme Colors */
     9    --am-admin-primary: #1e40af; /* Deep indigo for better contrast */
     10    --am-admin-primary-hover: #1e3a8a; /* Darker indigo for hover */
     11    --am-admin-secondary: #475569; /* Neutral slate for secondary elements */
     12    --am-admin-success: #16a34a; /* Vibrant green for success states */
     13    --am-admin-warning: #d97706; /* Warm amber for warnings */
     14    --am-admin-danger: #dc2626; /* Bold red for errors */
     15    --am-admin-white: #ffffff;
     16    --am-admin-gray-50: #f9fafb;
     17    --am-admin-gray-100: #f3f4f6;
     18    --am-admin-gray-200: #e5e7eb;
     19    --am-admin-gray-300: #d1d5db;
     20    --am-admin-gray-400: #9ca3af;
     21    --am-admin-gray-500: #6b7280;
     22    --am-admin-gray-600: #4b5563;
     23    --am-admin-gray-700: #374151;
     24    --am-admin-gray-800: #1f2937;
     25    --am-admin-gradient: linear-gradient(135deg, var(--am-admin-primary) 0%, #4f46e5 100%); /* Softer gradient with indigo */
     26    --am-admin-shadow: 0 2px 4px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.06);
     27    --am-admin-shadow-lg: 0 8px 12px rgba(0, 0, 0, 0.1), 0 3px 6px rgba(0, 0, 0, 0.08);
     28    --am-admin-radius: 0.5rem;
     29    --am-admin-radius-lg: 0.75rem;
     30    --am-admin-transition: all 0.2s ease-in-out;
    3031}
    3132
    3233/* Modern header styling */
    3334.accessimate-admin-header {
    34     background: var(--ap-admin-gradient) !important;
    35     color: var(--ap-admin-white) !important;
     35    background: var(--am-admin-gradient) !important;
     36    color: var(--am-admin-white) !important;
    3637    padding: 24px !important;
    37     border-radius: var(--ap-admin-radius-lg) !important;
     38    border-radius: var(--am-admin-radius-lg) !important;
    3839    border: none !important;
    3940    margin: 20px 0 !important;
    40     box-shadow: var(--ap-admin-shadow-lg) !important;
     41    box-shadow: var(--am-admin-shadow-lg) !important;
    4142    position: relative !important;
    4243    overflow: hidden !important;
     
    5051    right: 0;
    5152    bottom: 0;
    52     background: radial-gradient(circle at top right, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
     53    background: radial-gradient(circle at top right, rgba(255, 255, 255, 0.08) 0%, transparent 70%);
    5354    pointer-events: none;
    5455}
     
    6566/* Info section styling */
    6667.accessimate-admin-info {
    67     background: var(--ap-admin-white) !important;
     68    background: var(--am-admin-white) !important;
    6869    padding: 32px !important;
    69     border: 1px solid var(--ap-admin-gray-200) !important;
    70     border-radius: var(--ap-admin-radius-lg) !important;
     70    border: 1px solid var(--am-admin-gray-200) !important;
     71    border-radius: var(--am-admin-radius-lg) !important;
    7172    margin-top: 32px !important;
    72     box-shadow: var(--ap-admin-shadow) !important;
     73    box-shadow: var(--am-admin-shadow) !important;
    7374}
    7475
    7576.accessimate-admin-info h3 {
    76     color: var(--ap-admin-gray-800) !important;
     77    color: var(--am-admin-gray-800) !important;
    7778    font-size: 20px !important;
    7879    font-weight: 600 !important;
    7980    margin: 0 0 20px 0 !important;
    8081    padding-bottom: 12px !important;
    81     border-bottom: 2px solid var(--ap-admin-gray-100) !important;
     82    border-bottom: 2px solid var(--am-admin-gray-100) !important;
    8283}
    8384
     
    9091.accessimate-admin-info ul li {
    9192    padding: 12px 0 !important;
    92     border-bottom: 1px solid var(--ap-admin-gray-100) !important;
    93     color: var(--ap-admin-gray-700) !important;
     93    border-bottom: 1px solid var(--am-admin-gray-100) !important;
     94    color: var(--am-admin-gray-700) !important;
    9495    font-size: 14px !important;
    9596    line-height: 1.5 !important;
     
    107108    left: 0;
    108109    top: 12px;
    109     color: var(--ap-admin-success);
     110    color: var(--am-admin-success);
    110111    font-weight: 600;
    111112    width: 20px;
     
    122123
    123124.ai-service-status {
    124     background: var(--ap-admin-gray-50) !important;
    125     border: 1px solid var(--ap-admin-gray-200) !important;
    126     border-radius: var(--ap-admin-radius) !important;
     125    background: var(--am-admin-gray-50) !important;
     126    border: 1px solid var(--am-admin-gray-200) !important;
     127    border-radius: var(--am-admin-radius) !important;
    127128    padding: 20px !important;
    128     transition: var(--ap-admin-transition) !important;
     129    transition: var(--am-admin-transition) !important;
    129130    position: relative !important;
    130131    overflow: hidden !important;
     
    138139    right: 0;
    139140    height: 3px;
    140     background: var(--ap-admin-gradient);
     141    background: var(--am-admin-gradient);
    141142}
    142143
    143144.ai-service-status:hover {
    144145    transform: translateY(-2px) !important;
    145     box-shadow: var(--ap-admin-shadow-lg) !important;
    146     border-color: var(--ap-admin-primary) !important;
     146    box-shadow: var(--am-admin-shadow-lg) !important;
     147    border-color: var(--am-admin-primary) !important;
    147148}
    148149
     
    151152    font-size: 16px !important;
    152153    font-weight: 600 !important;
    153     color: var(--ap-admin-gray-800) !important;
     154    color: var(--am-admin-gray-800) !important;
    154155}
    155156
     
    160161    gap: 6px !important;
    161162    padding: 6px 12px !important;
    162     border-radius: var(--ap-admin-radius) !important;
     163    border-radius: var(--am-admin-radius) !important;
    163164    font-size: 12px !important;
    164165    font-weight: 600 !important;
     
    168169
    169170.status-configured {
    170     background: rgba(16, 185, 129, 0.1) !important;
    171     color: var(--ap-admin-success) !important;
    172     border: 1px solid rgba(16, 185, 129, 0.2) !important;
     171    background: rgba(22, 163, 74, 0.1) !important;
     172    color: var(--am-admin-success) !important;
     173    border: 1px solid rgba(22, 163, 74, 0.2) !important;
    173174}
    174175
    175176.status-missing {
    176     background: rgba(239, 68, 68, 0.1) !important;
    177     color: var(--ap-admin-danger) !important;
    178     border: 1px solid rgba(239, 68, 68, 0.2) !important;
     177    background: rgba(220, 38, 38, 0.1) !important;
     178    color: var(--am-admin-danger) !important;
     179    border: 1px solid rgba(220, 38, 38, 0.2) !important;
    179180}
    180181
    181182.status-warning {
    182     background: rgba(245, 158, 11, 0.1) !important;
    183     color: var(--ap-admin-warning) !important;
    184     border: 1px solid rgba(245, 158, 11, 0.2) !important;
     183    background: rgba(217, 119, 6, 0.1) !important;
     184    color: var(--am-admin-warning) !important;
     185    border: 1px solid rgba(217, 119, 6, 0.2) !important;
    185186}
    186187
    187188.status-info {
    188     background: rgba(37, 99, 235, 0.1) !important;
    189     color: var(--ap-admin-primary) !important;
    190     border: 1px solid rgba(37, 99, 235, 0.2) !important;
     189    background: rgba(30, 64, 175, 0.1) !important;
     190    color: var(--am-admin-primary) !important;
     191    border: 1px solid rgba(30, 64, 175, 0.2) !important;
    191192}
    192193
     
    201202    margin: 8px 0 !important;
    202203    font-size: 13px !important;
    203     color: var(--ap-admin-success) !important;
     204    color: var(--am-admin-success) !important;
    204205    font-weight: 500 !important;
    205206    display: flex !important;
     
    210211.enabled-features-list li::before {
    211212    content: '●' !important;
    212     color: var(--ap-admin-success) !important;
     213    color: var(--am-admin-success) !important;
    213214    font-size: 8px !important;
    214215}
     
    216217/* Form improvements */
    217218.form-table th {
    218     color: var(--ap-admin-gray-700) !important;
     219    color: var(--am-admin-gray-700) !important;
    219220    font-weight: 600 !important;
    220221    font-size: 14px !important;
     
    232233.form-table input[type="password"],
    233234.form-table select {
    234     border: 1px solid var(--ap-admin-gray-300) !important;
    235     border-radius: var(--ap-admin-radius) !important;
     235    border: 1px solid var(--am-admin-gray-300) !important;
     236    border-radius: var(--am-admin-radius) !important;
    236237    padding: 10px 12px !important;
    237238    font-size: 14px !important;
    238     transition: var(--ap-admin-transition) !important;
    239     background: var(--ap-admin-white) !important;
     239    transition: var(--am-admin-transition) !important;
     240    background: var(--am-admin-white) !important;
    240241}
    241242
     
    243244.form-table input[type="password"]:focus,
    244245.form-table select:focus {
    245     border-color: var(--ap-admin-primary) !important;
    246     box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1) !important;
     246    border-color: var(--am-admin-primary) !important;
     247    box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.15) !important;
    247248    outline: none !important;
    248249}
     
    254255    width: 50px !important;
    255256    height: 26px !important;
    256     background: var(--ap-admin-gray-300) !important;
     257    background: var(--am-admin-gray-300) !important;
    257258    border-radius: 13px !important;
    258259    position: relative !important;
    259260    cursor: pointer !important;
    260     transition: var(--ap-admin-transition) !important;
     261    transition: var(--am-admin-transition) !important;
    261262    margin-right: 12px !important;
    262263    border: none !important;
    263264    outline: none !important;
    264265    vertical-align: middle !important;
    265     display: inline-block !important;
    266266}
    267267
     
    273273    width: 22px !important;
    274274    height: 22px !important;
    275     background: var(--ap-admin-white) !important;
     275    background: var(--am-admin-white) !important;
    276276    border-radius: 50% !important;
    277277    transition: all 0.3s ease !important;
     
    280280
    281281.form-table input[type="checkbox"]:checked {
    282     background: var(--ap-admin-primary) !important;
     282    background: var(--am-admin-primary) !important;
    283283}
    284284
     
    289289
    290290.form-table input[type="checkbox"]:hover {
    291     box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1) !important;
     291    box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.15) !important;
    292292}
    293293
    294294.form-table input[type="checkbox"]:focus {
    295     box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2) !important;
     295    box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.25) !important;
    296296}
    297297
     
    301301    align-items: center !important;
    302302    font-weight: 500 !important;
    303     color: var(--ap-admin-gray-700) !important;
     303    color: var(--am-admin-gray-700) !important;
    304304    cursor: pointer !important;
    305305    line-height: 1.5 !important;
     306    position: relative;
     307}
     308
     309.form-table label .accessimate-beta-feature {
     310    background: #f59e0b;
     311    color: #000;
     312    padding: 3px 12px;
     313    line-height: 1;
     314    border-radius: 10px;
     315    text-align: center;
     316    margin-left: 30px;
    306317}
    307318
    308319/* Submit button styling */
    309320.button-primary {
    310     background: var(--ap-admin-gradient) !important;
     321    background: var(--am-admin-gradient) !important;
    311322    border: none !important;
    312     border-radius: var(--ap-admin-radius) !important;
     323    border-radius: var(--am-admin-radius) !important;
    313324    padding: 12px 24px !important;
    314325    font-size: 14px !important;
    315326    font-weight: 600 !important;
    316327    text-shadow: none !important;
    317     box-shadow: var(--ap-admin-shadow) !important;
    318     transition: var(--ap-admin-transition) !important;
     328    box-shadow: var(--am-admin-shadow) !important;
     329    transition: var(--am-admin-transition) !important;
    319330}
    320331
    321332.button-primary:hover {
    322     background: linear-gradient(135deg, var(--ap-admin-primary-hover) 0%, var(--ap-admin-primary) 100%) !important;
     333    background: linear-gradient(135deg, var(--am-admin-primary-hover) 0%, var(--am-admin-primary) 100%) !important;
    323334    transform: translateY(-1px) !important;
    324     box-shadow: var(--ap-admin-shadow-lg) !important;
     335    box-shadow: var(--am-admin-shadow-lg) !important;
    325336}
    326337
    327338.button-primary:focus {
    328     box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.3) !important;
     339    box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.3) !important;
    329340}
    330341
    331342/* Section headers */
    332343h2.title {
    333     color: var(--ap-admin-gray-800) !important;
     344    color: var(--am-admin-gray-800) !important;
    334345    font-size: 24px !important;
    335346    font-weight: 700 !important;
     
    346357    width: 60px;
    347358    height: 3px;
    348     background: var(--ap-admin-gradient);
     359    background: var(--am-admin-gradient);
    349360    border-radius: 2px;
    350361}
     
    352363/* Settings sections */
    353364.form-table {
    354     background: var(--ap-admin-white) !important;
    355     border-radius: var(--ap-admin-radius-lg) !important;
    356     box-shadow: var(--ap-admin-shadow) !important;
    357     border: 1px solid var(--ap-admin-gray-200) !important;
     365    background: var(--am-admin-white) !important;
     366    border-radius: var(--am-admin-radius-lg) !important;
     367    box-shadow: var(--am-admin-shadow) !important;
     368    border: 1px solid var(--am-admin-gray-200) !important;
    358369    margin-top: 20px !important;
    359370    overflow: hidden !important;
     
    363374
    364375.form-table tr:nth-child(even) {
    365     background: var(--ap-admin-gray-50) !important;
     376    background: var(--am-admin-gray-50) !important;
    366377}
    367378
    368379.form-table tr:hover {
    369     background: rgba(37, 99, 235, 0.03) !important;
     380    background: rgba(30, 64, 175, 0.05) !important;
    370381}
    371382
     
    381392
    382393.form-table th {
    383     border-right: 1px solid var(--ap-admin-gray-200) !important;
    384     border-bottom: 1px solid var(--ap-admin-gray-200) !important;
    385     background: var(--ap-admin-gray-50) !important;
     394    border-right: 1px solid var(--am-admin-gray-200) !important;
     395    border-bottom: 1px solid var(--am-admin-gray-200) !important;
     396    background: var(--am-admin-gray-50) !important;
    386397}
    387398
    388399.form-table td {
    389     border-bottom: 1px solid var(--ap-admin-gray-200) !important;
     400    border-bottom: 1px solid var(--am-admin-gray-200) !important;
    390401}
    391402
    392403/* Description text */
    393404.description {
    394     color: var(--ap-admin-gray-600) !important;
     405    color: var(--am-admin-gray-600) !important;
    395406    font-size: 13px !important;
    396407    font-style: italic !important;
     
    402413/* Notice improvements */
    403414.notice {
    404     border-radius: var(--ap-admin-radius) !important;
     415    border-radius: var(--am-admin-radius) !important;
    405416    border-left-width: 4px !important;
    406     box-shadow: var(--ap-admin-shadow) !important;
     417    box-shadow: var(--am-admin-shadow) !important;
    407418}
    408419
    409420.notice-info {
    410     background: rgba(37, 99, 235, 0.05) !important;
    411     border-left-color: var(--ap-admin-primary) !important;
     421    background: rgba(30, 64, 175, 0.05) !important;
     422    border-left-color: var(--am-admin-primary) !important;
    412423}
    413424
     
    418429        gap: 16px !important;
    419430    }
    420    
     431
    421432    .accessimate-admin-header {
    422433        padding: 20px !important;
    423434        margin: 16px 0 !important;
    424435    }
    425    
     436
    426437    .accessimate-admin-info {
    427438        padding: 20px !important;
    428439        margin-top: 20px !important;
    429440    }
    430    
     441
    431442    .form-table th,
    432443    .form-table td {
     
    436447        border-right: none !important;
    437448    }
    438    
     449
    439450    .form-table th {
    440         border-bottom: 1px solid var(--ap-admin-gray-300) !important;
     451        border-bottom: 1px solid var(--am-admin-gray-300) !important;
    441452        padding-bottom: 8px !important;
    442453        background: transparent !important;
    443454        font-weight: 700 !important;
    444455    }
    445    
     456
    446457    .form-table td {
    447458        padding-top: 8px !important;
     
    451462
    452463    .form-table tr {
    453         border-bottom: 2px solid var(--ap-admin-gray-200) !important;
     464        border-bottom: 2px solid var(--am-admin-gray-200) !important;
    454465    }
    455466
     
    488499@media (prefers-color-scheme: dark) {
    489500    :root {
    490         --ap-admin-primary: #3b82f6;
    491         --ap-admin-primary-hover: #2563eb;
    492         --ap-admin-secondary: #94a3b8;
    493         --ap-admin-success: #22c55e;
    494         --ap-admin-warning: #fbbf24;
    495         --ap-admin-danger: #f87171;
    496         --ap-admin-white: #1e293b;
    497         --ap-admin-gray-50: #0f172a;
    498         --ap-admin-gray-100: #1e293b;
    499         --ap-admin-gray-200: #334155;
    500         --ap-admin-gray-300: #475569;
    501         --ap-admin-gray-400: #64748b;
    502         --ap-admin-gray-500: #94a3b8;
    503         --ap-admin-gray-600: #cbd5e1;
    504         --ap-admin-gray-700: #e2e8f0;
    505         --ap-admin-gray-800: #f1f5f9;
    506         --ap-admin-gradient: linear-gradient(135deg, var(--ap-admin-primary) 0%, #6366f1 100%);
    507         --ap-admin-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.3), 0 1px 2px -1px rgb(0 0 0 / 0.2);
    508         --ap-admin-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.2), 0 4px 6px -4px rgb(0 0 0 / 0.1);
     501        --am-admin-primary: #60a5fa; /* Bright indigo for dark mode */
     502        --am-admin-primary-hover: #3b82f6; /* Slightly darker indigo */
     503        --am-admin-secondary: #94a3b8; /* Light slate for secondary elements */
     504        --am-admin-success: #4ade80; /* Bright green */
     505        --am-admin-warning: #f59e0b; /* Vibrant amber */
     506        --am-admin-danger: #f87171; /* Bright red */
     507        --am-admin-white: #1e293b; /* Dark slate for backgrounds */
     508        --am-admin-gray-50: #0f172a;
     509        --am-admin-gray-100: #1e293b;
     510        --am-admin-gray-200: #334155;
     511        --am-admin-gray-300: #475569;
     512        --am-admin-gray-400: #64748b;
     513        --am-admin-gray-500: #94a3b8;
     514        --am-admin-gray-600: #cbd5e1;
     515        --am-admin-gray-700: #e2e8f0;
     516        --am-admin-gray-800: #f1f5f9;
     517        --am-admin-gradient: linear-gradient(135deg, var(--am-admin-primary) 0%, #818cf8 100%); /* Softer indigo gradient */
     518        --am-admin-shadow: 0 2px 4px rgba(255, 255, 255, 0.08), 0 1px 2px rgba(255, 255, 255, 0.06);
     519        --am-admin-shadow-lg: 0 8px 12px rgba(255, 255, 255, 0.1), 0 3px 6px rgba(255, 255, 255, 0.08);
    509520    }
    510521
     
    513524    .form-table td,
    514525    .accessimate-admin-info h3,
     526    .accessimate-admin-info .desc,
    515527    .accessimate-admin-info ul li,
    516528    .ai-service-status h4,
    517529    h2.title,
    518530    .description {
    519         color: var(--ap-admin-gray-700) !important;
     531        color: var(--am-admin-gray-700) !important;
    520532    }
    521533
     
    524536    .form-table input[type="password"],
    525537    .form-table select {
    526         background: var(--ap-admin-gray-100) !important;
    527         color: var(--ap-admin-gray-700) !important;
    528         border-color: var(--ap-admin-gray-300) !important;
     538        background: var(--am-admin-gray-100) !important;
     539        color: var(--am-admin-gray-700) !important;
     540        border-color: var(--am-admin-gray-300) !important;
    529541    }
    530542
     
    532544    .form-table input[type="password"]:focus,
    533545    .form-table select:focus {
    534         background: var(--ap-admin-gray-50) !important;
    535         color: var(--ap-admin-gray-800) !important;
     546        background: var(--am-admin-gray-50) !important;
     547        color: var(--am-admin-gray-800) !important;
     548        box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.2) !important;
    536549    }
    537550
    538551    /* Dark mode status indicators */
    539552    .status-configured {
    540         background: rgba(34, 197, 94, 0.15) !important;
    541         color: var(--ap-admin-success) !important;
    542         border-color: rgba(34, 197, 94, 0.3) !important;
     553        background: rgba(74, 222, 128, 0.15) !important;
     554        color: var(--am-admin-success) !important;
     555        border-color: rgba(74, 222, 128, 0.3) !important;
    543556    }
    544557
    545558    .status-missing {
    546559        background: rgba(248, 113, 113, 0.15) !important;
    547         color: var(--ap-admin-danger) !important;
     560        color: var(--am-admin-danger) !important;
    548561        border-color: rgba(248, 113, 113, 0.3) !important;
    549562    }
    550563
    551564    .status-warning {
    552         background: rgba(251, 191, 36, 0.15) !important;
    553         color: var(--ap-admin-warning) !important;
    554         border-color: rgba(251, 191, 36, 0.3) !important;
     565        background: rgba(245, 158, 11, 0.15) !important;
     566        color: var(--am-admin-warning) !important;
     567        border-color: rgba(245, 158, 11, 0.3) !important;
    555568    }
    556569
    557570    .status-info {
    558         background: rgba(59, 130, 246, 0.15) !important;
    559         color: var(--ap-admin-primary) !important;
    560         border-color: rgba(59, 130, 246, 0.3) !important;
     571        background: rgba(96, 165, 250, 0.15) !important;
     572        color: var(--am-admin-primary) !important;
     573        border-color: rgba(96, 165, 250, 0.3) !important;
    561574    }
    562575
    563576    /* Dark mode switch styling */
    564577    .form-table input[type="checkbox"] {
    565         background: var(--ap-admin-gray-400) !important;
     578        background: var(--am-admin-gray-400) !important;
    566579    }
    567580
    568581    .form-table input[type="checkbox"]:before {
    569         background: var(--ap-admin-white) !important;
     582        background: var(--am-admin-gray-50) !important;
    570583        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3) !important;
    571584    }
    572585
    573586    .form-table input[type="checkbox"]:checked {
    574         background: var(--ap-admin-primary) !important;
     587        background: var(--am-admin-primary) !important;
    575588    }
    576589}
     
    578591/* High contrast mode */
    579592@media (prefers-contrast: high) {
     593    :root {
     594        --am-admin-primary: #1e3a8a;
     595        --am-admin-gray-100: #ffffff;
     596        --am-admin-gray-200: #f0f0f0;
     597        --am-admin-gray-300: #d0d0d0;
     598    }
     599
    580600    .form-table input[type="text"],
    581601    .form-table input[type="password"],
     
    583603        border-width: 2px !important;
    584604    }
    585    
     605
    586606    .button-primary {
    587         border: 2px solid var(--ap-admin-primary) !important;
    588     }
    589    
     607        border: 2px solid var(--am-admin-primary) !important;
     608    }
     609
    590610    .status-indicator {
    591611        border-width: 2px !important;
     
    601621        border: 1px solid black !important;
    602622    }
    603    
     623
    604624    .ai-service-status {
    605625        break-inside: avoid !important;
  • accessimate/trunk/assets/css/accessimate-frontend.css

    r3332446 r3344806  
    11/**
    22 * AccessiMate Frontend CSS
    3  * Modern accessibility toolbar with clean design
     3 * Modern accessibility toolbar with optimized, eye-catching design
    44 */
    55
    66/* CSS Variables for consistent theming */
    77:root {
    8     --accessimate-primary: #2563eb;
    9     --accessimate-primary-hover: #1d4ed8;
    10     --accessimate-primary-light: #3b82f6;
    11     --accessimate-secondary: #64748b;
    12     --accessimate-success: #10b981;
    13     --accessimate-warning: #f59e0b;
    14     --accessimate-danger: #ef4444;
    15     --accessimate-dark: #1e293b;
    16     --accessimate-light: #f8fafc;
     8    --accessimate-primary: #1e40af; /* Deep indigo for better contrast */
     9    --accessimate-primary-hover: #1e3a8a; /* Darker indigo for hover */
     10    --accessimate-primary-light: #60a5fa; /* Lighter indigo for accents */
     11    --accessimate-secondary: #475569; /* Neutral slate for secondary elements */
     12    --accessimate-success: #16a34a; /* Vibrant green for success states */
     13    --accessimate-warning: #fff176; /* Softer yellow for warnings */
     14    --accessimate-danger: #dc2626; /* Bold red for errors */
     15    --accessimate-dark: #111827; /* Deep slate for dark backgrounds */
     16    --accessimate-light: #f9fafb; /* Clean off-white for light backgrounds */
    1717    --accessimate-white: #ffffff;
    18     --accessimate-gray-100: #f1f5f9;
    19     --accessimate-gray-200: #e2e8f0;
    20     --accessimate-gray-300: #cbd5e1;
    21     --accessimate-gray-400: #94a3b8;
    22     --accessimate-gray-500: #64748b;
    23     --accessimate-gray-600: #475569;
    24     --accessimate-gray-700: #334155;
    25     --accessimate-gray-800: #1e293b;
    26     --accessimate-gray-900: #0f172a;
    27 
    28     --accessimate-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
    29     --accessimate-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
    30     --accessimate-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
    31     --accessimate-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
    32     --accessimate-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
     18
     19    --accessimate-gray-100: #f3f4f6;
     20    --accessimate-gray-200: #e5e7eb;
     21    --accessimate-gray-300: #d1d5db;
     22    --accessimate-gray-400: #9ca3af;
     23    --accessimate-gray-500: #6b7280;
     24    --accessimate-gray-600: #4b5563;
     25    --accessimate-gray-700: #374151;
     26    --accessimate-gray-800: #1f2937;
     27    --accessimate-gray-900: #111827;
     28
     29    --accessimate-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
     30    --accessimate-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
     31    --accessimate-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
     32    --accessimate-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
     33    --accessimate-shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);
    3334
    3435    --accessimate-radius: 0.5rem;
     
    3738    --accessimate-radius-full: 9999px;
    3839
    39     --accessimate-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
    40     --accessimate-transition: all 0.15s ease-in-out;
     40    --accessimate-font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
     41    --accessimate-transition: all 0.2s ease-in-out;
    4142}
    4243
     
    6162
    6263/* Toolbar positioning */
    63 .accessimate-top-right {
    64     top: 20px;
    65     right: 20px;
    66 }
    67 
    68 .accessimate-top-left {
    69     top: 20px;
    70     left: 20px;
    71 }
    72 
    73 .accessimate-bottom-right {
    74     bottom: 20px;
    75     right: 20px;
    76 }
    77 
    78 .accessimate-bottom-left {
    79     bottom: 20px;
    80     left: 20px;
    81 }
     64.accessimate-top-right { top: 20px; right: 20px; }
     65.accessimate-top-left { top: 20px; left: 20px; }
     66.accessimate-bottom-right { bottom: 20px; right: 20px; }
     67.accessimate-bottom-left { bottom: 20px; left: 20px; }
    8268
    8369/* Responsive positioning for mobile */
     
    9278
    9379/* Toggle button */
    94 .accessimate-toolbar-toggle {
    95     position: relative;
    96 }
    97 
    9880.accessimate-toolbar-toggle button {
    9981    background: linear-gradient(135deg, var(--accessimate-primary), var(--accessimate-primary-light));
     
    10688    font-size: 24px;
    10789    box-shadow: var(--accessimate-shadow-lg);
    108     transition: var(--accessimate-transition);
     90    transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55), opacity 0.3s ease-out, background 0.3s ease, box-shadow 0.3s ease;
    10991    display: flex;
    11092    align-items: center;
     
    11294    position: relative;
    11395    overflow: hidden;
     96    opacity: 0;
     97    transform: scale(0.4) rotate(-45deg); /* Dynamic initial state with rotation */
     98    pointer-events: none;
     99    visibility: hidden;
     100}
     101
     102.accessimate-toolbar-toggle button.loaded {
     103    opacity: 1;
     104    transform: scale(1) rotate(0deg);
     105    pointer-events: auto;
     106    visibility: visible;
     107    animation: accessimate-toolbar-toggle 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards; /* Bouncy animation */
     108}
     109
     110.accessimate-toolbar-toggle button:hover {
     111    transform: scale(1.1) rotate(0deg); /* Slight scale on hover */
     112    box-shadow: var(--accessimate-shadow-xl), 0 0 12px rgba(30, 64, 175, 0.3); /* Glow effect */
     113    background: linear-gradient(135deg, var(--accessimate-primary-hover), var(--accessimate-primary));
     114}
     115
     116.accessimate-toolbar-toggle button:focus {
     117    outline: 3px solid rgba(30, 64, 175, 0.3);
     118    outline-offset: 2px;
    114119}
    115120
     
    121126    right: 0;
    122127    bottom: 0;
    123     background: radial-gradient(circle at center, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
     128    background: radial-gradient(circle at center, rgba(255, 255, 255, 0.15) 0%, transparent 70%);
    124129    opacity: 0;
    125     transition: var(--accessimate-transition);
    126 }
    127 
    128 .accessimate-toolbar-toggle button:hover {
    129     transform: translateY(-2px);
    130     box-shadow: var(--accessimate-shadow-xl);
    131     background: linear-gradient(135deg, var(--accessimate-primary-hover), var(--accessimate-primary));
     130    transition: opacity 0.3s ease;
    132131}
    133132
     
    136135}
    137136
    138 .accessimate-toolbar-toggle button:focus {
    139     outline: 3px solid rgba(37, 99, 235, 0.3);
    140     outline-offset: 2px;
    141 }
    142 
    143137.accessimate-toolbar-toggle button:active {
    144138    transform: translateY(0);
    145139}
    146140
    147 .accessimate-icon {
    148     display: inline-block;
    149     font-style: normal;
    150     font-variant: normal;
    151     text-rendering: auto;
     141.accessimate-toolbar-toggle button .accessimate-icon {
     142    border-radius: 100px;
     143    color: var(--accessimate-white);
     144    border: 2px solid var(--accessimate-white);
     145    padding: 6px;
     146    font-size: 30px;
    152147    line-height: 1;
     148}
     149
     150@keyframes accessimate-toolbar-toggle {
     151    0% {
     152        opacity: 0;
     153        transform: scale(0.4) rotate(-45deg);
     154        pointer-events: none;
     155        visibility: hidden;
     156    }
     157    60% {
     158        opacity: 1;
     159        transform: scale(1.15) rotate(10deg); /* Overshoot for bounce */
     160    }
     161    100% {
     162        opacity: 1;
     163        transform: scale(1) rotate(0deg);
     164        pointer-events: auto;
     165        visibility: visible;
     166    }
     167}
     168
     169/* Respect reduced motion */
     170@media (prefers-reduced-motion: reduce) {
     171    .accessimate-toolbar-toggle button,
     172    .accessimate-toolbar-toggle button.loaded,
     173    .accessimate-toolbar-toggle button:hover {
     174        animation: none !important;
     175        transition-duration: 0.01ms !important;
     176        transform: none !important;
     177    }
    153178}
    154179
     
    160185    border-radius: var(--accessimate-radius-xl);
    161186    box-shadow: var(--accessimate-shadow-xl);
    162     width: 320px;
     187    width: 350px;
    163188    max-width: 90vw;
    164189    backdrop-filter: blur(10px);
     
    176201}
    177202
    178 /* Panel positioning based on toolbar position */
     203/* Panel positioning */
    179204.accessimate-top-right .accessimate-panel,
    180 .accessimate-top-left .accessimate-panel {
    181     top: 70px;
    182 }
    183 
     205.accessimate-top-left .accessimate-panel { top: 70px; }
    184206.accessimate-bottom-right .accessimate-panel,
    185 .accessimate-bottom-left .accessimate-panel {
    186     bottom: 70px;
    187 }
    188 
     207.accessimate-bottom-left .accessimate-panel { bottom: 70px; }
    189208.accessimate-top-right .accessimate-panel,
    190 .accessimate-bottom-right .accessimate-panel {
    191     right: 0;
    192 }
    193 
     209.accessimate-bottom-right .accessimate-panel { right: 0; }
    194210.accessimate-top-left .accessimate-panel,
    195 .accessimate-bottom-left .accessimate-panel {
    196     left: 0;
    197 }
     211.accessimate-bottom-left .accessimate-panel { left: 0; }
    198212
    199213/* Mobile panel adjustments */
     
    209223/* Panel header */
    210224.accessimate-panel-header {
    211     padding: 20px 24px 16px;
     225    padding: 24px 28px 20px; /* Increased padding for better spacing */
    212226    border-bottom: 1px solid var(--accessimate-gray-100);
    213     background: linear-gradient(135deg, var(--accessimate-gray-50) 0%, var(--accessimate-white) 100%);
     227    background: linear-gradient(135deg, var(--accessimate-gray-100) 0%, var(--accessimate-white) 80%); /* Subtler gradient */
    214228    display: flex;
    215229    justify-content: space-between;
    216230    align-items: center;
     231    position: relative;
     232    box-shadow: var(--accessimate-shadow-sm); /* Subtle shadow for depth */
    217233}
    218234
    219235.accessimate-panel-header h3 {
    220     font-size: 18px;
    221     font-weight: 600;
     236    font-size: 20px; /* Slightly larger for emphasis */
     237    font-weight: 700; /* Bolder for hierarchy */
    222238    color: var(--accessimate-gray-800);
    223239    margin: 0;
     240    letter-spacing: -0.025em; /* Tighter letter spacing for modern look */
    224241}
    225242
     
    227244    background: none;
    228245    border: none;
    229     color: var(--accessimate-gray-400);
     246    color: var(--accessimate-gray-700);
    230247    cursor: pointer;
    231248    font-size: 24px;
     
    244261}
    245262
     263.accessimate-header-actions {
     264    display: flex;
     265    justify-content: space-between;
     266    gap: 15px;
     267}
     268
     269/* Theme toggle button */
     270.accessimate-theme-toggle {
     271    background: none;
     272    border: none;
     273    color: var(--accessimate-gray-500);
     274    cursor: pointer;
     275    font-size: 24px;
     276    width: 36px;
     277    height: 36px;
     278    border-radius: var(--accessimate-radius);
     279    display: flex;
     280    align-items: center;
     281    justify-content: center;
     282    transition: var(--accessimate-transition);
     283}
     284
     285.accessimate-theme-toggle:hover {
     286    background: var(--accessimate-gray-100);
     287    color: var(--accessimate-primary);
     288    transform: scale(1.1); /* Subtle scale effect for interactivity */
     289}
     290
     291.accessimate-theme-toggle:focus {
     292    outline: 2px solid var(--accessimate-primary);
     293    outline-offset: 2px;
     294}
     295
     296.accessimate-theme-toggle .material-icons {
     297    font-size: 24px;
     298    line-height: 1;
     299}
     300
    246301/* Panel content */
    247302.accessimate-panel-content {
     
    249304    max-height: 400px;
    250305    overflow-y: auto;
     306    display: grid;
     307    grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
     308    gap: 15px;
    251309}
    252310
    253311/* Custom scrollbar */
    254 .accessimate-panel-content::-webkit-scrollbar {
    255     width: 6px;
    256 }
    257 
     312.accessimate-panel-content::-webkit-scrollbar { width: 6px; }
    258313.accessimate-panel-content::-webkit-scrollbar-track {
    259314    background: var(--accessimate-gray-100);
    260315    border-radius: var(--accessimate-radius);
    261316}
    262 
    263317.accessimate-panel-content::-webkit-scrollbar-thumb {
    264     background: var(--accessimate-gray-300);
     318    background: var(--accessimate-gray-400);
    265319    border-radius: var(--accessimate-radius);
    266320}
    267 
    268321.accessimate-panel-content::-webkit-scrollbar-thumb:hover {
    269     background: var(--accessimate-gray-400);
    270 }
    271 
    272 /* Option containers */
    273 .accessimate-option {
    274     margin-bottom: 16px;
    275 }
    276 
    277 .accessimate-option:last-child {
    278     margin-bottom: 0;
     322    background: var(--accessimate-gray-500);
    279323}
    280324
    281325/* Button styles */
     326.accessimate-btn:focus,
    282327.accessimate-btn {
    283328    width: 100%;
    284329    padding: 12px 16px;
    285     background: var(--accessimate-gray-50);
    286     border: 1px solid var(--accessimate-gray-200);
     330    background: var(--accessimate-gray-100);
     331    border: 1px solid var(--accessimate-gray-300);
    287332    border-radius: var(--accessimate-radius);
    288333    cursor: pointer;
    289334    font-size: 14px;
    290335    font-weight: 500;
    291     color: var(--accessimate-gray-700);
     336    color: var(--accessimate-gray-800);
    292337    display: flex;
    293     align-items: center;
    294     gap: 12px;
     338    gap: 10px;
    295339    transition: var(--accessimate-transition);
    296     text-align: left;
     340    text-align: center;
    297341    position: relative;
    298342    overflow: hidden;
     343    flex-wrap: wrap;
     344    justify-content: center;
     345    height: 100%;
     346    align-items: flex-start;
     347}
     348
     349.accessimate-btn:hover {
     350    background: var(--accessimate-gray-200);
     351    border-color: var(--accessimate-gray-400);
     352    transform: translateY(-1px);
     353    box-shadow: var(--accessimate-shadow);
     354    color: var(--accessimate-primary);
    299355}
    300356
     
    310366}
    311367
    312 .accessimate-btn:hover {
    313     background: var(--accessimate-gray-100);
    314     border-color: var(--accessimate-gray-300);
    315     transform: translateY(-1px);
    316     box-shadow: var(--accessimate-shadow);
    317 }
    318 
    319 .accessimate-btn:hover::before {
     368.accessimate-panel-footer .accessimate-btn {
     369    width: 100%;
     370    padding: 16px;
     371    color: var(--accessimate-white);
     372    border: none;
     373    border-radius: 0 0 var(--accessimate-radius) var(--accessimate-radius);
     374    box-shadow: var(--accessimate-shadow-lg);
     375    flex-direction: row;
     376    justify-content: center;
     377    background: linear-gradient(135deg, var(--accessimate-danger) 0%, #ef4444 100%); /* Red gradient for reset */
     378    border-top: 1px solid var(--accessimate-gray-100);
     379    transition: var(--accessimate-transition), background 0.3s ease, transform 0.2s ease;
     380}
     381
     382.accessimate-panel-footer .accessimate-btn:hover {
     383    background: linear-gradient(135deg, #b91c1c, var(--accessimate-danger)); /* Darker red gradient on hover */
     384    transform: translateY(0);
     385    box-shadow: var(--accessimate-shadow-xl);
     386}
     387
     388.accessimate-panel-footer .accessimate-btn:focus {
     389    outline: none;
     390}
     391
     392.accessimate-btn:hover::before {
    320393    left: 100%;
    321394}
     
    324397    outline: 2px solid var(--accessimate-primary);
    325398    outline-offset: 2px;
     399    /* background: transparent !important; */
    326400}
    327401
     
    329403    background: linear-gradient(135deg, var(--accessimate-primary), var(--accessimate-primary-light));
    330404    border-color: var(--accessimate-primary);
    331     color: var(--accessimate-light);
     405    color: var(--accessimate-white);
    332406    box-shadow: var(--accessimate-shadow-md);
    333407}
     
    338412}
    339413
    340 /* Reset button special styling */
    341 .accessimate-btn-reset {
    342     background: linear-gradient(135deg, var(--accessimate-gray-100), var(--accessimate-gray-50));
    343     border-color: var(--accessimate-gray-300);
    344     color: var(--accessimate-gray-600);
    345     margin-top: 16px;
    346     padding-top: 16px;
    347     border-top: 1px solid var(--accessimate-gray-200);
    348 }
    349 
    350 .accessimate-btn-reset:hover {
    351     background: linear-gradient(135deg, var(--accessimate-gray-200), var(--accessimate-gray-100));
    352     color: var(--accessimate-gray-700);
     414/* Option containers */
     415.accessimate-option-label {
     416    display: block;
     417    width: 100%;
     418    user-select: none;
     419    font-size: 14px;
     420}
     421
     422.accessimate-option-step {
     423    display: flex;
     424    align-items: center;
     425    justify-content: center;
     426    width: 100%;
     427    height: auto;
     428    gap: 5px;
     429    line-height: 0;
     430}
     431
     432.accessimate-option-step .accessimate-option-step-item {
     433    height: 2px;
     434    width: calc(70% / 3);
     435    border-radius: 2px;
     436    background: var(--accessimate-gray-400);
     437    display: inline-block;
     438}
     439
     440.accessimate-option-step .accessimate-option-step-item.active {
     441    background: var(--accessimate-light);
    353442}
    354443
     
    360449    margin-top: 8px;
    361450    padding: 12px;
    362     background: var(--accessimate-gray-50);
     451    background: var(--accessimate-gray-100);
    363452    border-radius: var(--accessimate-radius);
    364453    border: 1px solid var(--accessimate-gray-200);
     
    367456.accessimate-font-controls label {
    368457    font-weight: 500;
    369     color: var(--accessimate-gray-700);
     458    color: var(--accessimate-gray-800);
    370459    margin-bottom: 0;
    371460}
     
    398487#accessimate-font-current {
    399488    font-weight: 600;
    400     color: var(--accessimate-primary-light);
     489    color: var(--accessimate-primary);
    401490    min-width: 50px;
    402491    text-align: center;
     492}
     493
     494/* Text to speech */
     495.accessimate-word-highlight {
     496    background-color: var(--accessimate-warning); /* Softer yellow */
     497    color: var(--accessimate-dark);
     498    border-radius: 2px;
     499    font-size: inherit !important;
     500    font-weight: inherit !important;
     501    line-height: inherit !important;
     502    box-shadow: 0 0 4px 4px rgba(255, 241, 118, 0.7) !important;
     503    transition: box-shadow 0.3s ease, background-color 0.3s ease;
     504    user-select: none; /* prevent accidental text selection flicker */
    403505}
    404506
     
    427529
    428530/* Accessibility states */
    429 body.accessimate-high-contrast {
     531/* body.accessimate-high-contrast {
    430532    filter: contrast(150%) !important;
    431533}
     
    434536    text-shadow: none !important;
    435537    box-shadow: none !important;
    436 }
    437 
    438 body.accessimate-enhanced-focus *:focus {
     538} */
     539
     540body.accessimate-enhanced-keyboard *:focus {
    439541    outline: 3px solid var(--accessimate-warning) !important;
    440542    outline-offset: 2px !important;
     
    443545}
    444546
    445 body.accessimate-highlight-links a {
    446     background: linear-gradient(45deg, #ffff00, #fff200) !important;
    447     color: #000000 !important;
     547body.accessimate-highlight-links a:not(.accessimate-panel a),
     548body.accessimate-highlight-links a:not(.accessimate-panel a) *,
     549body.accessimate-highlight-links a:not(.accessimate-panel a)::before,
     550body.accessimate-highlight-links a:not(.accessimate-panel a)::after,
     551body.accessimate-highlight-links a:not(.accessimate-panel a) *::before,
     552body.accessimate-highlight-links a:not(.accessimate-panel a) *::after {
     553    background: linear-gradient(45deg, var(--accessimate-warning), var(--accessimate-warning)) !important;
     554    color: var(--accessimate-dark) !important;
    448555    text-decoration: underline !important;
    449556    padding: 2px 4px !important;
     
    453560
    454561body.accessimate-simplified-text .accessimate-needs-simplification {
    455     background: linear-gradient(45deg, rgba(59, 130, 246, 0.1), rgba(37, 99, 235, 0.1)) !important;
     562    background: linear-gradient(45deg, rgba(30, 64, 175, 0.1), rgba(30, 64, 175, 0.05)) !important;
    456563    border-left: 4px solid var(--accessimate-primary) !important;
    457564    padding: 8px 12px !important;
     
    484591
    485592@keyframes accessimate-spin {
    486     0% {
    487         transform: rotate(0deg);
    488     }
    489 
    490     100% {
    491         transform: rotate(360deg);
    492     }
     593    0% { transform: rotate(0deg); }
     594    100% { transform: rotate(360deg); }
    493595}
    494596
    495597/* Tooltip styles */
    496 .accessimate-tooltip {
    497     position: relative;
    498 }
    499 
    500598.accessimate-tooltip::after {
    501599    content: attr(data-tooltip);
     
    532630
    533631.accessimate-tooltip:hover::after,
    534 .accessimate-tooltip:hover::before {
    535     opacity: 1;
    536 }
     632.accessimate-tooltip:hover::before { opacity: 1; }
    537633
    538634/* Status indicators */
     
    548644
    549645.accessimate-status-indicator.success {
    550     background: rgba(16, 185, 129, 0.1);
     646    background: rgba(22, 163, 74, 0.1);
    551647    color: var(--accessimate-success);
    552     border: 1px solid rgba(16, 185, 129, 0.2);
     648    border: 1px solid rgba(22, 163, 74, 0.2);
    553649}
    554650
    555651.accessimate-status-indicator.warning {
    556     background: rgba(245, 158, 11, 0.1);
     652    background: rgba(217, 119, 6, 0.1);
    557653    color: var(--accessimate-warning);
    558     border: 1px solid rgba(245, 158, 11, 0.2);
     654    border: 1px solid rgba(217, 119, 6, 0.2);
    559655}
    560656
    561657.accessimate-status-indicator.error {
    562     background: rgba(239, 68, 68, 0.1);
     658    background: rgba(220, 38, 38, 0.1);
    563659    color: var(--accessimate-danger);
    564     border: 1px solid rgba(239, 68, 68, 0.2);
     660    border: 1px solid rgba(220, 38, 38, 0.2);
    565661}
    566662
    567663/* Animation classes */
    568 .accessimate-fade-in {
    569     animation: accessimate-fadeIn 0.3s ease-out;
    570 }
    571 
    572 .accessimate-slide-in {
    573     animation: accessimate-slideIn 0.3s ease-out;
    574 }
     664.accessimate-fade-in { animation: accessimate-fadeIn 0.3s ease-out; }
     665.accessimate-fade-out { animation: accessimate-fadeOut 0.3s ease-out; }
     666.accessimate-slide-in-right { animation: accessimate-slide-in-right 0.3s ease-out; }
     667.accessimate-slide-out-right { animation: accessimate-slide-out-right 0.3s ease-out; }
     668.accessimate-slide-in-left { animation: accessimate-slide-in-left 0.3s ease-out; }
     669.accessimate-slide-out-left { animation: accessimate-slide-out-left 0.3s ease-out; }
     670.accessimate-slide-in-top { animation: accessimate-slide-in-top 0.3s ease-out; }
     671.accessimate-slide-out-top { animation: accessimate-slide-out-top 0.3s ease-out; }
     672.accessimate-slide-in-bottom { animation: accessimate-slide-in-bottom 0.3s ease-out; }
     673.accessimate-slide-out-bottom { animation: accessimate-slide-out-bottom 0.3s ease-out; }
    575674
    576675@keyframes accessimate-fadeIn {
    577     from {
    578         opacity: 0;
    579     }
    580 
    581     to {
    582         opacity: 1;
    583     }
    584 }
    585 
    586 @keyframes accessimate-slideIn {
    587     from {
    588         opacity: 0;
    589         transform: translateY(-20px);
    590     }
    591 
    592     to {
    593         opacity: 1;
    594         transform: translateY(0);
    595     }
     676    from { opacity: 0; }
     677    to { opacity: 1; }
     678}
     679
     680@keyframes accessimate-fadeOut {
     681    from { opacity: 1; }
     682    to { opacity: 0; }
     683}
     684
     685@keyframes accessimate-slide-in-right {
     686    from { opacity: 0; transform: translateX(100px); }
     687    to { opacity: 1; transform: translateX(0); }
     688}
     689
     690@keyframes accessimate-slide-out-right {
     691    from { opacity: 1; transform: translateX(0); }
     692    to { opacity: 0; transform: translateX(100px); }
     693}
     694
     695@keyframes accessimate-slide-in-left {
     696    from { opacity: 0; transform: translateX(-100px); }
     697    to { opacity: 1; transform: translateX(0); }
     698}
     699
     700@keyframes accessimate-slide-out-left {
     701    from { opacity: 1; transform: translateX(0); }
     702    to { opacity: 0; transform: translateX(-100px); }
     703}
     704
     705@keyframes accessimate-slide-in-top {
     706    from { opacity: 0; transform: translateY(-100px); }
     707    to { opacity: 1; transform: translateY(0); }
     708}
     709
     710@keyframes accessimate-slide-out-top {
     711    from { opacity: 1; transform: translateY(0); }
     712    to { opacity: 0; transform: translateY(-100px); }
     713}
     714
     715@keyframes accessimate-slide-in-bottom {
     716    from { opacity: 0; transform: translateY(100px); }
     717    to { opacity: 1; transform: translateY(0); }
     718}
     719
     720@keyframes accessimate-slide-out-bottom {
     721    from { opacity: 1; transform: translateY(0); }
     722    to { opacity: 0; transform: translateY(100px); }
     723}
     724
     725/* Dark mode support scoped to toolbar section */
     726.accessimate-toolbar[data-accessimate-theme="dark"] {
     727    --accessimate-primary: #60a5fa;
     728    --accessimate-primary-hover: #3b82f6;
     729    --accessimate-primary-light: #93c5fd;
     730    --accessimate-secondary: #94a3b8;
     731    --accessimate-success: #4ade80;
     732    --accessimate-warning: #f59e0b;
     733    --accessimate-danger: #f87171;
     734    --accessimate-dark: #0f172a;
     735    --accessimate-light: #1e293b;
     736    --accessimate-white: #1e293b;
     737    --accessimate-gray-100: #1e293b;
     738    --accessimate-gray-200: #334155;
     739    --accessimate-gray-300: #475569;
     740    --accessimate-gray-400: #64748b;
     741    --accessimate-gray-500: #94a3b8;
     742    --accessimate-gray-600: #cbd5e1;
     743    --accessimate-gray-700: #d1d5db;
     744    --accessimate-gray-800: #e5e7eb;
     745    --accessimate-gray-900: #f3f4f6;
     746    --accessimate-shadow-sm: 0 1px 2px 0 rgba(255, 255, 255, 0.05);
     747    --accessimate-shadow: 0 2px 4px rgba(255, 255, 255, 0.08);
     748    --accessimate-shadow-md: 0 4px 6px rgba(255, 255, 255, 0.1);
     749    --accessimate-shadow-lg: 0 10px 15px rgba(255, 255, 255, 0.1);
     750    --accessimate-shadow-xl: 0 20px 25px rgba(255, 255, 255, 0.15);
     751}
     752
     753.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-panel {
     754    background: var(--accessimate-light);
     755    border-color: var(--accessimate-gray-300);
     756    backdrop-filter: blur(10px) brightness(0.9);
     757}
     758
     759.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-panel-header {
     760    background: linear-gradient(135deg, var(--accessimate-gray-200), var(--accessimate-gray-100));
     761    box-shadow: var(--accessimate-shadow-sm);
     762}
     763
     764.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-panel-content {
     765    background: var(--accessimate-light);
     766}
     767
     768.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-btn {
     769    background: var(--accessimate-gray-200);
     770    border-color: var(--accessimate-gray-400);
     771    color: var(--accessimate-gray-800);
     772}
     773
     774.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-btn:hover {
     775    background: var(--accessimate-gray-300);
     776    border-color: var(--accessimate-gray-500);
     777}
     778
     779.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-btn.active {
     780    background: linear-gradient(135deg, var(--accessimate-primary), var(--accessimate-primary-light));
     781    border-color: var(--accessimate-primary);
     782    color: var(--accessimate-white);
     783}
     784
     785.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-btn.active:hover {
     786    background: linear-gradient(135deg, var(--accessimate-primary-hover), var(--accessimate-primary));
     787    transform: translateY(-1px);
     788}
     789
     790.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-panel-footer .accessimate-btn {
     791    background: linear-gradient(135deg, var(--accessimate-danger) 0%, #f87171 100%);
     792}
     793
     794.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-panel-footer .accessimate-btn:hover {
     795    background: linear-gradient(135deg, #b91c1c, var(--accessimate-danger));
     796    transform: translateY(0);
     797    box-shadow: var(--accessimate-shadow-xl);
     798}
     799
     800.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-font-controls {
     801    background: var(--accessimate-gray-200);
     802    border-color: var(--accessimate-gray-400);
     803}
     804
     805.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-font-controls label {
     806    color: var(--accessimate-gray-800);
     807}
     808
     809.accessimate-toolbar[data-accessimate-theme="dark"] #accessimate-font-current {
     810    color: var(--accessimate-primary-light);
     811}
     812
     813.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-theme-toggle {
     814    color: var(--accessimate-gray-600);
     815}
     816
     817.accessimate-toolbar[data-accessimate-theme="dark"] .accessimate-theme-toggle:hover {
     818    background: var(--accessimate-gray-200);
     819    color: var(--accessimate-primary-light);
    596820}
    597821
     
    602826        --accessimate-gray-200: #f0f0f0;
    603827        --accessimate-gray-300: #d0d0d0;
     828        --accessimate-primary: #1e3a8a;
     829        --accessimate-primary-light: #1e40af;
    604830    }
    605831
    606     .accessimate-btn {
    607         border-width: 2px;
    608     }
    609 
    610     .accessimate-panel {
    611         border-width: 2px;
    612     }
     832    .accessimate-btn { border-width: 2px; }
     833    .accessimate-panel { border-width: 2px; }
    613834}
    614835
    615836/* Reduced motion support */
    616837@media (prefers-reduced-motion: reduce) {
    617 
    618838    .accessimate-toolbar *,
    619839    .accessimate-toolbar *::before,
     
    627847/* Print styles */
    628848@media print {
    629     .accessimate-toolbar {
    630         display: none !important;
    631     }
    632 }
    633 
    634 /* Dark mode support */
    635 @media (prefers-color-scheme: dark) {
    636     :root {
    637         --accessimate-white: #1e293b;
    638         --accessimate-gray-50: #334155;
    639         --accessimate-gray-100: #475569;
    640         --accessimate-gray-200: #64748b;
    641         --accessimate-gray-800: #f1f5f9;
    642         --accessimate-gray-700: #e2e8f0;
    643         --accessimate-gray-600: #cbd5e1;
    644     }
    645 
    646     .accessimate-panel {
    647         backdrop-filter: blur(10px) brightness(0.8);
    648     }
    649 }
    650 
    651 /* ================================
    652     HIGHLIGHT TITLES
    653    ================================ */
    654 
     849    .accessimate-toolbar { display: none !important; }
     850}
     851
     852/* Highlight titles */
     853/* .accessimate-highlight,
    655854body.accessimate-highlight-titles h1,
    656855body.accessimate-highlight-titles h2,
     
    663862    outline-width: 2px !important;
    664863    outline-offset: 2px !important;
    665 }
    666 
    667 /* ================================
    668     HIGHLIGHT All
    669    ================================ */
     864    border-radius: 5px !important;
     865    background-color: rgba(30, 64, 175, 0.1) !important;
     866    color: var(--accessimate-primary) !important;
     867    text-decoration: underline !important;
     868    transition: background-color 0.3s ease, color 0.3s ease;
     869} */
     870.accessimate-highlight,
     871body.accessimate-highlight-titles h1:not(.accessimate-panel h1),
     872body.accessimate-highlight-titles h2:not(.accessimate-panel h2),
     873body.accessimate-highlight-titles h3:not(.accessimate-panel h3),
     874body.accessimate-highlight-titles h4:not(.accessimate-panel h4),
     875body.accessimate-highlight-titles h5:not(.accessimate-panel h5),
     876body.accessimate-highlight-titles h6:not(.accessimate-panel h6) {
     877    outline: 3px solid var(--accessimate-primary) !important;
     878    outline-offset: 4px !important;
     879    border-radius: var(--accessimate-radius-lg) !important;
     880
     881    background-color: rgba(30, 64, 175, 0.10) !important;
     882    color: var(--accessimate-dark) !important;
     883    text-decoration: underline solid var(--accessimate-primary-light) !important;
     884    text-underline-offset: 3px;
     885
     886    box-shadow:
     887        0 0 8px 3px rgba(30, 64, 175, 0.3),
     888        0 4px 12px rgba(30, 64, 175, 0.2) !important;
     889
     890    transition:
     891        background-color 0.35s ease,
     892        color 0.35s ease,
     893        box-shadow 0.35s ease;
     894    cursor: pointer;
     895}
     896
     897
     898/* Highlight all */
    670899body.accessimate-highlight-all *:hover {
    671900    outline-style: solid !important;
     
    683912body.accessimate-highlight-all .accessimate-toolbar:hover,
    684913body.accessimate-highlight-all .accessimate-toolbar *:hover {
    685     outline-style: solid !important;
    686     outline-color: unset !important;
     914    outline-style: none !important;
    687915    outline-width: 0 !important;
    688     outline-offset: 0 !important;
    689 }
    690 
    691 /* ================================
    692     Feature Magnifier.
    693    ================================ */
     916}
     917
     918/* Feature Magnifier */
    694919.accessimate-markup-text-magnifier {
    695     color: #fff !important;
     920    color: var(--accessimate-white) !important;
    696921    font-size: 36px !important;
    697922    position: absolute !important;
    698923    padding: 16px !important;
    699924    border-radius: 4px !important;
    700     background: #333 !important;
     925    background: var(--accessimate-dark) !important;
    701926    line-height: 1.5 !important;
    702927    z-index: 999999999 !important;
     
    705930    width: fit-content !important;
    706931}
     932
     933/* Cursor adjustments */
     934.accessimate-cursor-feature1 {
     935    cursor: url('../images/custom-cursor-v1.png'), default !important;
     936    transition: transform 0.2s ease-in-out;
     937}
     938
     939.accessimate-cursor-feature2 {
     940    cursor: url('../images/custom-cursor-v2.png'), default !important;
     941    transition: transform 0.2s ease-in-out;
     942}
     943
     944.accessimate-cursor-feature3 {
     945    cursor: url('../images/custom-cursor-v3.png'), default !important;
     946    transition: transform 0.2s ease-in-out;
     947}
     948
     949/* Notifications */
     950button.accessimate-notification-close {
     951    padding: 0;
     952    margin: 0;
     953}
  • accessimate/trunk/assets/js/accessimate-frontend.js

    r3332446 r3344806  
    99    class AccessiMateToolbar {
    1010        constructor() {
     11            this.themeToggle = $('#accessimate-theme-toggle');
    1112            this.toolbar = $('#accessimate-toolbar');
    1213            this.toggle = $('#accessimate-toggle');
     
    1516            this.fontSize = 100;
    1617            this.isOpen = false;
     18            this.excludedElements = ".accessimate-notification, .accessimate-notification *, .accessimate-toolbar, .accessimate-toolbar *, #wpadminbar, #wpadminbar *, rs-fullwidth-wrap, rs-fullwidth-wrap *, rs-module-wrap, rs-module-wrap *, sr7-module, sr7-module *";
     19
     20            this.options = {
     21                biggerText: {
     22                    key: 'biggerText',
     23                    name: 'Bigger Text',
     24                    trigger: $('#accessimate-bigger-text'),
     25                    steps: ['default', 'small', 'medium', 'biggest'],
     26                    scales: { small: 0.25, medium: 0.5, biggest: 0.75 },
     27                },
     28                cursor: {
     29                    key: 'cursor',
     30                    name: 'Cursor',
     31                    trigger: $('#accessimate-cursor'),
     32                    steps: ['default', 'cursor-v1', 'cursor-v2', 'cursor-v3'],
     33                },
     34                lineHeight: {
     35                    key: 'lineHeight',
     36                    name: 'Line Height',
     37                    trigger: $('#accessimate-line-height'),
     38                    steps: ['default', 'small', 'medium', 'biggest'],
     39                    scales: { small: 0.25, medium: 0.5, biggest: 0.75 },
     40                },
     41                letterSpacing: {
     42                    key: 'letterSpacing',
     43                    name: 'Letter Spacing',
     44                    trigger: $('#accessimate-letter-spacing'),
     45                    steps: ['default', 'small', 'medium', 'biggest'],
     46                    scales: { small: 1, medium: 3, biggest: 5 },
     47                },
     48                readableFont: {
     49                    key: 'readableFont',
     50                    name: 'Readable Font',
     51                    trigger: $('#accessimate-readable-font'),
     52                },
     53                dyslexicFont: {
     54                    key: 'dyslexicFont',
     55                    name: 'Dyslexic Font',
     56                    trigger: $('#accessimate-dyslexic-font')
     57                },
     58                textAlign: {
     59                    key: 'textAlign',
     60                    name: 'Text Align',
     61                    trigger: $('#accessimate-text-align'),
     62                    steps: ['default', 'left', 'center', 'right'],
     63                },
     64                invertColors: {
     65                    key: 'invertColors',
     66                    name: 'Invert Colors',
     67                    trigger: $('#accessimate-invert-colors'),
     68                    steps: ['default', 'invert-v1', 'invert-v2', 'invert-v3'],
     69                },
     70                brightness: {
     71                    key: 'brightness',
     72                    name: 'Brightness',
     73                    trigger: $('#accessimate-brightness'),
     74                    steps: ['default', 'brightness-v1', 'brightness-v2', 'brightness-v3'],
     75                },
     76                grayScale: {
     77                    key: 'grayScale',
     78                    name: 'Grayscale',
     79                    trigger: $('#accessimate-gray-scale'),
     80                    steps: ['default', 'grayscale-v1', 'grayscale-v2', 'grayscale-v3'],
     81                },
     82                saturation: {
     83                    key: 'saturation',
     84                    name: 'Saturation',
     85                    trigger: $('#accessimate-saturation'),
     86                    steps: ['default', 'saturation-v1', 'saturation-v2', 'saturation-v3'],
     87                },
     88                highContrast: {
     89                    key: 'highContrast',
     90                    name: 'Contrast',
     91                    trigger: $('#accessimate-contrast'),
     92                    steps: ['default', 'dark', 'light', 'high-contrast'],
     93                },
     94                muteSounds: {
     95                    key: 'muteSounds',
     96                    name: 'Mute Sounds',
     97                    trigger: $('#accessimate-mute-sounds'),
     98                },
     99                stopAnimations: {
     100                    key: 'stopAnimations',
     101                    name: 'Stop Animations',
     102                    trigger: $('#accessimate-stop-animations'),
     103                },
     104                textToSpeech: {
     105                    key: 'textToSpeech',
     106                    name: 'Text to Speech',
     107                    trigger: $('#accessimate-text-to-speech'),
     108                },
     109                textMagnifier: {
     110                    key: 'textMagnifier',
     111                    name: 'Text Magnifier',
     112                    trigger: $('#accessimate-text-magnifier'),
     113                },
     114            };
    17115
    18116            this.init();
     
    20118
    21119        init() {
     120            this.loaded();
    22121            this.bindEvents();
    23122            this.loadUserPreferences();
     
    26125        }
    27126
     127        loaded() {
     128            this.toggle.addClass('loaded');
     129            this.updateButtonStatus('highContrast');
     130            this.updateButtonStatus('biggerText');
     131            this.updateButtonStatus('lineHeight');
     132            this.updateButtonStatus('letterSpacing');
     133            this.updateButtonStatus('textAlign');
     134            this.updateButtonStatus('invertColors');
     135            this.updateButtonStatus('brightness');
     136            this.updateButtonStatus('grayScale');
     137            this.updateButtonStatus('saturation');
     138            this.updateButtonStatus('cursor');
     139            this.updateButtonStatus('dyslexicFont');
     140            this.updateButtonStatus('readableFont');
     141            this.updateButtonStatus('muteSounds');
     142            this.updateButtonStatus('stopAnimations');
     143            this.updateButtonStatus('textToSpeech');
     144            this.updateButtonStatus('textMagnifier');
     145        }
     146
     147        getTrigger($key) {
     148            return this.options[$key] ? this.options[$key].trigger : null;
     149        }
     150
    28151        bindEvents() {
    29152            // Toggle panel
     
    39162            });
    40163
     164            // Theme toggle
     165            this.themeToggle.on('click', (e) => {
     166                e.preventDefault();
     167                this.toggleTheme();
     168            });
     169
     170            //Bigger Text
     171            this.getTrigger('biggerText').on('click', (e) => {
     172                e.preventDefault();
     173                this.toggleBiggerText();
     174            });
     175
     176            // Cursor
     177            this.getTrigger('cursor').on('click', (e) => {
     178                e.preventDefault();
     179                this.toggleCursor();
     180            });
     181
     182            // Line Height
     183            this.getTrigger('lineHeight').on('click', (e) => {
     184                e.preventDefault();
     185                this.toggleLineHeight();
     186            });
     187
     188            // Letter Spacing
     189            this.getTrigger('letterSpacing').on('click', (e) => {
     190                e.preventDefault();
     191                this.toggleLetterSpacing();
     192            });
     193
     194            // Readable Font
     195            this.getTrigger('readableFont').on('click', (e) => {
     196                e.preventDefault();
     197                this.toggleReadableFont();
     198            });
     199
     200            // Dyslexic Font
     201            this.getTrigger('dyslexicFont').on('click', (e) => {
     202                e.preventDefault();
     203                this.toggleDyslexicFont();
     204            });
     205
     206            // Text Align
     207            this.getTrigger('textAlign').on('click', (e) => {
     208                e.preventDefault();
     209                this.toggleTextAlign();
     210            });
     211
     212            // Invert Colors
     213            this.getTrigger('invertColors').on('click', (e) => {
     214                e.preventDefault();
     215                this.toggleInvertColors();
     216            });
     217
     218            // Brightness
     219            this.getTrigger('brightness').on('click', (e) => {
     220                e.preventDefault();
     221                this.toggleBrightness();
     222            });
     223
     224            // Grayscale
     225            this.getTrigger('grayScale').on('click', (e) => {
     226                e.preventDefault();
     227                this.toggleGrayscale();
     228            });
     229
     230            // Saturation
     231            this.getTrigger('saturation').on('click', (e) => {
     232                e.preventDefault();
     233                this.toggleSaturation();
     234            });
     235
    41236            // High contrast toggle
    42             $('#accessimate-contrast').on('click', (e) => {
    43                 e.preventDefault();
    44                 this.toggleHighContrast();
    45                 // this.closePanel(); // Close menu after action
    46             });
    47 
    48             // Font size controls
    49             $('#accessimate-font-increase').on('click', (e) => {
    50                 e.preventDefault();
    51                 this.increaseFontSize();
    52                 // this.closePanel(); // Close menu after action
    53             });
    54 
    55             $('#accessimate-text-magnifier').on('click', (e) => {
     237            this.getTrigger('highContrast').on('click', (e) => {
     238                e.preventDefault();
     239                this.toggleHighContrast(e);
     240            });
     241
     242            // Text to speech
     243            this.getTrigger('textToSpeech').on('click', (e) => {
     244                e.preventDefault();
     245                this.toggleTextToSpeech();
     246            });
     247
     248            // Text Magnifier
     249            this.getTrigger('textMagnifier').on('click', (e) => {
    56250                e.preventDefault();
    57251                this.toggleTextMagnifier();
    58                 // this.closePanel(); // Close menu after action
    59             });
    60 
     252            });
     253
     254            // Mute Sounds
     255            this.getTrigger('muteSounds').on('click', (e) => {
     256                e.preventDefault();
     257                this.toggleMuteSounds();
     258            });
     259
     260            // Stop Animations
     261            this.getTrigger('stopAnimations').on('click', (e) => {
     262                e.preventDefault();
     263                this.toggleStopAnimations();
     264            });
     265
     266            // Increase font size
    61267            $('#accessimate-font-decrease').on('click', (e) => {
    62268                e.preventDefault();
    63269                this.decreaseFontSize();
    64                 // this.closePanel(); // Close menu after action
    65             });
    66 
    67             // Enhanced focus
    68             $('#accessimate-focus').on('click', (e) => {
    69                 e.preventDefault();
    70                 this.toggleEnhancedFocus();
    71                 // this.closePanel(); // Close menu after action
     270            });
     271
     272            // Enhanced keyboard
     273            $('#accessimate-keyboard').on('click', (e) => {
     274                e.preventDefault();
     275                this.toggleEnhancedKeyboard();
    72276            });
    73277
     
    79283
    80284            // Highlight Titles
    81             $('#accessimate-titles').on('click', (e) => {
     285            $('#accessimate-highlight-titles').on('click', (e) => {
    82286                e.preventDefault();
    83287                this.toggleHighlightTitles();
     
    88292                e.preventDefault();
    89293                this.toggleHighlightLinks();
    90                 // this.closePanel(); // Close menu after action
    91             });
    92 
    93             // Text-to-Speech - Handled by AccessiMateSpeech module
    94             // Event binding is done in accessimate-speech.js
     294            });
    95295
    96296            // Reading assistance features
    97297            $('#accessimate-hide-images').on('click', (e) => {
    98298                e.preventDefault();
    99                 // console.log('Hide images clicked');
    100299                this.hideImages();
    101                 // this.closePanel(); // Close menu after action
    102             });
    103 
     300            });
     301
     302            // Reading mask
    104303            $('#accessimate-reading-mask').on('click', (e) => {
    105304                e.preventDefault();
    106                 // console.log('Reading mask clicked');
    107305                this.toggleReadingMask();
    108                 // this.closePanel(); // Close menu after action
    109             });
    110 
     306            });
     307
     308            // Reading line
    111309            $('#accessimate-reading-line').on('click', (e) => {
    112310                e.preventDefault();
    113                 // console.log('Reading line clicked');
    114311                this.toggleReadingLine();
    115                 // this.closePanel(); // Close menu after action
    116             });
    117 
    118             // AI Content Scan
    119             $('#accessimate-scan').on('click', (e) => {
    120                 e.preventDefault();
    121                 this.scanContent();
    122             });
    123 
    124             // AI Text Simplification
    125             $('#accessimate-simplify').on('click', (e) => {
    126                 e.preventDefault();
    127                 this.toggleTextSimplification();
    128312            });
    129313
     
    157341        }
    158342
     343        panelAnimationClass(key, type = "in") {
     344            if (key === 'none') {
     345                return 'accessimate-animation-none';
     346            }
     347
     348            if (key === 'fade') {
     349                return `accessimate-fade-${type}`;
     350            }
     351
     352            const [direction, position] = key.split('-');
     353
     354            return `accessimate-${direction}-${type}-${position}`;
     355        }
     356
    159357        openPanel() {
    160             this.panel.show().addClass('show accessimate-fade-in');
     358            const animationType = this.panel.data('animation') || 'slide-top';
     359
     360            this.panel.show().removeClass(this.panelAnimationClass(animationType, 'out')).addClass('show ' + this.panelAnimationClass(animationType, 'in'));
    161361            this.toggle.attr('aria-expanded', 'true');
    162362            this.panel.attr('aria-hidden', 'false');
     
    170370
    171371        closePanel() {
    172             this.panel.removeClass('show').fadeOut(200);
     372            const animationType = this.panel.data('animation') || 'slide-top';
     373            this.panel.removeClass('show ' + this.panelAnimationClass(animationType, 'in')).addClass(this.panelAnimationClass(animationType, 'out')).delay(200);
    173374            this.toggle.attr('aria-expanded', 'false');
    174375            this.panel.attr('aria-hidden', 'true');
     
    176377        }
    177378
     379        toggleTheme() {
     380            const autoMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
     381            const currentTheme = this.getPreferences('theme') || this.toolbar.attr('data-accessimate-theme') || autoMode;
     382            const newTheme = currentTheme === 'light' ? 'dark' : 'light';
     383            this.toolbar.attr('data-accessimate-theme', newTheme);
     384            this.savePreference('theme', newTheme);
     385            this.showNotification('Theme: ' + newTheme);
     386        }
     387
     388        toggleBiggerText() {
     389            let { _, value: level } = this.next('biggerText');
     390            this.applyTextStyle(level, {
     391                property: 'font-size',
     392                unit: 'px',
     393                scaleValues: this.options.biggerText.scales,
     394                notificationLabel: 'Font size: ' + (100 + (this.options.biggerText.scales[level] * 100)) + '%'
     395            });
     396            this.updateButtonStatus('biggerText');
     397        }
     398
     399        toggleCursor() {
     400            let { _, value } = this.next('cursor');
     401            this.cursorStyles(value);
     402            this.updateButtonStatus('cursor');
     403        }
     404
     405        toggleLineHeight() {
     406            let { _, value } = this.next('lineHeight');
     407            this.applyTextStyle(value, {
     408                property: 'line-height',
     409                unit: 'px',
     410                scaleValues: this.options.lineHeight.scales,
     411                notificationLabel: 'Line height: ' + (100 + (this.options.lineHeight.scales[value] * 100)) + '%'
     412            });
     413            this.updateButtonStatus('lineHeight');
     414        }
     415
     416        toggleSaturation() {
     417            let { _, value } = this.next('saturation');
     418            this.saturationStyles(value);
     419            this.updateButtonStatus('saturation');
     420        }
     421
     422        toggleLetterSpacing() {
     423            let { _, value } = this.next('letterSpacing');
     424            this.letterSpacingStyles(value);
     425            this.updateButtonStatus('letterSpacing');
     426        }
     427
     428        toggleReadableFont() {
     429            const value = this.getPreferences('readableFont') === 'enabled' ? 'disabled' : 'enabled';
     430            this.readableFontStyles(value);
     431            this.updateButtonStatus('readableFont');
     432        }
     433
     434        toggleDyslexicFont() {
     435            const value = this.getPreferences('dyslexicFont') === 'enabled' ? 'disabled' : 'enabled';
     436            this.dyslexicFontStyles(value);
     437            this.updateButtonStatus('dyslexicFont');
     438        }
     439
     440        toggleTextAlign() {
     441            let { _, value } = this.next('textAlign');
     442            this.textAlignStyles(value);
     443            this.updateButtonStatus('textAlign');
     444        }
     445
     446        toggleInvertColors() {
     447            let { _, value } = this.next('invertColors');
     448            this.invertColorsStyles(value);
     449            this.updateButtonStatus('invertColors');
     450        }
     451
     452        toggleBrightness() {
     453            let { _, value } = this.next('brightness');
     454            this.brightnessStyles(value);
     455            this.updateButtonStatus('brightness');
     456        }
     457
     458        toggleGrayscale() {
     459            let { _, value } = this.next('grayScale');
     460            this.grayScaleStyles(value);
     461            this.updateButtonStatus('grayScale');
     462        }
     463
    178464        toggleHighContrast() {
    179             const $types = ['default', 'dark', 'light', 'high-contrast'];
    180             const currentType = this.getPreferences('highContrast') || 'default';
    181             let newType = $types[($types.indexOf(currentType) + 1) % $types.length];
    182 
    183             this.savePreference('highContrast', newType);
    184             this.highContrastStyles(newType);
    185         }
    186 
    187         increaseFontSize() {
    188             if (this.fontSize < 150) {
    189                 this.fontSize += 10;
    190                 this.updateFontSize();
    191             }
     465            let { _, value } = this.next('highContrast');
     466            this.highContrastStyles(value);
     467            this.updateButtonStatus('highContrast');
     468        }
     469
     470        toggleStopAnimations() {
     471            const value = this.getPreferences('stopAnimations') === 'enabled' ? 'disabled' : 'enabled';
     472            this.stopAnimations(value);
     473            this.updateButtonStatus('stopAnimations');
     474        }
     475
     476        toggleTextToSpeech() {
     477            const value = this.getPreferences('textToSpeech') === 'enabled' ? 'disabled' : 'enabled';
     478            this.textToSpeech(value);
     479            this.updateButtonStatus('textToSpeech');
    192480        }
    193481
     
    207495
    208496        toggleTextMagnifier() {
     497            const value = this.getPreferences('textMagnifier') === 'enabled' ? 'disabled' : 'enabled';
     498            this.textMagnifier(value);
     499            this.updateButtonStatus('textMagnifier');
     500            // const body = $('body');
     501            // const button = $('#accessimate-text-magnifier');
     502            // const isMagnifierDisabled = this.getPreferences('textMagnifier');
     503
     504            // if (!isMagnifierDisabled) {
     505            //     this.enableMagnifier();
     506            // } else {
     507            //     $(".accessimate-markup-text-magnifier").hide();
     508            //     $(document).off("mousemove");
     509            // }
     510
     511            // body.toggleClass('accessimate-text-magnifier');
     512            // button.toggleClass('active');
     513
     514            // this.savePreference('textMagnifier', body.hasClass('accessimate-text-magnifier'));
     515            // this.showNotification('Text magnifier ' + (body.hasClass('accessimate-text-magnifier') ? 'enabled' : 'disabled'));
     516        }
     517
     518        textMagnifier(value, notification = true) {
    209519            const body = $('body');
    210             const button = $('#accessimate-text-magnifier');
    211             const isMagnifierDisabled = this.getPreferences('textMagnifier');
    212 
    213             if (!isMagnifierDisabled) {
    214                 this.enableMagnifier();
     520            const magnifier = $('.accessimate-markup-text-magnifier');
     521            body.toggleClass('accessimate-text-magnifier');
     522
     523            if (value === 'enabled') {
     524                if (!magnifier.length) {
     525                    const newMagnifier = $('<div class="accessimate-markup-text-magnifier"></div>');
     526                    body.append(newMagnifier);
     527                }
     528
     529                $(document).on("mousemove", function (event) {
     530                    const windowWidth = $(window).width();
     531                    const windowHeight = $(window).height();
     532                    const element = document.elementFromPoint(event.clientX, event.clientY);
     533
     534                    if (!$(element).hasClass("accessimate-markup-text-magnifier")) {
     535                        const text = element ? $(element).contents().filter(function () { return this.nodeType === 3; }).text().trim() : "";
     536
     537                        $(".accessimate-markup-text-magnifier").text(text).toggle(!!text);
     538                        const position = {
     539                            left: event.pageX < windowWidth / 2 ? event.pageX + 15 : event.pageX - 115,
     540                            top: event.pageY < windowHeight / 2 ? event.pageY + 30 : event.pageY - 115
     541                        };
     542                        $(".accessimate-markup-text-magnifier").css(position);
     543                    }
     544                });
    215545            } else {
    216546                $(".accessimate-markup-text-magnifier").hide();
    217547                $(document).off("mousemove");
    218548            }
    219 
    220             body.toggleClass('accessimate-text-magnifier');
     549            if (notification) {
     550                this.showNotification(`Text magnifier ${value === 'enabled' ? 'enabled' : 'disabled'}`, value === 'enabled' ? 'success' : 'info');
     551            }
     552            this.savePreference('textMagnifier', value);
     553        }
     554
     555        // enableMagnifier() {
     556        //     const body = $('body');
     557        //     const magnifier = $('.accessimate-markup-text-magnifier');
     558
     559        //     if (!magnifier.length) {
     560        //         const newMagnifier = $('<div class="accessimate-markup-text-magnifier"></div>');
     561        //         body.append(newMagnifier);
     562        //     }
     563
     564        //     $(document).on("mousemove", function (event) {
     565        //         const windowWidth = $(window).width();
     566        //         const windowHeight = $(window).height();
     567        //         const element = document.elementFromPoint(event.clientX, event.clientY);
     568
     569        //         if (!$(element).hasClass("accessimate-markup-text-magnifier")) {
     570        //             const text = element ? $(element).contents().filter(function () { return this.nodeType === 3; }).text().trim() : "";
     571
     572        //             $(".accessimate-markup-text-magnifier").text(text).toggle(!!text);
     573        //             const position = {
     574        //                 left: event.pageX < windowWidth / 2 ? event.pageX + 15 : event.pageX - 115,
     575        //                 top: event.pageY < windowHeight / 2 ? event.pageY + 30 : event.pageY - 115
     576        //             };
     577        //             $(".accessimate-markup-text-magnifier").css(position);
     578        //         }
     579        //     });
     580        // }
     581
     582        toggleEnhancedKeyboard() {
     583            const body = $('body');
     584            const button = $('#accessimate-keyboard');
     585
     586            body.toggleClass('accessimate-enhanced-keyboard');
    221587            button.toggleClass('active');
    222588
    223             this.savePreference('textMagnifier', body.hasClass('accessimate-text-magnifier'));
    224             this.showNotification('Text magnifier ' + (body.hasClass('accessimate-text-magnifier') ? 'enabled' : 'disabled'));
    225         }
    226 
    227         enableMagnifier() {
    228             const body = $('body');
    229             const magnifier = $('.accessimate-markup-text-magnifier');
    230 
    231             if (!magnifier.length) {
    232                 const newMagnifier = $('<div class="accessimate-markup-text-magnifier"></div>');
    233                 body.append(newMagnifier);
    234             }
    235 
    236             $(document).on("mousemove", function (event) {
    237                 const windowWidth = $(window).width();
    238                 const windowHeight = $(window).height();
    239                 const element = document.elementFromPoint(event.clientX, event.clientY);
    240 
    241                 if (!$(element).hasClass("accessimate-markup-text-magnifier")) {
    242                     const text = element ? $(element).contents().filter(function () { return this.nodeType === 3; }).text().trim() : "";
    243 
    244                     $(".accessimate-markup-text-magnifier").text(text).toggle(!!text);
    245                     const position = {
    246                         left: event.pageX < windowWidth / 2 ? event.pageX + 15 : event.pageX - 115,
    247                         top: event.pageY < windowHeight / 2 ? event.pageY + 30 : event.pageY - 115
    248                     };
    249                     $(".accessimate-markup-text-magnifier").css(position);
    250                 }
    251             });
    252         }
    253 
    254         toggleEnhancedFocus() {
    255             const body = $('body');
    256             const button = $('#accessimate-focus');
    257 
    258             body.toggleClass('accessimate-enhanced-focus');
    259             button.toggleClass('active');
    260 
    261             this.savePreference('enhancedFocus', body.hasClass('accessimate-enhanced-focus'));
    262             this.showNotification('Enhanced focus ' + (body.hasClass('accessimate-enhanced-focus') ? 'enabled' : 'disabled'));
     589            this.savePreference('enhancedKeyboard', body.hasClass('accessimate-enhanced-keyboard'));
     590            this.showNotification('Enhanced keyboard ' + (body.hasClass('accessimate-enhanced-keyboard') ? 'enabled' : 'disabled'));
    263591        }
    264592
     
    296624        }
    297625
    298         // Text-to-Speech functionality moved to AccessiMateSpeech module
    299 
    300         // New reading assistance features
     626        toggleMuteSounds() {
     627            const value = this.getPreferences('muteSounds') === 'enabled' ? 'disabled' : 'enabled';
     628            this.muteSounds(value);
     629            this.updateButtonStatus('muteSounds');
     630        }
     631
    301632        hideImages() {
    302633            // Get all regular images and elements with background images
    303634            const images = document.querySelectorAll('img, svg, [role="img"]');
    304635            const backgroundElements = document.querySelectorAll('*:not(.accessimate-toolbar, .accessimate-toolbar *)');
    305             const isCurrentlyHidden = localStorage.getItem('accessimate-hide-images') === 'true';
     636            const isCurrentlyHidden = this.getPreferences('hideImages');
    306637            const button = $('#accessimate-hide-images');
    307638
    308             // Handle regular images
    309639            images.forEach(img => {
    310640                if (isCurrentlyHidden) {
    311                     // Show images
    312641                    img.style.opacity = '1';
    313642                    img.style.transition = 'opacity 0.3s ease';
    314643                    img.removeAttribute('data-accessimate-hidden');
    315644                } else {
    316                     // Hide images
    317645                    img.style.opacity = '0';
    318646                    img.style.transition = 'opacity 0.3s ease';
     
    321649            });
    322650
    323             // Hide background images using background size 0 0
    324651            backgroundElements.forEach(element => {
    325 
    326652                if (isCurrentlyHidden) {
    327653                    element.style.backgroundSize = '';
     
    331657            });
    332658
    333             // Toggle the state
    334             localStorage.setItem('accessimate-hide-images', !isCurrentlyHidden);
     659            this.savePreference('hideImages', !isCurrentlyHidden);
    335660
    336661            if (isCurrentlyHidden) {
    337                 // Was hidden, now showing
    338662                button.removeClass('active');
    339663                this.showNotification('Images restored and shown', 'success');
    340664            } else {
    341                 // Was showing, now hiding
    342665                button.addClass('active');
    343666                this.showNotification('Images hidden (including background images)', 'success');
     
    346669
    347670        toggleReadingMask() {
    348             console.log('Toggle reading mask called');
    349             let mask = document.getElementById('accessimate-reading-mask');
    350671            let maskSelection = document.getElementById('accessimate-reading-mask-section');
    351672            const button = $('#accessimate-reading-mask');
    352673
    353674            if (!maskSelection) {
    354                 console.log('Creating new reading mask');
    355675                maskSelection = document.createElement('div');
    356676                maskSelection.id = 'accessimate-reading-mask-section';
     
    367687                `;
    368688
    369                 // Append to body
    370689                document.body.appendChild(maskSelection);
    371                 console.log('Reading mask appended to body');
    372             }
    373 
    374             // Ensure mouse tracking is set up
     690            }
     691
    375692            if (!this.maskMouseTracker) {
    376693                console.log('Setting up mouse tracking for reading mask');
     
    384701                };
    385702                document.addEventListener('mousemove', this.maskMouseTracker);
    386                 console.log('Mouse tracking added for reading mask');
    387703            }
    388704
    389705            const isVisible = window.getComputedStyle(maskSelection).display === 'block';
    390             console.log('Reading mask current visibility:', isVisible);
    391706
    392707            if (isVisible) {
    393708                maskSelection.style.display = 'none';
    394709                button.removeClass('active');
    395                 localStorage.setItem('accessimate-reading-mask', 'false');
     710                this.savePreference('readingMask', 'false');
    396711                this.showNotification('Reading mask disabled', 'info');
    397                 console.log('Reading mask disabled');
    398712            } else {
    399713                maskSelection.style.display = 'block';
    400714                button.addClass('active');
    401                 localStorage.setItem('accessimate-reading-mask', 'true');
     715                this.savePreference('readingMask', 'true');
    402716                this.showNotification('Reading mask enabled - Move mouse to see spotlight effect', 'success');
    403                 console.log('Reading mask enabled');
    404717            }
    405718        }
    406719
    407720        toggleReadingLine() {
    408             console.log('Toggle reading line called');
    409             let line = document.getElementById('accessimate-reading-line');
     721
    410722            let lineSelection = document.getElementById('accessimate-reading-line-section');
    411723            const button = $('#accessimate-reading-line');
    412724
    413725            if (!lineSelection) {
    414                 console.log('Creating new reading line');
    415726                lineSelection = document.createElement('div');
    416727                lineSelection.id = 'accessimate-reading-line-section';
     
    430741                // Append to body
    431742                document.body.appendChild(lineSelection);
    432                 console.log('Reading line appended to body');
    433743            }
    434744
     
    443753                };
    444754                document.addEventListener('mousemove', this.lineMouseTracker);
    445                 console.log('Mouse tracking added for reading line');
    446755            }
    447756
    448757            const isVisible = window.getComputedStyle(lineSelection).display === 'block';
    449             console.log('Reading line current visibility:', isVisible);
    450758
    451759            if (isVisible) {
    452760                lineSelection.style.display = 'none';
    453761                button.removeClass('active');
    454                 localStorage.setItem('accessimate-reading-line', 'false');
     762                this.savePreference('readingLine', 'false');
    455763                this.showNotification('Reading line disabled', 'info');
    456                 console.log('Reading line disabled');
    457764            } else {
    458765                lineSelection.style.display = 'block';
    459766                button.addClass('active');
    460                 localStorage.setItem('accessimate-reading-line', 'true');
     767                this.savePreference('readingLine', 'true');
    461768                this.showNotification('Reading line enabled - Move mouse to see line guide', 'success');
    462                 console.log('Reading line enabled');
    463769            }
    464770        }
     
    535841            body.removeClass([
    536842                'accessimate-contrast',
    537                 'accessimate-enhanced-focus',
     843                'accessimate-enhanced-keyboard',
    538844                'accessimate-highlight-links',
    539845                'accessimate-simplified-text'
     
    626932            const preferences = this.getPreferences();
    627933
     934            if (preferences.theme) {
     935                this.toolbar.attr('data-accessimate-theme', preferences.theme);
     936            } else if (this.toolbar.attr('data-accessimate-theme') === 'auto') {
     937                const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
     938                if (darkModeMediaQuery.matches) {
     939                    this.toolbar.attr('data-accessimate-theme', 'dark');
     940                } else {
     941                    this.toolbar.attr('data-accessimate-theme', 'light');
     942                }
     943            }
     944
     945            if (preferences.biggerText) {
     946                // this.biggerTextStyle(preferences.biggerText, false);
     947                this.applyTextStyle(preferences.biggerText, {
     948                    property: 'font-size',
     949                    unit: 'px',
     950                    scaleValues: this.options.biggerText.scales
     951                });
     952            }
     953
     954            if (preferences.cursor) {
     955                this.cursorStyles(preferences.cursor, false);
     956            }
     957
     958            if (preferences.lineHeight) {
     959                // this.lineHeightStyles(preferences.lineHeight, false);
     960                this.applyTextStyle(preferences.lineHeight, {
     961                    property: 'line-height',
     962                    unit: 'px',
     963                    scaleValues: this.options.lineHeight.scales
     964                });
     965            }
     966
     967            if (preferences.letterSpacing) {
     968                this.letterSpacingStyles(preferences.letterSpacing, false);
     969            }
     970
     971            if (preferences.readableFont) {
     972                this.readableFontStyles(preferences.readableFont, false);
     973            }
     974
     975            if (preferences.dyslexicFont) {
     976                this.dyslexicFontStyles(preferences.dyslexicFont, false);
     977            }
     978
     979            if (preferences.textAlign) {
     980                this.textAlignStyles(preferences.textAlign, false);
     981            }
     982
     983            if (preferences.invertColors) {
     984                this.invertColorsStyles(preferences.invertColors, false);
     985            }
     986
     987            if (preferences.brightness) {
     988                this.brightnessStyles(preferences.brightness, false);
     989            }
     990
     991            if (preferences.grayScale) {
     992                this.grayScaleStyles(preferences.grayScale, false);
     993            }
     994
     995            if (preferences.saturation) {
     996                this.saturationStyles(preferences.saturation, false);
     997            }
     998
    628999            if (preferences.highContrast) {
    6291000                this.highContrastStyles(preferences.highContrast, false);
    6301001            }
    6311002
    632             if (preferences.enhancedFocus) {
    633                 $('body').addClass('accessimate-enhanced-focus');
    634                 $('#accessimate-focus').addClass('active');
    635             }
    636 
    637             if(preferences.textMagnifier) {
    638                 this.enableMagnifier();
    639                 $('body').addClass('accessimate-text-magnifier');
    640                 $('#accessimate-text-magnifier').addClass('active');
     1003            if (preferences.muteSounds) {
     1004                this.muteSounds(preferences.muteSounds, false);
     1005            }
     1006
     1007            if (preferences.stopAnimations) {
     1008                this.stopAnimations(preferences.stopAnimations, false);
     1009            }
     1010
     1011            if (preferences.textToSpeech) {
     1012                this.textToSpeech(preferences.textToSpeech, false);
     1013            }
     1014
     1015            if (preferences.enhancedKeyboard) {
     1016                $('body').addClass('accessimate-enhanced-keyboard');
     1017                $('#accessimate-keyboard').addClass('active');
     1018            }
     1019
     1020            if (preferences.textMagnifier) {
     1021                this.textMagnifier(preferences.textMagnifier, false);
     1022                // this.enableMagnifier();
     1023                // $('body').addClass('accessimate-text-magnifier');
     1024                // $('#accessimate-text-magnifier').addClass('active');
    6411025            }
    6421026
     
    8291213                top: '20px',
    8301214                left: '50%',
    831                 transform: 'translateX(-50%)',
    832                 background: type === 'error' ? '#ef4444' : type === 'warning' ? '#f59e0b' : type === 'success' ? '#10b981' : '#3b82f6',
    833                 color: 'white',
    834                 padding: '12px 20px',
     1215                transform: 'translateX(-50%) translateY(-20px)', // combine transforms for initial hidden state
     1216                background: (() => {
     1217                    switch (type) {
     1218                        case 'error': return '#ef4444';   // red
     1219                        case 'warning': return '#f59e0b'; // amber
     1220                        case 'success': return '#10b981'; // green
     1221                        default: return '#3b82f6';         // blue (info/default)
     1222                    }
     1223                })(),
     1224                color: '#fff',
     1225                padding: '10px 20px',
    8351226                borderRadius: '8px',
    8361227                boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
     
    8431234                maxWidth: '400px',
    8441235                opacity: '0',
    845                 transform: 'translateX(-50%) translateY(-20px)'
    846             });
     1236            });
     1237
    8471238
    8481239            $('body').append(notification);
     
    8911282        }
    8921283
     1284        letterSpacingStyles($level, $notification = true) {
     1285            const spacing = $level === 'small' ? "1px !important;" : $level === 'medium' ? "3px !important;" : $level === 'biggest' ? "5px !important;" : null;
     1286
     1287            $("*").not(this.excludedElements).each(function () {
     1288
     1289                let style = $(this).attr("style") || "";
     1290                if ($level === 'default') {
     1291                    style = style.replace(/letter-spacing:\s*[^;]+;?/, "");
     1292                } else if (['small', 'medium', 'biggest'].includes($level)) {
     1293                    style = style.trim() && !/;$/.test(style.trim()) ? style + ";" : style;
     1294                    style = /letter-spacing:\s*[^;]+;?/.test(style) ? style.replace(/letter-spacing:\s*[^;]+;?/, "letter-spacing: " + spacing) : style + " letter-spacing: " + spacing;
     1295                }
     1296                $(this).attr("style", style.trim());
     1297            });
     1298
     1299            if ($notification) {
     1300                const label = $level === 'small' ? 'Small' : $level === 'medium' ? 'Medium' : $level === 'biggest' ? 'Biggest' : 'Default';
     1301                this.showNotification(`Letter spacing: ${label}`);
     1302            }
     1303        }
     1304
     1305        textAlignStyles($value, $notification = true) {
     1306            const alignment = $value === 'left' ? "left !important;" : $value === 'center' ? "center !important;" : $value === 'right' ? "right !important;" : null;
     1307            $("*").not(this.excludedElements).each(function () {
     1308                let style = $(this).attr("style") || "";
     1309                if ($value === 'default') {
     1310                    style = style.replace(/text-align:\s*[^;]+;?/, "");
     1311                } else if (['left', 'center', 'right'].includes($value)) {
     1312                    style = style.trim() && !/;$/.test(style.trim()) ? style + ";" : style;
     1313                    style = /text-align:\s*[^;]+;?/.test(style) ? style.replace(/text-align:\s*[^;]+;?/, "text-align: " + alignment) : style + " text-align: " + alignment;
     1314                }
     1315                $(this).attr("style", style.trim());
     1316            });
     1317
     1318            if ($notification) {
     1319                this.showNotification('Text alignment: ' + ($value === 'default' ? 'Default' : $value.charAt(0).toUpperCase() + $value.slice(1)));
     1320            }
     1321        }
     1322
     1323        invertColorsStyles(level, $notification = true) {
     1324            const filter = level === 'invert-v1' ? "invert(70%) !important;" : level === 'invert-v2' ? "invert(85%) !important;" : level === 'invert-v3' ? "invert(100%) !important;" : null;
     1325
     1326            $("html, img").not(this.excludedElements).each(function () {
     1327                let style = $(this).attr("style") || "";
     1328                if (level === 'default') {
     1329                    style = style.replace(/filter:\s*[^;]+;?/, "");
     1330                } else if (['invert-v1', 'invert-v2', 'invert-v3'].includes(level)) {
     1331                    style = style.trim() && !/;$/.test(style.trim()) ? style + ";" : style;
     1332                    style = /filter:\s*[^;]+;?/.test(style) ? style.replace(/filter:\s*[^;]+;?/, "filter: " + filter) : style + " filter: " + filter;
     1333                }
     1334                $(this).attr("style", style.trim());
     1335            });
     1336            if ($notification) {
     1337                const label = level === 'invert-v1' ? 'Invert V1' : level === 'invert-v2' ? 'Invert V2' : level === 'invert-v3' ? 'Invert V3' : 'Default';
     1338                this.showNotification(`Color inversion: ${label}`);
     1339            }
     1340        }
     1341
     1342        brightnessStyles(level, $notification = true) {
     1343            const filter = level === 'brightness-v1' ? "brightness(50%) !important;" : level === 'brightness-v2' ? "brightness(80%) !important;" : level === 'brightness-v3' ? "brightness(110%) !important;" : null;
     1344            $("html").not(this.excludedElements).each(function () {
     1345                let style = $(this).attr("style") || "";
     1346                if (level === 'default') {
     1347                    style = style.replace(/filter:\s*[^;]+;?/, "");
     1348                } else if (['brightness-v1', 'brightness-v2', 'brightness-v3'].includes(level)) {
     1349                    style = style.trim() && !/;$/.test(style.trim()) ? style + ";" : style;
     1350                    style = /filter:\s*[^;]+;?/.test(style) ? style.replace(/filter:\s*[^;]+;?/, "filter: " + filter) : style + " filter: " + filter;
     1351                }
     1352                $(this).attr("style", style.trim());
     1353            });
     1354
     1355            if ($notification) {
     1356                const label = level === 1 ? 'Brightness V1' : level === 2 ? 'Brightness V2' : level === 3 ? 'Brightness V3' : 'Default';
     1357                this.showNotification(`Brightness: ${label}`);
     1358            }
     1359        }
     1360
     1361        grayScaleStyles(level, $notification = true) {
     1362            const filter = level === 'grayscale-v1' ? "grayscale(33%) !important;" : level === 'grayscale-v2' ? "grayscale(66%) !important;" : level === 'grayscale-v3' ? "grayscale(100%) !important;" : null;
     1363            $("html").not(this.excludedElements).each(function () {
     1364                let style = $(this).attr("style") || "";
     1365                if (level === 'default') {
     1366                    style = style.replace(/filter:\s*[^;]+;?/, "");
     1367                } else if (['grayscale-v1', 'grayscale-v2', 'grayscale-v3'].includes(level)) {
     1368                    style = style.trim() && !/;$/.test(style.trim()) ? style + ";" : style;
     1369                    style = /filter:\s*[^;]+;?/.test(style) ? style.replace(/filter:\s*[^;]+;?/, "filter: " + filter) : style + " filter: " + filter;
     1370                }
     1371                $(this).attr("style", style.trim());
     1372            });
     1373
     1374            if ($notification) {
     1375                const label = level === 1 ? 'Grayscale V1' : level === 2 ? 'Grayscale V2' : level === 3 ? 'Grayscale V3' : 'Default';
     1376                this.showNotification(`Grayscale: ${label}`);
     1377            }
     1378        }
     1379
    8931380        highContrastStyles($type, $notification = true) {
    894             const body = $('body'),
    895                 button = $('#accessimate-contrast'),
    896                 buttonText = $('#accessimate-contrast-current'),
    897                 styleSheetId = 'accessimate-high-contrast-styles';
    898 
    899             if ($type === 'default') {
    900                 body.removeClass('accessimate-contrast');
    901                 button.removeClass('active');
    902                 buttonText.text('Contrast');
    903                 this.removeStyles(styleSheetId);
    904                 if ($notification) {
    905                     this.showNotification('High contrast mode disabled', 'info');
    906                 }
    907                 return;
    908             } else {
    909                 body.addClass('accessimate-contrast');
    910                 button.addClass('active');
    911                 buttonText.text(`Contrast: ${$type.charAt(0).toUpperCase() + $type.slice(1)}`);
    912                 if ($notification) {
    913                     this.showNotification('High contrast mode ' + $type.replace('-', ' '), 'success');
    914                 }
    915             }
    916 
     1381            const styleSheetId = 'accessimate-highContrast-styles';
    9171382
    9181383            this.removeStyles(styleSheetId);
    9191384
    9201385            const style = {
    921                 'dark': `
     1386                dark: `
    9221387                    *:not(#accessimate-toolbar):not(#accessimate-toolbar *):not(#accessimate-reading-mask-section,.accessimate-notification, .accessimate-notification *) {
    9231388                        box-shadow: none !important;
     
    9331398                    }
    9341399                `,
    935                 'light': `
     1400                light: `
    9361401                    *:not(#accessimate-toolbar):not(#accessimate-toolbar *):not(#accessimate-reading-mask-section,.accessimate-notification,.accessimate-notification *) {
    9371402                        box-shadow: none !important;
     
    9681433
    9691434            this.injectStyles(styleSheetId, style[$type]);
     1435
     1436            if ($notification) {
     1437                this.showNotification(`High contrast mode: ${$type.charAt(0).toUpperCase() + $type.slice(1)}`, 'success');
     1438            }
     1439        }
     1440
     1441        applyTextStyle($level, {
     1442            property,
     1443            unit = '',
     1444            scaleValues = {},
     1445            excludeInherited = true,
     1446            notificationLabel = '',
     1447        }) {
     1448            const $this = this;
     1449            const scale = scaleValues[$level] ?? 0;
     1450
     1451            $("body, body *").each(function () {
     1452                if ($(this).is($this.excludedElements)) return;
     1453
     1454                // Reset style
     1455                if ($level === 'default' || scale === 0) {
     1456                    $(this).css(property, '');
     1457                    delete this.dataset[`original${property.replace(/-([a-z])/g, (_, char) => char.toUpperCase())}`];
     1458                    return;
     1459                }
     1460
     1461                const computedStyle = window.getComputedStyle(this);
     1462                const parentStyle = window.getComputedStyle(this.parentElement || document.body);
     1463
     1464                const currentValue = computedStyle.getPropertyValue(property);
     1465                const parentValue = parentStyle.getPropertyValue(property);
     1466
     1467                // Skip if inherited
     1468                if (excludeInherited && this !== document.body && currentValue === parentValue) return;
     1469
     1470                const originalKey = `original${property.replace(/-([a-z])/g, (_, char) => char.toUpperCase())}`;
     1471                const originalValue = parseFloat(currentValue);
     1472
     1473                if (isNaN(originalValue)) return;
     1474
     1475                this.dataset[originalKey] = this.dataset[originalKey] || originalValue;
     1476
     1477                const baseValue = parseFloat(this.dataset[originalKey]);
     1478                if (!baseValue) return;
     1479
     1480                const newValue = `${property}: ${(baseValue * (1 + scale)).toFixed(2)}${unit} !important;`;
     1481
     1482                let style = $(this).attr("style") || "";
     1483                style = new RegExp(`${property}:\\s*[^;]+;?`).test(style)
     1484                    ? style.replace(new RegExp(`${property}:\\s*[^;]+;?`), newValue)
     1485                    : style + (style.trim().endsWith(";") || style.trim() === "" ? " " : "; ") + newValue;
     1486
     1487                $(this).attr("style", style.trim());
     1488            });
     1489
     1490            if ($this.showNotification && notificationLabel) {
     1491                const label = $level === 'default' ? 'Default' : notificationLabel;
     1492                $this.showNotification(`${property.replace("-", " ")}: ${label}`);
     1493            }
     1494        }
     1495
     1496        cursorStyles(level, $notification = true) {
     1497            $("html")
     1498                .toggleClass("accessimate-cursor-feature1", level === 'cursor-v1')
     1499                .toggleClass("accessimate-cursor-feature2", level === 'cursor-v2')
     1500                .toggleClass("accessimate-cursor-feature3", level === 'cursor-v3');
     1501
     1502            if ($notification) {
     1503                const label = level === 'cursor-v1' ? 'Cursor V1' : level === 'cursor-v2' ? 'Cursor V2' : level === 'cursor-v3' ? 'Cursor V3' : 'Default';
     1504                this.showNotification(`Cursor: ${label}`);
     1505            }
     1506        }
     1507
     1508        readableFontStyles(level, $notification = true) {
     1509            const $this = this;
     1510            $("*").not(this.excludedElements).each(function () {
     1511                let style = $(this).attr("style") || "";
     1512                if (level === 'enabled') {
     1513                    style = style.trim() && !/;$/.test(style.trim()) ? style + ";" : style;
     1514                    style = /font-family:\s*[^;]+;?/.test(style) ? style.replace(/font-family:\s*[^;]+;?/, "font-family: Roboto, sans-serif !important;") : style + " font-family: Roboto, sans-serif !important;";
     1515                } else if (level === 'disabled' || level === 'default') {
     1516                    style = $this.getPreferences('dyslexicFont') === 'enabled' ? style.replace("font-family: Roboto, sans-serif !important;", "font-family: OpenDyslexic, sans-serif !important;") : style.replace(/font-family:\s*[^;]+;?/, "");
     1517                }
     1518                $(this).attr("style", style.trim());
     1519            });
     1520
     1521            if ($notification) {
     1522                this.showNotification(`Readable Font: ${level === 'enabled' ? 'Enabled' : 'Disabled'}`);
     1523            }
     1524            this.savePreference('readableFont', level);
     1525        }
     1526
     1527        dyslexicFontStyles(level, $notification = true) {
     1528            $("*").not(this.excludedElements).each(function () {
     1529                let style = $(this).attr("style") || "";
     1530                if (level === 'enabled') {
     1531                    style = style.trim() && !/;$/.test(style.trim()) ? style + ";" : style;
     1532                    style = /font-family:\s*[^;]+;?/.test(style) ? style.replace(/font-family:\s*[^;]+;?/, "font-family: OpenDyslexic, sans-serif !important;") : style + " font-family: OpenDyslexic, sans-serif !important;";
     1533                } else if (level === 'disabled' || level === 'default') {
     1534                    style = style.replace(/font-family:\s*[^;]+;?/, "");
     1535                }
     1536                $(this).attr("style", style.trim());
     1537            });
     1538
     1539            if ($notification) {
     1540                this.showNotification(`Dyslexic Font: ${level === 'enabled' ? 'Enabled' : 'Disabled'}`);
     1541            }
     1542            this.savePreference('dyslexicFont', level);
     1543        }
     1544
     1545        saturationStyles(level, $notification = true) {
     1546            const filter = level === 'saturation-v1' ? "saturate(150%) !important;" : level === 'saturation-v2' ? "saturate(200%) !important;" : level === 'saturation-v3' ? "saturate(250%) !important;" : null;
     1547            $("html").not(this.excludedElements).each(function () {
     1548                let style = $(this).attr("style") || "";
     1549                if (level === 'default') {
     1550                    style = style.replace(/filter:\s*[^;]+;?/, "");
     1551                } else if (['saturation-v1', 'saturation-v2', 'saturation-v3'].includes(level)) {
     1552                    style = style.trim() && !/;$/.test(style.trim()) ? style + ";" : style;
     1553                    style = /filter:\s*[^;]+;?/.test(style) ? style.replace(/filter:\s*[^;]+;?/, "filter: " + filter) : style + " filter: " + filter;
     1554                }
     1555                $(this).attr("style", style.trim());
     1556            });
     1557            if ($notification) {
     1558                const label = level === 'saturation-v1' ? 'Saturation V1' : level === 'saturation-v2' ? 'Saturation V2' : level === 'saturation-v3' ? 'Saturation V3' : 'Default';
     1559                this.showNotification(`Saturation: ${label}`);
     1560            }
     1561            this.savePreference('saturation', level);
     1562        }
     1563
     1564        muteSounds(level, $notification = true) {
     1565            if (level === 'enabled') {
     1566                $("audio, video").not(this.excludedElements).prop("muted", true);
     1567                $('iframe[src*="youtube.com"]').each(function () {
     1568                    const src = $(this).attr("src");
     1569                    if (!src.includes("mute=1")) {
     1570                        $(this).attr("src", src + (src.includes("?") ? "&" : "?") + "mute=1");
     1571                    }
     1572                });
     1573            } else {
     1574                $("audio, video").not(this.excludedElements).prop("muted", false);
     1575                $('iframe[src*="youtube.com"]').each(function () {
     1576                    const src = $(this).attr("src");
     1577                    if (src.includes("mute=1")) {
     1578                        $(this).attr("src", src.replace("mute=1", ""));
     1579                    }
     1580                });
     1581            }
     1582            if ($notification) {
     1583                this.showNotification(`Mute Sounds: ${level === 'enabled' ? 'Enabled' : 'Disabled'}`);
     1584            }
     1585            this.savePreference('muteSounds', level);
     1586        }
     1587
     1588        stopAnimations(level, $notification = true) {
     1589            $("*").not(this.excludedElements).each(function () {
     1590                let style = $(this).attr("style") || "";
     1591                if (level === 'enabled') {
     1592                    style = style.trim() && !/;$/.test(style.trim()) ? style + ";" : style;
     1593                    style = /transition:\s*[^;]+;?/.test(style) ? style.replace(/transition:\s*[^;]+;?/, "transition: none !important;") : style + " transition: none !important;";
     1594                    style = /animation:\s*[^;]+;?/.test(style) ? style.replace(/animation:\s*[^;]+;?/, "animation: none !important;") : style + " animation: none !important;";
     1595                } else {
     1596                    style = style.replace(/transition:\s*[^;]+;?/, "").replace(/animation:\s*[^;]+;?/, "");
     1597                }
     1598                $(this).attr("style", style.trim());
     1599            });
     1600            if ($notification) {
     1601                this.showNotification(`Stop Animations: ${level === 'enabled' ? 'Enabled' : 'Disabled'}`);
     1602            }
     1603            this.savePreference('stopAnimations', level);
     1604        }
     1605
     1606        escapeHTML(str) {
     1607            return str.replace(/[&<>"']/g, function (m) {
     1608                return {
     1609                    '&': '&amp;',
     1610                    '<': '&lt;',
     1611                    '>': '&gt;',
     1612                    '"': '&quot;',
     1613                    "'": '&#39;'
     1614                }[m];
     1615            });
     1616        }
     1617
     1618        textToSpeech(level, $notification = true) {
     1619            const $this = this;
     1620
     1621            if (!this._highlightedElement) {
     1622                this._highlightedElement = null;
     1623            }
     1624
     1625            $(document).off("click.accessimateTTS");
     1626
     1627            if (level === 'disabled') {
     1628                window.speechSynthesis.cancel();
     1629                $("*").removeClass("accessimate-highlight");
     1630                this._highlightedElement = null;
     1631
     1632                if ($notification) {
     1633                    $this.showNotification("Text to Speech: Disabled");
     1634                }
     1635
     1636                $this.savePreference('textToSpeech', level);
     1637                return;
     1638            }
     1639
     1640            if (level === 'enabled') {
     1641                $(document).on("click.accessimateTTS", function (e) {
     1642                    if (!window.getSelection().isCollapsed) return;
     1643
     1644                    if ($(e.target).closest("input, textarea, select, .accessimate-panel, .accessimate-panel *").length) return;
     1645
     1646                    const $target = $(e.target).closest("p, span, li, h1, h2, h3, h4, h5, h6, button, a, div");
     1647
     1648                    if ($target.length === 0) {
     1649                        window.speechSynthesis.cancel();
     1650                        if ($this._highlightedElement) {
     1651                            const $el = $($this._highlightedElement);
     1652                            $el.removeClass("accessimate-highlight");
     1653                            $el.find(".accessimate-word-highlight").each(function () {
     1654                                $(this).replaceWith($(this).text());
     1655                            });
     1656                            $this._highlightedElement = null;
     1657                        }
     1658                        return;
     1659                    }
     1660
     1661                    const $element = $target.first();
     1662                    const fullText = $element.clone().children().remove().end().text().trim();
     1663
     1664                    if (!fullText) return;
     1665
     1666                    window.speechSynthesis.cancel();
     1667
     1668                    if ($this._highlightedElement) {
     1669                        const $el = $($this._highlightedElement);
     1670                        $el.removeClass("accessimate-highlight");
     1671                        $el.find(".accessimate-word-highlight").each(function () {
     1672                            $(this).replaceWith($(this).text());
     1673                        });
     1674                        $this._highlightedElement = null;
     1675                    }
     1676
     1677                    $element.addClass("accessimate-highlight");
     1678                    $this._highlightedElement = $element;
     1679
     1680                    const originalHTML = $element.html();
     1681                    const utterance = new SpeechSynthesisUtterance(fullText);
     1682                    utterance.volume = 1;
     1683                    utterance.rate = 1;
     1684
     1685                    utterance.onboundary = function (event) {
     1686                        if (event.name === "word") {
     1687                            const start = event.charIndex;
     1688                            const end = start + event.charLength;
     1689                            const before = fullText.slice(0, start);
     1690                            const word = fullText.slice(start, end);
     1691                            const after = fullText.slice(end);
     1692
     1693                            const highlightedHTML =
     1694                                $this.escapeHTML(before) +
     1695                                `<span class="accessimate-word-highlight">${$this.escapeHTML(word)}</span>` +
     1696                                $this.escapeHTML(after);
     1697
     1698                            $element.html(highlightedHTML);
     1699                        }
     1700                    };
     1701
     1702                    utterance.onend = function () {
     1703                        $element.html(originalHTML);
     1704                        $element.removeClass("accessimate-highlight");
     1705                        $this._highlightedElement = null;
     1706                    };
     1707
     1708                    window.speechSynthesis.speak(utterance);
     1709                });
     1710
     1711                if ($notification) {
     1712                    $this.showNotification("Text to Speech: Enabled (Normal volume and speed)");
     1713                }
     1714
     1715                $this.savePreference('textToSpeech', level);
     1716            }
     1717        }
     1718
     1719        next($key) {
     1720            if (!this.options[$key]) {
     1721                return;
     1722            }
     1723
     1724            const current = this.getPreferences($key) || 'default',
     1725                nextIndex = (this.options[$key].steps.indexOf(current) + 1) % this.options[$key].steps.length,
     1726                nextValue = this.options[$key].steps[nextIndex];
     1727
     1728            this.savePreference($key, nextValue);
     1729            return {
     1730                index: nextIndex,
     1731                value: nextValue
     1732            };
     1733        }
     1734
     1735        updateButtonStatus($key) {
     1736
     1737            if (!this.options[$key]) {
     1738                return;
     1739            }
     1740
     1741            const body = $('body'),
     1742                button = this.getTrigger($key),
     1743                buttonText = button.find('.accessimate-option-label'),
     1744                name = this.options[$key].name || $key.charAt(0).toUpperCase() + $key.slice(1),
     1745                currentType = this.getPreferences($key) || 'default';
     1746
     1747            if (currentType === 'default' || currentType === 'disabled') {
     1748                body.removeClass(`accessimate-${$key}`);
     1749                button.removeClass('active');
     1750                buttonText.text(name);
     1751            } else if (currentType === 'enabled') {
     1752                body.addClass(`accessimate-${$key}`);
     1753                button.addClass('active');
     1754                buttonText.text(name);
     1755            } else if (this.options[$key]?.steps?.includes(currentType)) {
     1756                body.addClass(`accessimate-${currentType}`);
     1757                button.addClass('active');
     1758                buttonText.text(`${currentType.charAt(0).toUpperCase() + currentType.slice(1).replace(/-/g, ' ')}`);
     1759            }
     1760
     1761            if (this.options[$key].steps) {
     1762                this.updateSteps($key);
     1763            }
     1764        }
     1765
     1766        updateSteps(key) {
     1767            const $target = this.options[key].trigger;
     1768            const $steps = this.options[key].steps;
     1769            const $current = this.getPreferences(key) || 'default';
     1770            const $currentIndex = $steps.indexOf($current);
     1771
     1772            const stepWrapper = $target.find('.accessimate-option-step');
     1773            if (stepWrapper.length === 0) {
     1774                return;
     1775            }
     1776            const $createSteps = Array.from($steps).map((option, index) => {
     1777                if (index === 0) return;
     1778                return `<div class="accessimate-option-step-item" data-value="${option}"></div>`;
     1779            }).join('');
     1780
     1781            stepWrapper.html($createSteps);
     1782
     1783            const $currentItemIndex = parseInt($currentIndex, 10) - 1;
     1784            const stepItems = stepWrapper.find('.accessimate-option-step-item');
     1785            stepItems.removeClass('active');
     1786            stepItems.each(function (index) {
     1787
     1788                if (-1 === $currentItemIndex) {
     1789                    $(this).removeClass('active');
     1790                    return;
     1791                }
     1792
     1793                if (index <= $currentItemIndex) {
     1794                    $(this).addClass('active');
     1795                }
     1796            });
    9701797        }
    9711798    }
    9721799
    973     // Initialize when DOM is ready
    974     $(document).ready(function () {
    975         window.AccessiMateToolbar = new AccessiMateToolbar();
    976     });
     1800    window.AccessiMateToolbar = new AccessiMateToolbar();
    9771801
    9781802})(jQuery);
  • accessimate/trunk/readme.txt

    r3332446 r3344806  
    1717= Key Features =
    1818
    19 * **Accessibility Toolbar**: A customizable frontend toolbar with accessibility options
     19= Key Features =
     20
     21* **Accessibility Toolbar**: Fully customizable frontend toolbar with options for position, animation, and theme
     22* **Toolbar Position & Animation**: Choose toolbar placement (e.g., bottom left) and animation style (e.g., slide left)
     23* **Bigger Text**: Increase text size for better readability
     24* **Cursor Enhancements**: Improve cursor visibility for users with visual challenges
     25* **Line Height Adjustment**: Adjust line spacing to reduce text clutter
     26* **Letter Spacing Control**: Increase spacing between letters for clarity
     27* **Readable Font**: Use a clean, legible font for easier reading
     28* **Dyslexic-Friendly Font (Beta)**: Enable a font designed to aid dyslexic users
     29* **Text Alignment Control**: Adjust text alignment for better legibility
     30* **Text Magnifier (Beta)**: Magnify text on hover or focus for better visibility
     31* **Highlight Links**: Highlight all links on the page for quick identification
     32* **Invert Colors**: Invert website colors to reduce eye strain
     33* **Brightness Control**: Adjust screen brightness for comfort
     34* **Contrast Adjustment (Beta)**: Improve content visibility with contrast controls
    2035* **High Contrast Mode**: Toggle high contrast colors for better visibility
    21 * **Font Size Controls**: Allow users to increase or decrease font sizes
     36* **Grayscale Mode**: Convert content to grayscale for focus
     37* **Saturation Adjustment (Beta)**: Adjust color saturation to reduce visual overload
     38* **Reading Line**: Display a horizontal line to follow text while reading
     39* **Reading Mask**: Dim parts of the screen to focus on text
     40* **Highlight All Content**: Highlight all page content for visual tracking
     41* **Highlight Titles (Beta)**: Emphasize headings and titles for easier navigation
     42* **Hide Images**: Hide images to reduce distractions
     43* **Text-to-Speech (Beta)**: AI-powered reading of text for visually impaired users
     44* **Mute Sounds (Beta)**: Silence all site audio for a quieter experience
     45* **Stop Animations**: Stop moving elements to prevent distractions
     46* **Keyboard Navigation (Beta)**: Highlight elements during keyboard navigation
    2247* **Enhanced Focus Indicators**: Improve keyboard navigation visibility
    2348* **Skip Links**: Add skip-to-content links for keyboard users
    24 * **Link Highlighting**: Highlight all links on the page for better visibility
    25 * **Text-to-Speech**: AI-powered text-to-speech functionality
    26 * **Content Scanning**: AI-powered accessibility scanning and suggestions
    27 * **Text Simplification**: AI-powered text simplification for easier reading
    28 * **Alt Text Generation**: AI-powered alt text generation for images
     49* **AI Accessibility Tools**: AI-powered content scanning, text simplification, and alt text generation for images
    2950
    30 = AI-Powered Features =
    31 
    32 AccessiMate includes advanced AI features powered by OpenAI and Google Vision:
    33 
    34 * **Automatic Alt Text**: Generate descriptive alt text for images
    35 * **Content Analysis**: Scan content for accessibility issues
    36 * **Text Simplification**: Provide simplified versions of complex text
    37 * **Speech Synthesis**: Convert text to speech with natural voices
    3851
    3952= Accessibility Standards =
     
    85981. Accessibility toolbar with all options
    86992. Admin settings page - Main settings
    87 3. Admin settings page - AI features
    881004. High contrast mode example
    891015. Font size controls in action
    90102
    91103== Changelog ==
     104
     105= 1.0.1 =
     106* Added toolbar animation options (e.g., slide left)
     107* Added light/dark toolbar theme selection
     108* Added bigger text option for improved readability
     109* Added cursor visibility enhancements
     110* Added line height adjustment
     111* Added letter spacing control
     112* Added readable font option
     113* Added dyslexic-friendly font (Beta)
     114* Added text alignment control
     115* Added text magnifier (Beta)
     116* Added invert colors option
     117* Added brightness control
     118* Added contrast adjustment (Beta)
     119* Added grayscale mode
     120* Added saturation adjustment (Beta)
     121* Added reading line feature
     122* Added reading mask feature
     123* Added highlight all content option
     124* Added highlight titles (Beta)
     125* Added hide images option
     126* Added mute sounds (Beta)
     127* Added stop animations option
     128* Added keyboard navigation enhancements (Beta)
     129* Improved accessibility toolbar customization
     130* Minor UI and performance improvements
    92131
    93132= 1.0.0 =
     
    121160* No personal data is collected or transmitted without user consent
    122161* Session data is used only for preference persistence
    123 
    124 == Third-Party Services ==
    125 
    126 This plugin may connect to the following third-party services when AI features are enabled:
    127 
    128 * **OpenAI API**: For GPT-4 Vision alt text generation and text processing
    129   - Privacy Policy: https://openai.com/privacy/
    130   - Terms of Service: https://openai.com/terms/
    131 
    132 * **Google Vision API**: For image analysis and alt text generation
    133   - Privacy Policy: https://policies.google.com/privacy
    134   - Terms of Service: https://cloud.google.com/terms/
    135 
    136 These connections are only made when:
    137 1. AI features are enabled in settings
    138 2. Valid API keys are configured
    139 3. Users actively use AI-powered features
    140 
    141 == Support ==
    142 
    143 For support, please visit our documentation or contact us through our website.
Note: See TracChangeset for help on using the changeset viewer.