Kaynağa Gözat

Site accessibility: every audited page reaches a Lighthouse score of 100

Baseline was a mean of 90 over 66 page-audits with nothing at 100 and a worst
page of 80. Now 99 page-audits score 100, across guest and member, light and
dark, mobile and desktop. Studio was re-checked and is unaffected.

Accessible names (link-name failed on every page)
- BxBaseMenu::_getMenuTitle() falls back to the sys_menu_items.title_system
  column. The toolbar rows ship with an empty title, which is why the hamburger,
  search, add-content, login and notifications triggers had no name at all;
  title_system is populated for every item, so this names every icon-only menu
  item with no new language keys and no data migration.
- attrs_add becomes the single per-item extra-attributes key, and the duplicate
  implementation in BxBaseStudioMenu is removed.
- _isMenuLabelInContent() keeps an aria-label from hiding a visible counter.
- The site search toggle is a real button; More triggers, design-box menus,
  breadcrumb home, timeline manage and profile action menus all gained names.

Contrast
- Menu, submenu and counter text move to gray-600/gray-400, links to
  blue-600/blue-400, and the login and join agreement text gains underlined
  links. The timeline Load more button is genuinely disabled rather than only
  wearing the class. FullCalendar's faded days and today cell are overridden in
  template/css/fullcalendar.css.

Images, forms and targets
- alt on cover images, avatars and unit thumbnails; menu icon images get alt
  from the shared PHP path.
- Grid filter selects gain a generic aria-label in BxBaseGrid; the uploader
  paste catcher loses its positive tabindex and gains a name; the password
  reveal control is a button with a name and a 24px target.

Structure and keyboard
- One main landmark per page: the nested main in the layout templates, the
  application page type and the splash blocks become div.
- Design-box block titles are h2 and the cover title is a conditional h1, so
  pages have a heading outline for the first time.
- One focus-ring rule covers every link, button, summary and tabindex="0"
  element on the public site, so nothing falls back to the browser default.
  The logo link becomes inline-flex, since an inline box wrapping a block child
  cannot paint a ring at all, and the timeline title box wraps long titles
  instead of clipping them along with the ring.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Andrey Yasko 1 ay önce
ebeveyn
işleme
f436d33548
100 değiştirilmiş dosya ile 525 ekleme ve 214 silme
  1. 7 1
      inc/js/classes/BxDolMenuMoreAuto.js
  2. 27 1
      inc/js/functions.js
  3. 1 1
      inc/js/jquery.dolPopup.js
  4. 16 3
      inc/js/jquery.webForms.js
  5. 2 0
      modules/base/general/classes/BxBaseModGeneralTemplate.php
  6. 2 2
      modules/base/general/template/breadcrumb.html
  7. 1 1
      modules/base/general/template/uploader_button_html5_attach.html
  8. 2 2
      modules/base/groups/template/cover_block.html
  9. 2 2
      modules/base/groups/template/unit.html
  10. 1 1
      modules/base/groups/template/unit_live_search.html
  11. 2 0
      modules/base/profile/classes/BxBaseModProfileTemplate.php
  12. 2 2
      modules/base/profile/template/cover.html
  13. 2 2
      modules/base/profile/template/cover_block.html
  14. 1 1
      modules/base/profile/template/image_popup.html
  15. 2 2
      modules/base/profile/template/unit.html
  16. 1 1
      modules/base/profile/template/unit_live_search.html
  17. 2 2
      modules/base/profile/template/unit_with_cover.html
  18. 1 1
      modules/base/profile/template/unit_wo_info.html
  19. 1 1
      modules/base/profile/template/unit_wo_info_links.html
  20. 1 1
      modules/base/profile/template/unit_wo_links.html
  21. 27 2
      modules/boonex/artificer/data/template/bx_timeline/css/view.css
  22. 2 2
      modules/boonex/artificer/data/template/bx_timeline/item_outline.html
  23. 2 2
      modules/boonex/artificer/data/template/bx_timeline/item_timeline.html
  24. 2 2
      modules/boonex/artificer/data/template/mod_groups/cover.html
  25. 2 2
      modules/boonex/artificer/data/template/mod_groups/cover_block.html
  26. 2 2
      modules/boonex/artificer/data/template/mod_profile/cover.html
  27. 2 2
      modules/boonex/artificer/data/template/mod_profile/cover_block.html
  28. 2 2
      modules/boonex/artificer/data/template/system/_block_explore.html
  29. 2 2
      modules/boonex/artificer/data/template/system/_block_splash.html
  30. 27 6
      modules/boonex/artificer/data/template/system/_header_js_custom.html
  31. 1 1
      modules/boonex/artificer/data/template/system/block_join.html
  32. 1 1
      modules/boonex/artificer/data/template/system/block_login.html
  33. 4 2
      modules/boonex/artificer/data/template/system/cover.html
  34. 2 2
      modules/boonex/artificer/data/template/system/cover_home.html
  35. 10 3
      modules/boonex/artificer/data/template/system/css/forms.css
  36. 1 1
      modules/boonex/artificer/data/template/system/menu_main_submenu.html
  37. 1 1
      modules/boonex/artificer/data/template/system/menu_main_submenu_more_auto.html
  38. 1 1
      modules/boonex/artificer/data/template/system/menu_meta_item.html
  39. 1 1
      modules/boonex/artificer/data/template/system/profile_avatar.html
  40. 1 1
      modules/boonex/artificer/data/template/system/profile_stats.html
  41. 3 3
      modules/boonex/artificer/data/template/system/pt_application.html
  42. 1 0
      modules/boonex/artificer/data/template/system/scripts/BxTemplMenuSidebarSite.php
  43. 13 0
      modules/boonex/artificer/data/template/system/scripts/BxTemplMenuToolbar.php
  44. 1 1
      modules/boonex/artificer/data/template/system/sidebar_account.html
  45. 2 1
      modules/boonex/artificer/data/template/system/sidebar_site.html
  46. 0 0
      modules/boonex/artificer/install/sql/enable.sql
  47. 2 2
      modules/boonex/courses/template/unit_personal.html
  48. 2 2
      modules/boonex/decorous/data/template/bx_organizations/cover.html
  49. 2 2
      modules/boonex/decorous/data/template/bx_persons/cover.html
  50. 4 0
      modules/boonex/forum/classes/BxForumGrid.php
  51. 2 0
      modules/boonex/massmailer/classes/BxMassMailerTemplate.php
  52. 1 0
      modules/boonex/tasks/classes/BxTasksTemplate.php
  53. 1 0
      modules/boonex/timeline/classes/BxTimelineTemplate.php
  54. 8 2
      modules/boonex/timeline/template/css/view.css
  55. 1 1
      modules/boonex/timeline/template/item_outline.html
  56. 1 1
      modules/boonex/timeline/template/item_timeline.html
  57. 1 1
      modules/boonex/timeline/template/load_more.html
  58. 1 1
      modules/boonex/timeline/template/load_more_auto.html
  59. 0 3
      studio/template/scripts/BxBaseStudioMenu.php
  60. 1 1
      template/_page_content_beg.html
  61. 1 1
      template/_page_submenu.html
  62. 4 3
      template/_page_toolbar_search.html
  63. 1 1
      template/comments_uploader_bs.html
  64. 1 1
      template/connection_counter.html
  65. 4 2
      template/cover.html
  66. 1 1
      template/cover_empty.html
  67. 2 1
      template/css/forms.css
  68. 35 0
      template/css/fullcalendar.css
  69. 45 6
      template/css/tailwind.css
  70. 1 1
      template/designbox_1.html
  71. 1 1
      template/designbox_11.html
  72. 1 1
      template/designbox_14.html
  73. 1 1
      template/designbox_4.html
  74. 1 1
      template/form_field_password.html
  75. 4 4
      template/layout_2_columns.html
  76. 8 8
      template/layout_3_columns.html
  77. 8 8
      template/layout_bar_content_bar.html
  78. 4 4
      template/layout_bar_left.html
  79. 4 4
      template/layout_bar_right.html
  80. 4 4
      template/layout_bottom_area_2_columns.html
  81. 4 4
      template/layout_top_area_2_columns.html
  82. 8 8
      template/layout_top_area_3_columns.html
  83. 8 8
      template/layout_top_area_bar_content_bar.html
  84. 4 4
      template/layout_top_area_bar_left.html
  85. 4 4
      template/layout_top_area_bar_right.html
  86. 4 4
      template/layout_topbottom_area_2_columns.html
  87. 4 4
      template/layout_topbottom_area_bar_left.html
  88. 4 4
      template/layout_topbottom_area_bar_right.html
  89. 8 8
      template/layout_topbottom_area_col1_col3_col2.html
  90. 4 4
      template/layout_topbottom_area_col1_col5.html
  91. 8 8
      template/layout_topbottom_area_col2_col5_col3.html
  92. 1 1
      template/pt_application.html
  93. 15 1
      template/scripts/BxBaseCover.php
  94. 12 0
      template/scripts/BxBaseFunctions.php
  95. 19 0
      template/scripts/BxBaseGrid.php
  96. 53 11
      template/scripts/BxBaseMenu.php
  97. 1 1
      template/scripts/BxBaseMenuManage.php
  98. 15 0
      template/scripts/BxBaseMenuMoreAuto.php
  99. 1 0
      template/scripts/BxBaseSearch.php
  100. 1 1
      template/uploader_button_html5.html

+ 7 - 1
inc/js/classes/BxDolMenuMoreAuto.js

@@ -102,7 +102,13 @@ BxDolMenuMoreAuto.prototype.more = function(oElement)
             el: oElement
         }, 
         moveToDocRoot: false,
-        cssClass: 'bx-popup-menu'
+        cssClass: 'bx-popup-menu',
+        onShow: function() {
+            oElement.attr('aria-expanded', 'true');
+        },
+        onHide: function() {
+            oElement.attr('aria-expanded', 'false');
+        }
     });
 }
 

+ 27 - 1
inc/js/functions.js

@@ -501,11 +501,37 @@ function bx_menu_popup (o, e, options, vars) {
     if ('undefined' == typeof(e))
         e = window;
 
+    var bExpanded = e !== window && $(e).length != 0 && $(e).is('[aria-expanded]');
+    var fOnShow = options.onShow, fOnHide = options.onHide;
+
     var o = $.extend({}, $.fn.dolPopupDefaultOptions, {
         id: o, 
         url: bx_append_url_params('menu.php', $.extend({o:o}, vars)), 
         cssClass: 'bx-popup-menu'
-    }, options);
+    }, options, {
+        onShow: function(oPopup) {
+            if(bExpanded)
+                $(e).attr('aria-expanded', 'true');
+
+            // remembered on the popup: the hide handler dolPopup keeps is the one from the first show, whichever trigger opened it since
+            oPopup.data('bx-popup-trigger', bExpanded ? $(e) : null);
+
+            if(typeof fOnShow == 'function')
+                fOnShow(oPopup);
+            else if(typeof fOnShow == 'string')
+                eval(fOnShow);
+        },
+        onHide: function(oPopup) {
+            var oTrigger = oPopup.data('bx-popup-trigger');
+            if(oTrigger && oTrigger.length)
+                oTrigger.attr('aria-expanded', 'false');
+
+            if(typeof fOnHide == 'function')
+                fOnHide(oPopup);
+            else if(typeof fOnHide == 'string')
+                eval(fOnHide);
+        }
+    });
 
     $(e).dolPopupAjax(o);
 }

+ 1 - 1
inc/js/jquery.dolPopup.js

@@ -514,7 +514,7 @@
                 if (!$.isWindow(e[0]))
                     bx_menu_on(e, true);
 
-                $('<div id="' + sPopupId + '" style="display:none;">' + $('#bx-popup-loading').html() + '</div>').appendTo(options.parent).find(options.container).hide();
+                $('<div id="' + sPopupId + '" role="dialog" style="display:none;">' + $('#bx-popup-loading').html() + '</div>').appendTo(options.parent).find(options.container).hide();
 
                 $('#' + sPopupId).addClass($('#bx-popup-loading').attr('class'));
                 

+ 16 - 3
inc/js/jquery.webForms.js

@@ -167,15 +167,15 @@
                 $(this).parents(".bx-form-input-wrapper-password:first").removeClass(sClassFocus);
             });
 
-            $(this).find("a").on("click", function () {
+            $(this).find(".password-show, .password-hide").on("click", function () {
                 var oLink = $(this);
                 var oFld = oLink.parents(".bx-form-input-wrapper-password:first").find("input");
                 if (oLink.hasClass('password-show')) {
-                    oLink.attr('title', _t('_sys_form_input_password_hide'));
+                    oLink.attr('title', _t('_sys_form_input_password_hide')).attr('aria-label', _t('_sys_form_input_password_hide'));
                     oFld.attr("type", "text");
                 }
                 else {
-                    oLink.attr('title', _t('_sys_form_input_password_show'));
+                    oLink.attr('title', _t('_sys_form_input_password_show')).attr('aria-label', _t('_sys_form_input_password_show'));
                     oFld.attr("type", "password");
                 }
                 oLink.toggleClass('password-show password-hide');
@@ -394,6 +394,19 @@
                 }
                 
                 if(bDatePicker) {
+                    // flatpickr's altInput is the field the user actually sees and focuses, but it is a bare clone:
+                    // it copies class/placeholder/disabled/required/tabindex and no accessible name, so carry the
+                    // labelling of the original (now hidden) input over to it.
+                    var oAltInput = this._flatpickr ? this._flatpickr.altInput : null;
+                    if (oAltInput) {
+                        var aLabelAttrs = ['aria-label', 'aria-labelledby', 'aria-describedby', 'title'];
+                        for (var iLabelAttr = 0; iLabelAttr < aLabelAttrs.length; iLabelAttr++) {
+                            var sLabelValue = this.getAttribute(aLabelAttrs[iLabelAttr]);
+                            if (sLabelValue)
+                                oAltInput.setAttribute(aLabelAttrs[iLabelAttr], sLabelValue);
+                        }
+                    }
+
                     if (typeof window.glOnColorSchemeChange === 'undefined')
                         window.glOnColorSchemeChange = [];    
 

+ 2 - 0
modules/base/general/classes/BxBaseModGeneralTemplate.php

@@ -359,9 +359,11 @@ class BxBaseModGeneralTemplate extends BxDolModuleTemplate
     public function entryBreadcrumb($aContentInfo, $aTmplVarsItems = array())
     {
     	$CNF = &BxDolModule::getInstance($this->MODULE)->_oConfig->CNF;
+    	$sTitleHome = BxDolModule::getInstance($this->MODULE)->_aModule['title'];
     	return bx_is_api() ? ['id' => 2, 'type' => 'breadcrumb', 'data' => ['name' => BxDolModule::getInstance($this->MODULE)->_aModule['title'], 'url' => BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME'])]] : $this->parseHtmlByName('breadcrumb.html', [
     		'url_home' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME'])),
     		'icon_home' => $CNF['ICON'],
+    		'title_home' => bx_html_attribute(strip_tags(_t($sTitleHome ? $sTitleHome : '_sys_menu_item_title_system_home')), BX_ESCAPE_STR_QUOTE),
     		'bx_repeat:items' => $aTmplVarsItems
     	]);
     }

+ 2 - 2
modules/base/general/template/breadcrumb.html

@@ -1,6 +1,6 @@
 <div class="bx-base-general-breadcrumb flex items-center">
-    <a class ="bx-base-general-breadcrumb-home" href="__url_home__"><i class="sys-icon __icon_home__"></i></a>
+    <a class ="bx-base-general-breadcrumb-home" href="__url_home__" title="__title_home__" aria-label="__title_home__"><i class="sys-icon __icon_home__" aria-hidden="true"></i></a>
     <bx_repeat:items>
-        <i class="sys-icon chevron-right bx-def-margin-sec-leftright"></i><a href="__url__">__title__</a>
+        <i class="sys-icon chevron-right bx-def-margin-sec-leftright" aria-hidden="true"></i><a href="__url__">__title__</a>
     </bx_repeat:items>
 </div>

+ 1 - 1
modules/base/general/template/uploader_button_html5_attach.html

@@ -1,6 +1,6 @@
 <div>
     <div id="__div_id__" class="filepond bx-uploader-html5-drop-area border-2 border-gray-300 border-dashed rounded-lg hidden"></div>
-    <input type="text" id="__focus_div_id__" class="bx-uploader-html5-paste-catcher" tabindex="1" style="display: none" />
+    <input type="text" id="__focus_div_id__" class="bx-uploader-html5-paste-catcher" tabindex="-1" aria-label="<bx_text_attribute:_sys_uploader_simple_submit_button />" style="display: none" />
     <div id="__errors_container_id__" class="bx-uploader-html5-errors-area bx-def-font-small"></div>
     <div id="__progress_div_id__" class="hidden">
         <div class="w-full bg-gray-200 rounded-full h-1 dark:bg-gray-700">

+ 2 - 2
modules/base/groups/template/cover_block.html

@@ -9,7 +9,7 @@
                     </div>
                     <div class="bx-base-pofile-cover-image relative h-64 lg:h-40 max-w-7xl mx-auto opacity-100 __add_class__">
                         <p class="bx-base-pofile-cover-image box-border absolute h-full w-full" >
-                            <img class="bx-base-pofile-cover-image h-64 mx-auto w-full object-cover bg-cover lg:h-40 rounded-t z-10 __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                            <img alt="" class="bx-base-pofile-cover-image h-64 mx-auto w-full object-cover bg-cover lg:h-40 rounded-t z-10 __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />" />
                         </p>
                     </div>
                 </div>
@@ -19,7 +19,7 @@
                     <bx_if:show_avatar>
                         <div class="bx-base-pofile-cover-thumb __add_class__">
                             <a class="bx-base-pofile-cover-thumb" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
-                                <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
                                 <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
                             </a>
                             <bx_if:show_online>

+ 2 - 2
modules/base/groups/template/unit.html

@@ -1,11 +1,11 @@
 <div class="__class__ p-2 box-border">
     <div class="bx-base-pofile-unit-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box relative h-full overflow-hidden">
         <div class="absolute z-0 w-full h-40 bg-gradient-to-b from-green-400 to-green-500"></div>
-        <a class="bx-base-pofile-unit-cover relative flex items-center justify-start w-full h-40 bg-no-repeat bg-center bg-cover hover:no-underline" style="background-image:url(__cover_url__); __cover_settings__" href="__content_url__" onclick="__content_click__">
+        <a class="bx-base-pofile-unit-cover relative flex items-center justify-start w-full h-40 bg-no-repeat bg-center bg-cover hover:no-underline" style="background-image:url(__cover_url__); __cover_settings__" href="__content_url__" onclick="__content_click__" aria-hidden="true" tabindex="-1">
             <bx_if:show_thumbnail>
                 <div class="bx-def-unit-img bx-def-__size__-size __class_size__ relative ml-5">
                     <bx_if:show_thumb_image>
-                        <img class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ ring-4 ring-white dark:ring-gray-900 rounded-md box-border" src="__thumb_url__" />
+                        <img alt="" class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ ring-4 ring-white dark:ring-gray-900 rounded-md box-border" src="__thumb_url__" />
                     </bx_if:show_thumb_image>
                     <bx_if:show_thumb_letter>
                         <p class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ flex items-center justify-center m-0 text-white font-bold ring-4 ring-white dark:ring-gray-900 rounded-md box-border" style="background-color:rgba(__color__)">__letter__</p>

+ 1 - 1
modules/base/groups/template/unit_live_search.html

@@ -2,7 +2,7 @@
     <a class="bx-def-box bx-def-box-hor bx-def-box-round-corners bx-def-color-bg-box bx-def-color-bg-box-hover relative items-center w-full p-2 box-border" href="__content_url__">
         <div class="bx-def-unit-img bx-def-__size__-size">
             <bx_if:show_thumb_image>
-                <img class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size" src="__thumb_url__" />
+                <img alt="" class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size" src="__thumb_url__" />
             </bx_if:show_thumb_image>
             <bx_if:show_thumb_letter>
                 <p class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size flex items-center justify-center text-white font-bold rounded box-border" style="background-color:rgba(__color__)">__letter__</p>

+ 2 - 0
modules/base/profile/classes/BxBaseModProfileTemplate.php

@@ -591,6 +591,7 @@ class BxBaseModProfileTemplate extends BxBaseModGeneralTemplate
 
             $aTmplVarsShowAvatar = array(
                 'add_class' => $sAddClassPicture,
+                'title_attr' => bx_html_attribute($sTitle),
                 'letter' => mb_strtoupper(mb_substr($sTitle, 0, 1)),
                 'img_class' => $sAddClassPicture != '' ? 'bx-media-editable-src' : '',
                 'ava_url' => $sUrlAvatar,
@@ -625,6 +626,7 @@ class BxBaseModProfileTemplate extends BxBaseModGeneralTemplate
             if($bProfileViewAllowed && $CNF['FIELD_PICTURE'] && $aData[$CNF['FIELD_PICTURE']]) {
                 $sPicturePopup = BxTemplFunctions::getInstance()->transBox($sPicturePopupId, $this->parseHtmlByName('image_popup.html', [
                     'image_url' => $sUrlPicture,
+                    'title_attr' => bx_html_attribute($sTitle),
                 ]), true, true);
             }
         }

+ 2 - 2
modules/base/profile/template/cover.html

@@ -3,7 +3,7 @@
         <div class="bx-base-pofile-cover bx-def-cover-color-bg bx-def-box-sizing">
             <div class="bx-base-pofile-cover-image __add_class__">
                 <p class="bx-base-pofile-cover-image bx-def-box-sizing flex justify-center items-center" >
-                    <img class="bx-base-pofile-cover-image __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />"/>
+                    <img alt="" class="bx-base-pofile-cover-image __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />"/>
                 </p>
                 <div class="bx-cover-gradient"></div>  
             </div>
@@ -12,7 +12,7 @@
                     <bx_if:show_avatar>
                         <div class="bx-base-pofile-cover-thumb __add_class__">
                             <a class="bx-base-pofile-cover-thumb" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
-                                <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
                                 <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>">__letter__</p>
                             </a>
                             <bx_if:show_online>

+ 2 - 2
modules/base/profile/template/cover_block.html

@@ -5,7 +5,7 @@
             <bx_if:show_cover>
                 <div class="bx-base-pofile-cover-image __add_class__">
                     <p class="bx-base-pofile-cover-image bx-def-box-sizing flex justify-center items-center">
-                        <img class="bx-base-pofile-cover-image h-full object-cover bg-cover w-full __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />"/>
+                        <img alt="" class="bx-base-pofile-cover-image h-full object-cover bg-cover w-full __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />"/>
                     </p>
                     
                 </div>
@@ -15,7 +15,7 @@
                     <bx_if:show_avatar>
                         <div class="bx-base-pofile-cover-thumb __add_class__">
                             <a class="bx-base-pofile-cover-thumb" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
-                                <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
                                 <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
                             </a>
                             <bx_if:show_online>

+ 1 - 1
modules/base/profile/template/image_popup.html

@@ -1,3 +1,3 @@
 <div class="bx-base-pofile-popup-wrapper">
-    <img class="bx-base-pofile-popup-image bx-def-border-radius-block" src="__image_url__" />
+    <img class="bx-base-pofile-popup-image bx-def-border-radius-block" src="__image_url__" alt="__title_attr__" />
 </div>

+ 2 - 2
modules/base/profile/template/unit.html

@@ -1,8 +1,8 @@
 <div class="__class__ bx-def-unit flex items-center w-46 mb-4 mr-2">
     <div class="bx-def-unit-img bx-def-__size__ bx-def-__size__-size __class_size__ relative flex-none">
-        <a class="text-center hover:no-underline" href="__content_url__" target="__content_target__"  onclick="__content_click__">
+        <a class="text-center hover:no-underline" href="__content_url__" target="__content_target__"  onclick="__content_click__" aria-hidden="true" tabindex="-1">
             <bx_if:show_thumb_image>
-                <img class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
+                <img alt="" class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
             </bx_if:show_thumb_image>
             <bx_if:show_thumb_letter>
                 <p class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ flex items-center justify-center box-border m-0 rounded-full text-white font-bold" style="background-color:rgba(__color__)">__letter__</p>

+ 1 - 1
modules/base/profile/template/unit_live_search.html

@@ -2,7 +2,7 @@
     <a class="bx-def-box bx-def-box-hor bx-def-box-round-corners bx-def-color-bg-box bx-def-color-bg-box-hover relative items-center w-full p-2 box-border" href="__content_url__">
         <div class="bx-def-unit-img bx-def-__size__-size">
             <bx_if:show_thumb_image>
-                <img class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size" src="__thumb_url__" />
+                <img alt="" class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size" src="__thumb_url__" />
             </bx_if:show_thumb_image>
             <bx_if:show_thumb_letter>
                 <p class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size flex items-center justify-center text-white font-bold rounded-full box-border" style="background-color:rgba(__color__)">__letter__</p>

+ 2 - 2
modules/base/profile/template/unit_with_cover.html

@@ -1,11 +1,11 @@
 <div class="__class__ p-2 box-border">
     <div class="bx-base-pofile-unit-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box relative h-full overflow-hidden">
         <div class="absolute z-0 w-full h-40 bg-gradient-to-b from-blue-400 to-blue-500"></div>
-        <a class="bx-base-pofile-unit-cover relative flex items-center justify-center w-full h-40 bg-no-repeat bg-center bg-cover hover:no-underline" style="background-image:url(__cover_url__);__cover_settings__" href="__content_url__" onclick="__content_click__">
+        <a class="bx-base-pofile-unit-cover relative flex items-center justify-center w-full h-40 bg-no-repeat bg-center bg-cover hover:no-underline" style="background-image:url(__cover_url__);__cover_settings__" href="__content_url__" onclick="__content_click__" aria-hidden="true" tabindex="-1">
             <bx_if:show_thumbnail>
                 <div class="bx-def-unit-img bx-def-__size__-size __class_size__ relative">
                     <bx_if:show_thumb_image>
-                        <img class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
+                        <img alt="" class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
                     </bx_if:show_thumb_image>
                     <bx_if:show_thumb_letter>
                         <p class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ flex items-center justify-center box-border m-0 rounded-full text-white font-bold" style="background-color:rgba(__color__)">__letter__</p>

+ 1 - 1
modules/base/profile/template/unit_wo_info.html

@@ -2,7 +2,7 @@
     <div class="bx-def-unit-img bx-def-__size__-size __class_size__ relative">
         <a class="bx-def-font-align-center" href="__content_url__" target="__content_target__" onclick="__content_click__" title="__title_attr__">
             <bx_if:show_thumb_image>
-                <img class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
+                <img alt="" class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
             </bx_if:show_thumb_image>
             <bx_if:show_thumb_letter>
                 <p class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ flex items-center justify-center box-border m-0 rounded-full text-white font-bold" style="background-color:rgba(__color__)">__letter__</p>

+ 1 - 1
modules/base/profile/template/unit_wo_info_links.html

@@ -1,7 +1,7 @@
 <div class="__class__ bx-def-__size__-size __class_size__ text-center">
     <div class="bx-def-unit-img bx-def-__size__-size __class_size__ relative">
         <bx_if:show_thumb_image>
-            <img class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
+            <img alt="" class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
         </bx_if:show_thumb_image>
         <bx_if:show_thumb_letter>
             <p class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ flex items-center justify-center box-border m-0 rounded-full text-white font-bold" style="background-color:rgba(__color__)">__letter__</p>

+ 1 - 1
modules/base/profile/template/unit_wo_links.html

@@ -1,7 +1,7 @@
 <div class="__class__ bx-def-unit flex items-center w-46 mb-4 mr-2">
     <div class="bx-def-unit-img bx-def-__size__-size __class_size__ relative">
         <bx_if:show_thumb_image>
-            <img class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
+            <img alt="" class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ rounded-full box-border" src="__thumb_url__" />
         </bx_if:show_thumb_image>
         <bx_if:show_thumb_letter>
             <p class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ flex items-center justify-center box-border m-0 rounded-full text-white font-bold" style="background-color:rgba(__color__)">__letter__</p>

+ 27 - 2
modules/boonex/artificer/data/template/bx_timeline/css/view.css

@@ -82,8 +82,14 @@ div.bx-tl-item-content form {
     padding: 1rem 1rem 0 1rem;
 }
 div.bx-tl-item-content div.bx-tl-title {
-    text-overflow: ellipsis;
-    overflow: hidden;
+    /* This box used to be `overflow: hidden`, which clipped the focus ring of the title link sitting
+       flush inside it. The clipping was really there to stop a long unbroken title from widening the
+       page, and wrapping does that without hiding anything; `text-overflow` never applied here anyway,
+       the box is a flex container. */
+    overflow-wrap: anywhere;
+}
+div.bx-tl-item-content div.bx-tl-title div.bx-tl-title-cnt {
+    min-width: 0;
 }
 div.bx-tl-item-text div.bx-tl-content {
     position: relative;
@@ -136,6 +142,25 @@ div.bx-tl-item div.bx-tl-item-activity.bx-tl-ia-counters .bx-menu-custom.bx-menu
     height: 2.5rem;
 }
 
+/*--- Item Owner: Name ---*/
+/* The owner-info wrapper is `overflow-hidden` (Tailwind), which would clip the
+   extra hit area added below; the name itself still truncates via `.truncate`. */
+div.bx-tl-item div.bx-tl-owner-info {
+    overflow: visible;
+}
+
+/* WCAG 2.5.8 (AA): the author link must be at least 24x24 CSS px. The extra
+   height is added as padding-top cancelled by an equal negative margin-top, so
+   the link's box grows UPWARD into the gap that already sits above the header
+   row. The text position, the row height, the meta row below and the card
+   height are all unchanged, and the box never reaches the date link beneath. */
+div.bx-tl-item div.bx-tl-owner-name > a.bx-tl-owner-name {
+    min-height: 1.5rem;
+
+    padding-top: 0.375rem;
+    margin-top: -0.375rem;
+}
+
 /*--- Menu: Item Manage ---*/
 .bx-menu-object-bx_timeline_menu_item_manage .sys-action-do-text {
     margin-left: 0rem;

+ 2 - 2
modules/boonex/artificer/data/template/bx_timeline/item_outline.html

@@ -37,7 +37,7 @@
                                 <bx_if:show_timeline_owner>
                                     <span class="mr-1"><bx_text:_bx_timeline_txt_to /></span> 
                                     <span class="__style_prefix__-timeline-owner-name mr-1">
-                                        <bx_repeat:owners><span class="__style_prefix__-ton-div">, </span><a href="__owner_url__" class="__style_prefix__-ton-item text-blue-600 dark:text-blue-500 font-semibold hover:underline">__owner_username__</a></bx_repeat:owners>
+                                        <bx_repeat:owners><span class="__style_prefix__-ton-div">, </span><a href="__owner_url__" class="__style_prefix__-ton-item text-blue-600 dark:text-blue-400 font-semibold hover:underline">__owner_username__</a></bx_repeat:owners>
                                     </span> 
                                 </bx_if:show_timeline_owner>
                             </div>
@@ -77,7 +77,7 @@
                 </bx_if:show_menu_item_actions>
                <bx_if:show_manage>
                 <div class="__style_prefix__-item-manage">
-                    <a class="group bx-stl-mil-sm" href="javascript:void(0)" onclick="__onclick__">
+                    <a class="group bx-stl-mil-sm" href="javascript:void(0)" onclick="__onclick__" title="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-label="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-haspopup="dialog" aria-expanded="false">
                         <span class="bx-menu-item-icon bx-def-align-center leading-5"><i class="sys-icon ellipsis-h"></i></span>
                     </a>
                 </div>

+ 2 - 2
modules/boonex/artificer/data/template/bx_timeline/item_timeline.html

@@ -36,7 +36,7 @@
                             <bx_if:show_timeline_owner>
                                 <span class="mr-1"><bx_text:_bx_timeline_txt_to /></span> 
                                 <span class="__style_prefix__-timeline-owner-name mr-1">
-                                    <bx_repeat:owners><span class="__style_prefix__-ton-div">, </span><a href="__owner_url__" class="__style_prefix__-ton-item text-blue-600 dark:text-blue-500 font-semibold hover:underline">__owner_username__</a></bx_repeat:owners>
+                                    <bx_repeat:owners><span class="__style_prefix__-ton-div">, </span><a href="__owner_url__" class="__style_prefix__-ton-item text-blue-600 dark:text-blue-400 font-semibold hover:underline">__owner_username__</a></bx_repeat:owners>
                                 </span> 
                             </bx_if:show_timeline_owner>
                         </div>
@@ -80,7 +80,7 @@
             </bx_if:show_menu_item_actions>
             <bx_if:show_manage>
                 <div class="__style_prefix__-item-manage">
-                    <a class="group bx-lnk-cnt bx-stl-mil-sm" href="javascript:void(0)" onclick="__onclick__">
+                    <a class="group bx-lnk-cnt bx-stl-mil-sm" href="javascript:void(0)" onclick="__onclick__" title="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-label="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-haspopup="dialog" aria-expanded="false">
                         <span class="bx-menu-item-icon bx-def-align-center leading-5"><i class="sys-icon ellipsis-h"></i></span>
                     </a>
                 </div>

+ 2 - 2
modules/boonex/artificer/data/template/mod_groups/cover.html

@@ -4,7 +4,7 @@
             <div class="bx-base-pofile-cover-image-wrp relative xl:px-4 overflow-hidden">
                 <div class="bx-base-pofile-cover-image bx-def-page-width relative mx-auto opacity-100 xl:rounded-b-lg <bx_if:show_cover_placeholder>bx-bpci-holder h-32 lg:h-32 bg-gradient-to-b from-green-400 to-green-500</bx_if:show_cover_placeholder><bx_if:show_cover>h-64 lg:h-80</bx_if:show_cover> __add_class__ ">
                     <p class="bx-base-pofile-cover-image box-border absolute h-full w-full flex justify-center items-center">
-                        <img class="bx-base-pofile-cover-image w-full object-cover bg-cover xl:rounded-b-lg h-full relative __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                        <img alt="" class="bx-base-pofile-cover-image w-full object-cover bg-cover xl:rounded-b-lg h-full relative __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />" />
                     </p>
                     __cover_tweak__
                 </div>
@@ -15,7 +15,7 @@
                     <bx_if:show_avatar>
                         <div class="bx-base-pofile-cover-thumb relative lg:absolute flex justify-center lg:flex-none z-10 __add_class__">
                             <a class="bx-base-pofile-cover-thumb hover:no-underline" href="__picture_href__" >
-                                <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
                                 <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
                             </a>
                             <bx_if:show_online>

+ 2 - 2
modules/boonex/artificer/data/template/mod_groups/cover_block.html

@@ -6,7 +6,7 @@
                 <div class="bx-base-pofile-cover-image-wrp relative overflow-hidden">
                     <div class="bx-base-pofile-cover-image relative h-64 lg:h-40 max-w-7xl mx-auto opacity-100 bg-gradient-to-b from-blue-400 to-blue-500 rounded-t-md __add_class__">
                         <p class="bx-base-pofile-cover-image box-border absolute h-full w-full">
-                            <img class="bx-base-pofile-cover-image relative h-64 mx-auto w-full object-cover bg-cover lg:h-40 rounded-t-md __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                            <img alt="" class="bx-base-pofile-cover-image relative h-64 mx-auto w-full object-cover bg-cover lg:h-40 rounded-t-md __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />" />
                         </p>
                     </div>
                 </div>
@@ -16,7 +16,7 @@
                     <bx_if:show_avatar>
                         <div class="bx-base-pofile-cover-thumb relative inline-flex justify-center __add_class__">
                             <a class="bx-base-pofile-cover-thumb" href="__picture_href__" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
-                                <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
                                 <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
                             </a>
                             <bx_if:show_online>

+ 2 - 2
modules/boonex/artificer/data/template/mod_profile/cover.html

@@ -4,7 +4,7 @@
             <div class="bx-base-pofile-cover-image-wrp relative xl:px-4 overflow-hidden">
                 <div class="bx-base-pofile-cover-image bx-def-page-width relative mx-auto opacity-100 xl:rounded-b-lg <bx_if:show_cover_placeholder>bx-bpci-holder h-32 lg:h-32 bg-gradient-to-b from-blue-400 to-blue-500</bx_if:show_cover_placeholder><bx_if:show_cover>h-64 lg:h-80</bx_if:show_cover> __add_class__">
                     <p class="bx-base-pofile-cover-image box-border absolute h-full w-full">
-                        <img class="bx-base-pofile-cover-image w-full object-cover bg-cover xl:rounded-b-lg h-full relative __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                        <img alt="" class="bx-base-pofile-cover-image w-full object-cover bg-cover xl:rounded-b-lg h-full relative __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />" />
                     </p>
                     __cover_tweak__
                 </div>
@@ -14,7 +14,7 @@
                     <bx_if:show_avatar>
                         <div class="bx-base-pofile-cover-thumb bx-def-ava-big-size relative lg:absolute flex self-center lg:flex-none z-10 __add_class__">
                             <a class="bx-base-pofile-cover-thumb hover:no-underline" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
-                                <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
                                 <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
                             </a>
                             <bx_if:show_online>

+ 2 - 2
modules/boonex/artificer/data/template/mod_profile/cover_block.html

@@ -6,7 +6,7 @@
                 <div class="bx-base-pofile-cover-image-wrp relative overflow-hidden">
                     <div class="bx-base-pofile-cover-image relative h-64 lg:h-40 max-w-7xl mx-auto opacity-100 bg-gradient-to-b from-blue-400 to-blue-500 rounded-t-md __add_class__">
                         <p class="bx-base-pofile-cover-image box-border absolute h-full w-full">
-                            <img class="bx-base-pofile-cover-image relative h-64 mx-auto w-full object-cover bg-cover lg:h-40 rounded-t-md __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                            <img alt="" class="bx-base-pofile-cover-image relative h-64 mx-auto w-full object-cover bg-cover lg:h-40 rounded-t-md __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />" />
                         </p>
                     </div>
                 </div>
@@ -16,7 +16,7 @@
                     <bx_if:show_avatar>
                         <div class="bx-base-pofile-cover-thumb relative inline-flex justify-center __add_class__">
                             <a class="bx-base-pofile-cover-thumb" href="__picture_href__" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
-                                <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
                                 <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
                             </a>
                             <bx_if:show_online>

+ 2 - 2
modules/boonex/artificer/data/template/system/_block_explore.html

@@ -15,7 +15,7 @@
         <img src="<bx_image_url:cover-dark.svg />" class="object-cover h-full w-full" />
     </div>
     <div class="relative pb-8 z-2">
-        <main class="mt-6">
+        <div class="mt-6">
             <div class="mx-auto max-w-7xl">
                 <div class="lg:grid lg:grid-cols-12 lg:gap-8">
                     <div class="px-6 lg:px-8 text-center md:max-w-2xl md:mx-auto lg:col-span-6 lg:text-left lg:flex lg:items-center">
@@ -56,6 +56,6 @@
                     </div>
                 </div>
             </div>
-        </main>
+        </div>
     </div>
 </div>

+ 2 - 2
modules/boonex/artificer/data/template/system/_block_splash.html

@@ -16,7 +16,7 @@
         <div class="absolute top-0 left-0 w-full h-full hidden dark:block z-1">
             <img src="<bx_image_url:cover-dark.svg />" class="object-cover h-full w-full" />
         </div>
-        <main class="relative mt-16 z-2">
+        <div class="relative mt-16 z-2">
             <div class="mx-auto max-w-7xl">
                 <div class="lg:grid lg:grid-cols-12 lg:gap-8">
                     <div class="px-6 lg:px-8 text-center md:max-w-2xl md:mx-auto lg:col-span-6 lg:text-left lg:flex lg:items-center">
@@ -57,7 +57,7 @@
                     </div>
                 </div>
             </div>
-        </main>
+        </div>
     </div>
 </div>
 <div class="bg-gray-100 dark:bg-gray-900 pt-12 sm:pt-16">

+ 27 - 6
modules/boonex/artificer/data/template/system/_header_js_custom.html

@@ -45,6 +45,20 @@
                     $(aFocusable[0]).focus();
             });
         }
+
+        //--- Escape closes whichever sidebar is open; bx_sidebar_toggle returns focus to its trigger.
+        $(document).on('keydown.bx-sidebar', function(event) {
+            if(event.which != 27 && event.key != 'Escape')
+                return;
+
+            for(var j in aSidebars) {
+                if(typeof(aSidebars[j]) != 'string' || !bx_sidebar_active(aSidebars[j]))
+                    continue;
+
+                event.preventDefault();
+                bx_sidebar_toggle(aSidebars[j]);
+            }
+        });
     });
 
     function bx_sidebar_get(sType) {
@@ -65,24 +79,31 @@
 
         oSidebar.toggleClass('bx-sidebar-active', !bSidebarActive);
 
+        var oTrigger = $('.bx-sidebar-' + sType + '-trigger');
+        oTrigger.attr('aria-expanded', !bSidebarActive ? 'true' : 'false');
+
         if(!bSidebarActive) {
             var aFocusable = bx_get_focusable(oSidebar.get(0));
             if(aFocusable && aFocusable.length > 0)
                 $(aFocusable[0]).focus();
         }
-        else 
-            $(bx_clicked_stack_pop()).focus();
+        else {
+            var oReturnTo = bx_clicked_stack_pop();
+            $(oReturnTo ? oReturnTo : oTrigger.filter(':visible').get(0)).focus();
+        }
     }
 
     function bx_sidebar_dropdown_toggle(oLink) {
-        $(oLink).parents('.bx-sidebar-item:first').toggleClass('bx-si-dropdown-open').find('.bx-si-dropdown-icon').toggleClass('rotate-0 rotate-90');
+        var oItem = $(oLink).parents('.bx-sidebar-item:first');
+        oItem.toggleClass('bx-si-dropdown-open').find('.bx-si-dropdown-icon').toggleClass('rotate-0 rotate-90');
+        $(oLink).attr('aria-expanded', oItem.hasClass('bx-si-dropdown-open') ? 'true' : 'false');
 
         return false;
     }
 
     function bx_site_search_show(oButtom) {
         var oButton = $(oButtom).parents('.bx-ti-search-button');
-        oButton.addClass('bx-tis-button-hidden');
+        oButton.addClass('bx-tis-button-hidden').find('button,a').attr('aria-expanded', 'true');
 
         var oBox = oButton.parents('.bx-ti-search').find('.bx-ti-search-box');
         oBox.addClass('bx-tis-box-shown');
@@ -96,7 +117,7 @@
                 else {
                     bx_site_search_close_all_opened();
                     oBox.removeClass('bx-tis-box-shown');
-                    oButton.removeClass('bx-tis-button-hidden').find('a').focus();
+                    oButton.removeClass('bx-tis-button-hidden').find('button,a').attr('aria-expanded', 'false').focus();
                 }
             });
         }, 10);
@@ -142,7 +163,7 @@
         if(oBox.hasClass(sClassBox) && oButton.hasClass(sClassButton)) {
             bx_site_search_close_all_opened();
             oBox.removeClass(sClassBox);
-            oButton.removeClass(sClassButton).find('a').focus();
+            oButton.removeClass(sClassButton).find('button,a').attr('aria-expanded', 'false').focus();
         }
     }
 

+ 1 - 1
modules/boonex/artificer/data/template/system/block_join.html

@@ -9,6 +9,6 @@
     </bx_if:show_login>
     <div class="sys-jf-agreement -mx-4">
         <hr class="bx-def-hr mt-4" />
-        <div class="sys-jf-agreement-cnt pt-4 px-4 text-xs text-gray-500">__agreement__</div>
+        <div class="sys-jf-agreement-cnt pt-4 px-4 text-xs text-gray-600 dark:text-gray-400 [&_a]:underline [&_a]:underline-offset-2">__agreement__</div>
     </div>
 </div>

+ 1 - 1
modules/boonex/artificer/data/template/system/block_login.html

@@ -11,7 +11,7 @@
     </bx_if:show_join>
     <div class="sys-lf-agreement -mx-4">
         <hr class="bx-def-hr mt-4" />
-        <div class="sys-lf-agreement-cnt pt-4 px-4 text-xs text-gray-500">__agreement__</div>
+        <div class="sys-lf-agreement-cnt pt-4 px-4 text-xs text-gray-600 dark:text-gray-400 [&_a]:underline [&_a]:underline-offset-2">__agreement__</div>
     </div>
     <bx_if:show_js_code>
         <script>

+ 4 - 2
modules/boonex/artificer/data/template/system/cover.html

@@ -16,10 +16,12 @@
                     </div>
                 </bx_if:image>
                 <div class="bx-cover-title flex justify-center items-center">
-                    <div class="text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-50">
+                    <bx_if:title>
+                    <h1 class="text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-50">
                         <span class="block pb-1 relative">__title__</span>
                         <span class="block pb-1 bg-clip-text text-transparent bg-gradient-to-r from-green-500 to-blue-500"></span>
-                    </div>
+                    </h1>
+                    </bx_if:title>
                 </div>
                 <div class="bx-cover-actions">__actions__</div>
             </div>

+ 2 - 2
modules/boonex/artificer/data/template/system/cover_home.html

@@ -11,10 +11,10 @@
             <div class="bx-cover-gradient bx-def-page-width relative mx-auto"></div>
             <div class="relative mx-auto py-16 text-center">
                 <div>
-                    <div class="text-4xl  sm:text-5xl xl:text-6xl tracking-tight  font-bold text-gray-800 dark:text-white ">
+                    <h1 class="text-4xl  sm:text-5xl xl:text-6xl tracking-tight  font-bold text-gray-800 dark:text-white ">
                         <span class="block pb-1 relative"><bx_text:_bx_artificer_txt_splash_welcome_l1 /></span>
                         <span class="block pb-1  bg-clip-text text-transparent bg-gradient-to-r from-green-500 to-blue-500"><bx_text:_bx_artificer_txt_splash_welcome_l2 /></span>
-                    </div>
+                    </h1>
                     <p class="p-8  font-light text-gray-700 dark:text-gray-300 text-base  sm:text-lg xl:text-xl">
                         <span class="block"><bx_text:_bx_artificer_txt_splash_welcome_l3 /></span>
                     </p>

+ 10 - 3
modules/boonex/artificer/data/template/system/css/forms.css

@@ -128,7 +128,8 @@ import url(../../../../../../../template/css/forms.css);
 
 
 /*-- Form field: Password --*/
-.bx-artificer .bx-form-input-wrapper-password > a {
+.bx-artificer .bx-form-input-wrapper-password > .password-show,
+.bx-artificer .bx-form-input-wrapper-password > .password-hide {
     position: absolute;
     z-index: 1000;
     
@@ -143,9 +144,15 @@ import url(../../../../../../../template/css/forms.css);
     right: 0;    
     height: 100%;
 
-    margin: 0 0.5rem;
+    /* WCAG 2.5.8 (AA): at least 24px wide. 1.75rem is the project's "mini"
+       button size. The side margin is reduced by exactly half the added
+       width, (28px - 18px) / 2 = 5px, so the eye glyph does not move. */
+    min-width: 1.75rem;
+
+    margin: 0 0.1875rem;
 }
-.bx-dir-rtl.bx-artificer .bx-form-input-wrapper-password > a {
+.bx-dir-rtl.bx-artificer .bx-form-input-wrapper-password > .password-show,
+.bx-dir-rtl.bx-artificer .bx-form-input-wrapper-password > .password-hide {
     left: 0;
     right: auto;
 }

+ 1 - 1
modules/boonex/artificer/data/template/system/menu_main_submenu.html

@@ -1,7 +1,7 @@
 <ul id="bx-menu-main-submenu" class="bx-menu-main-submenu bx-menu-object-__object__ inline-flex items-stretch w-max">
     <bx_repeat:menu_items>
         <li class="bx-menu-item bx-menu-item-__name__ __class_add__ flex" __attrs_wrp__>
-            <a class="group block relative py-4 px-4 text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-200 whitespace-nowrap text-sm font-medium text-center hover:bg-transparent focus:z-10 box-sizing" href="__link__" <bx_if:onclick>onclick="__onclick__"</bx_if:onclick> __attrs__>
+            <a class="group block relative py-4 px-4 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-200 whitespace-nowrap text-sm font-medium text-center hover:bg-transparent focus:z-10 box-sizing" href="__link__" <bx_if:onclick>onclick="__onclick__"</bx_if:onclick> __attrs__>
                 <bx_if:title>
                     <span class="bx-menu-item-title">__title__</span>
                 </bx_if:title>

+ 1 - 1
modules/boonex/artificer/data/template/system/menu_main_submenu_more_auto.html

@@ -1,7 +1,7 @@
 <ul id="__html_id__" class="bx-menu-main-submenu<bx_if:show_more_auto_class> bx-menu-more-auto</bx_if:show_more_auto_class> bx-menu-object-__object__ flex items-stretch">
     <bx_repeat:menu_items>
         <li class="bx-menu-item bx-menu-item-__name__ __class_add__ flex" __attrs_wrp__>
-            <a href="__link__" <bx_if:onclick>onclick="__onclick__"</bx_if:onclick> class="group block relative py-4 px-4 text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-200 whitespace-nowrap text-sm font-medium text-center hover:bg-transparent focus:z-10 box-sizing"__attrs__><bx_if:title>__title__</bx_if:title><span class="bx-mi-underline absolute inset-x-0 bottom-0 h-0.5 group-hover:bg-gray-500 rounded-md"></span></a>__popup__
+            <a href="__link__" <bx_if:onclick>onclick="__onclick__"</bx_if:onclick> class="group block relative py-4 px-4 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-200 whitespace-nowrap text-sm font-medium text-center hover:bg-transparent focus:z-10 box-sizing"__attrs__><bx_if:title>__title__</bx_if:title><span class="bx-mi-underline absolute inset-x-0 bottom-0 h-0.5 group-hover:bg-gray-500 rounded-md"></span></a>__popup__
         </li>
     </bx_repeat:menu_items>
 </ul>

+ 1 - 1
modules/boonex/artificer/data/template/system/menu_meta_item.html

@@ -1,4 +1,4 @@
-<span class="group flex items-center p-1 border-none rounded-full text-gray-500 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600">
+<span class="group flex items-center p-1 border-none rounded-full text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600">
     <span class="sys-action-counter-icon relative flex items-center justify-center ring-1  h-6 w-6 rounded-full ring-white dark:ring-gray-700 bg-gray-200 dark:bg-gray-700">__icon__</span>
     <span class="sys-action-counter-text ltr:ml-1 rtl:mr-1">__caption__</span>
 </span>

+ 1 - 1
modules/boonex/artificer/data/template/system/profile_avatar.html

@@ -6,7 +6,7 @@
                 <div class="bx-pai-line text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-white font-semibold truncate">
                     <a href="__profile_url__" title="__profile_title_attr__">__profile_title__</a>
                 </div>
-                <div class="bx-pai-line text-green-600 dark:text-green-400 text-xs font-normal truncate uppercase tracking-wider">
+                <div class="bx-pai-line text-green-700 dark:text-green-400 text-xs font-normal truncate uppercase tracking-wider">
                     <!--<bx_include_auto:menu_icon.html />--><span>__profile_acl_title__</span>
                 </div>
             </div>

+ 1 - 1
modules/boonex/artificer/data/template/system/profile_stats.html

@@ -6,7 +6,7 @@
                 <div class="bx-pa-info w-full">
                     <div class="bx-pa-info-cnt flex flex-col justify-center h-10 pl-10 box-border">
                         <div class="bx-pai-line text-gray-600 dark:text-gray-300 group-hover:text-gray-800 dark:group-hover:text-white font-semibold truncate">__profile_title__</div>
-                        <div class="bx-pai-line text-green-600 dark:text-green-400 text-xs truncate uppercase tracking-wider font-normal">
+                        <div class="bx-pai-line text-green-700 dark:text-green-400 text-xs truncate uppercase tracking-wider font-normal">
                             <div><!--<bx_include_auto:menu_icon.html />--><span>__profile_acl_title__</span></div>
                         </div>
                     </div>

+ 3 - 3
modules/boonex/artificer/data/template/system/pt_application.html

@@ -64,7 +64,7 @@
 
         <!-- BEG: Main Content -->
         <div id="main-content" class="bx-main-column wide relative w-full h-full overflow-y-auto xl:ml-64">
-            <main>
+            <div>
                 <bx_injection:injection_between_cover_logo />
                 __cover__
                 <bx_injection:injection_between_cover_top_menu />
@@ -91,7 +91,7 @@
                     __informer__
                     <div class="bx-page-wrapper mx-auto px-3 md:px-4 lg:px-6 box-border">
                         <div id="bx-content-container" class="bx-content-container">
-                            <main role="main"  id="bx-content-main" class="bx-content-main my-2 lg:my-3">
+                            <main role="main"  id="bx-content-main" class="bx-content-main my-2 lg:my-3" tabindex="-1">
                                 <bx_injection:injection_content_before />
                                 __page_main_code__
                                 <bx_injection:injection_content_after />
@@ -101,7 +101,7 @@
                         </div> <!-- #bx-content-container -->
                     </div> <!-- .bx-page-wrapper -->
                 </div> <!-- #bx-content-wrapper -->
-            </main>
+            </div>
             <footer class="p-4 m-4 bg-white rounded-lg shadow md:flex md:items-center md:justify-between md:p-6 xl:p-8 dark:bg-gray-800">
                 <bx_injection:injection_footer_before />
                 <div id="bx-menu-bottom">

+ 1 - 0
modules/boonex/artificer/data/template/system/scripts/BxTemplMenuSidebarSite.php

@@ -43,6 +43,7 @@ class BxTemplMenuSidebarSite extends BxTemplMenu
                     'onclick' => "javascript:return bx_sidebar_dropdown_toggle(this)"
             ]];
             $aResult['class_add'] .= ' bx-si-dropdown-has';
+            $aResult['attrs'] .= ' aria-expanded="false"';
 
             $aSubmenuItems = $oSubmenu->getMenuItemsRaw();
             if($oSubmenu->isHtmx() && !$this->_isSelected($a) && !array_key_exists($this->_sPageUri, $aSubmenuItems))

+ 13 - 0
modules/boonex/artificer/data/template/system/scripts/BxTemplMenuToolbar.php

@@ -49,17 +49,22 @@ class BxTemplMenuToolbar extends BxBaseMenuToolbar
             return $a;
 
         $a['class_add_a'] = '';
+
+        //--- Each of these items is a disclosure: it opens a sidebar or a popup instead of following a link.
+        $sAttrsAdd = '';
         switch ($a['name']) {
             case 'main-menu':
                 $a['class_add_a'] = ' bx-sidebar-site-trigger';
                 $a['link'] = 'javascript:void(0)';
                 $a['onclick'] = '';
+                $sAttrsAdd = 'aria-haspopup="dialog" aria-expanded="false" aria-controls="bx-sidebar-site"';
                 break;
 
             case 'account':
                 $a['class_add_a'] = ' bx-sidebar-account-trigger';
                 $a['link'] = 'javascript:void(0)';
                 $a['onclick'] = '';
+                $sAttrsAdd = 'aria-haspopup="dialog" aria-expanded="false" aria-controls="bx-sidebar-account"';
                 break;
 
             case 'add-content':
@@ -67,14 +72,22 @@ class BxTemplMenuToolbar extends BxBaseMenuToolbar
 
                 if(isset($a['bx_if:onclick']['content']['onclick']))
                     $a['bx_if:onclick']['content']['onclick'] = str_replace('bx_menu_slide_inline', 'bx_menu_popup_inline', $a['bx_if:onclick']['content']['onclick']);
+
+                $sAttrsAdd = 'aria-haspopup="true" aria-expanded="false" aria-controls="bx-sliding-menu-sys_add_content"';
                 break;
 
             case 'notifications-preview':
                 if(isset($a['bx_if:onclick']['content']['onclick']))
                     $a['bx_if:onclick']['content']['onclick'] = str_replace(["bx_menu_slide", "'site', "], ['bx_menu_popup'], $a['bx_if:onclick']['content']['onclick']);
+
+                //--- No aria-controls: bx_menu_popup() creates the popup lazily, so the id does not exist yet.
+                $sAttrsAdd = 'aria-haspopup="dialog" aria-expanded="false"';
                 break;
         }
 
+        if($sAttrsAdd && isset($a['attrs']))
+            $a['attrs'] .= ' ' . $sAttrsAdd;
+
         return $a;
     }
 }

+ 1 - 1
modules/boonex/artificer/data/template/system/sidebar_account.html

@@ -1,4 +1,4 @@
-<div class="bx-sidebar bx-sidebar-account bx-def-z-index-modal fixed flex flex-row justify-end inset-0" role="dialog" aria-modal="true">
+<div id="bx-sidebar-account" class="bx-sidebar bx-sidebar-account bx-def-z-index-modal fixed flex flex-row justify-end inset-0" role="dialog" aria-modal="true" aria-label="<bx_text:_sys_menu_item_title_system_account_menu />">
     <div class="bx-sidebar-account-bg fixed inset-0 bg-gray-600 opacity-75" aria-hidden="true"></div>
     <div class="flex-shrink-0 w-12" aria-hidden="true"></div>
     <div class="bx-sidebar-cnt relative flex max-w-xs w-full py-4 bg-white dark:bg-gray-900">

+ 2 - 1
modules/boonex/artificer/data/template/system/sidebar_site.html

@@ -1,4 +1,4 @@
-<div class="bx-sidebar bx-sidebar-site bx-def-z-index-modal fixed flex lg:hidden inset-0" role="dialog" aria-modal="true">
+<div id="bx-sidebar-site" class="bx-sidebar bx-sidebar-site bx-def-z-index-modal fixed flex lg:hidden inset-0" role="dialog" aria-modal="true" aria-label="<bx_text:_sys_menu_item_title_system_main_menu />">
     <div class="bx-sidebar-site-bg fixed inset-0 bg-gray-600 opacity-75" aria-hidden="true"></div>
     <div class="bx-sidebar-cnt relative flex-1 flex flex-col max-w-xs w-full pt-5 pb-4 bg-white dark:bg-gray-900">
         <div class="absolute top-0 ltr:right-0 rtl:left-0 ltr:-mr-12 rtl:-ml-12 pt-2">
@@ -15,6 +15,7 @@
                 <bx_menu:bx_artificer_sidebar_site />
             </nav>
         </div>
+        <div class="bx-focus-trap w-0 h-0 outline-none" tabindex="0"></div>
     </div>
     <div class="flex-shrink-0 w-14" aria-hidden="true"></div>
 </div>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
modules/boonex/artificer/install/sql/enable.sql


+ 2 - 2
modules/boonex/courses/template/unit_personal.html

@@ -1,11 +1,11 @@
 <div class="__class__ p-2 box-border">
     <div class="bx-base-pofile-unit-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box relative h-full overflow-hidden">
         <div class="absolute z-0 w-full h-40 bg-gradient-to-b from-green-400 to-green-500"></div>
-        <a class="bx-base-pofile-unit-cover relative flex items-center justify-start w-full h-40 bg-no-repeat bg-center bg-cover hover:no-underline" style="background-image:url(__cover_url__); __cover_settings__" href="__content_url__" onclick="__content_click__">
+        <a class="bx-base-pofile-unit-cover relative flex items-center justify-start w-full h-40 bg-no-repeat bg-center bg-cover hover:no-underline" style="background-image:url(__cover_url__); __cover_settings__" href="__content_url__" onclick="__content_click__" aria-hidden="true" tabindex="-1">
             <bx_if:show_thumbnail>
                 <div class="bx-def-unit-img bx-def-__size__-size __class_size__ relative ml-5">
                     <bx_if:show_thumb_image>
-                        <img class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ ring-4 ring-white dark:ring-gray-900 rounded-md box-border" src="__thumb_url__" />
+                        <img alt="" class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ ring-4 ring-white dark:ring-gray-900 rounded-md box-border" src="__thumb_url__" />
                     </bx_if:show_thumb_image>
                     <bx_if:show_thumb_letter>
                         <p class="bx-base-pofile-unit-thumb bx-def-__size__ bx-def-__size__-size __class_size__ flex items-center justify-center m-0 text-white font-bold ring-4 ring-white dark:ring-gray-900 rounded-md box-border" style="background-color:rgba(__color__)">__letter__</p>

+ 2 - 2
modules/boonex/decorous/data/template/bx_organizations/cover.html

@@ -3,7 +3,7 @@
         <div class="bx-base-pofile-cover bx-def-cover-color-bg bx-def-box-sizing">
             <div class="bx-base-pofile-cover-image">
                 <p class="bx-base-pofile-cover-image bx-def-box-sizing flex justify-center items-center">
-                    <img class="bx-base-pofile-cover-image bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />"/>
+                    <img alt="" class="bx-base-pofile-cover-image bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />"/>
                 </p>
                 <div class="bx-cover-gradient"></div>
             </div>
@@ -11,7 +11,7 @@
                 <bx_if:show_avatar>
                     <div class="bx-base-pofile-cover-thumb bx-def-ava-big-size __add_class__">
                         <a class="bx-base-pofile-cover-thumb" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
-                            <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size __img_class__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                            <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size __img_class__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
                             <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size bx-def-border __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>">__letter__</p>
                         </a>
                         <bx_if:show_online>

+ 2 - 2
modules/boonex/decorous/data/template/bx_persons/cover.html

@@ -4,7 +4,7 @@
             <div class="bx-base-pofile-cover-image bx-def-page-width bx-def-centered bx-def-box-sizing ">
                 <div class="bx-base-pofile-cover-image-cnt bx-def-box-sizing">
                     <p class="bx-base-pofile-cover-image bx-def-box-sizing flex justify-center items-center">
-                        <img class="bx-base-pofile-cover-image bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />"/>
+                        <img alt="" class="bx-base-pofile-cover-image bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />"/>
                     </p>
                     <div class="bx-cover-gradient"></div>
                 </div>
@@ -13,7 +13,7 @@
                 <bx_if:show_avatar>
                     <div class="bx-base-pofile-cover-thumb bx-def-ava-big-size __add_class__">
                         <a class="bx-base-pofile-cover-thumb" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
-                            <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                            <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__" <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
                             <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size bx-def-border __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>">__letter__</p>
                         </a>
                         <bx_if:show_online>

+ 4 - 0
modules/boonex/forum/classes/BxForumGrid.php

@@ -89,6 +89,10 @@ class BxForumGrid extends BxBaseModGeneralGrid
             $this->_aQueryAppend['filter3'] = $this->_sFilter1Value;
         }
 
+        $this->_aFilterAreaLabels = [
+            $this->_sFilter3Name => '_sys_grid_lbl_order', // "Order": filter3 has no placeholder option to borrow a name from
+        ];
+
         $this->_sDefaultSortingOrder = 'DESC';
         $this->_sDefaultSource = $this->_aOptions['source'];
     }

+ 2 - 0
modules/boonex/massmailer/classes/BxMassMailerTemplate.php

@@ -164,6 +164,7 @@ class BxMassMailerTemplate extends BxBaseModGeneralTemplate
     public function entryBreadcrumb($aContentInfo, $aTmplVarsItems = array())
     {
         $CNF = &$this->getModule()->_oConfig->CNF;
+        $sTitleHome = $this->getModule()->_aModule['title'];
         $aTmplVarsItems = array(array(
             'url' => $aContentInfo['url'],
             'title' => bx_process_output($aContentInfo[$CNF['FIELD_TITLE']])
@@ -172,6 +173,7 @@ class BxMassMailerTemplate extends BxBaseModGeneralTemplate
         return $this->parseHtmlByName('breadcrumb.html', array(
             'url_home' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_MANAGE_CAMPAIGNS'])),
             'icon_home' => $CNF['ICON'],
+            'title_home' => bx_html_attribute(strip_tags(_t($sTitleHome ? $sTitleHome : '_sys_menu_item_title_system_home')), BX_ESCAPE_STR_QUOTE),
             'bx_repeat:items' => $aTmplVarsItems
         ));
     }

+ 1 - 0
modules/boonex/tasks/classes/BxTasksTemplate.php

@@ -648,6 +648,7 @@ class BxTasksTemplate extends BxBaseModTextTemplate
         $aInput = [
             'type' => 'select', 
             'name' => 'filters',
+            'area_label' => '_bx_tasks_filter_title_select',
             'value' => $aParams['filter_selected'] ?? 0,
             'values' => [
                 ['key' => 0, 'value' => _t('_bx_tasks_filter_title_select')]

+ 1 - 0
modules/boonex/timeline/classes/BxTimelineTemplate.php

@@ -1311,6 +1311,7 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
         $aTmplVars = array(
             'style_prefix' => $sStylePrefix,
             'visible' => ($aParams['view'] == BX_TIMELINE_VIEW_TIMELINE && $bVisible) || ($aParams['view'] == BX_TIMELINE_VIEW_OUTLINE && $bEnabled && $bVisible) ? 'block' : 'none',
+            'disabled' => !$bEnabled ? ' disabled="disabled"' : '',
             'bx_if:is_disabled' => array(
                 'condition' => !$bEnabled,
                 'content' => array()

+ 8 - 2
modules/boonex/timeline/template/css/view.css

@@ -449,8 +449,14 @@ div.bx-tl-item-content form {
     padding: 1rem 1rem 0 1rem;
 }
 div.bx-tl-item-content div.bx-tl-title {
-    text-overflow: ellipsis;
-    overflow: hidden;
+    /* This box used to be `overflow: hidden`, which clipped the focus ring of the title link sitting
+       flush inside it. The clipping was really there to stop a long unbroken title from widening the
+       page, and wrapping does that without hiding anything; `text-overflow` never applied here anyway,
+       the box is a flex container. */
+    overflow-wrap: anywhere;
+}
+div.bx-tl-item-content div.bx-tl-title div.bx-tl-title-cnt {
+    min-width: 0;
 }
 div.bx-tl-item-content div.bx-tl-content iframe[src*='video'] {
     width: 100%;

+ 1 - 1
modules/boonex/timeline/template/item_outline.html

@@ -48,7 +48,7 @@
                     </div>
                     <bx_if:show_manage>
                         <div class="__style_prefix__-item-manage">
-                            <a href="javascript:void(0)" onclick="__onclick__">
+                            <a href="javascript:void(0)" onclick="__onclick__" title="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-label="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-haspopup="dialog" aria-expanded="false">
                                 <span class="bx-menu-item-icon bx-def-align-center"><i class="sys-icon ellipsis-v"></i></span>
                             </a>
                         </div>

+ 1 - 1
modules/boonex/timeline/template/item_timeline.html

@@ -47,7 +47,7 @@
                 </div>
                 <bx_if:show_manage>
                     <div class="__style_prefix__-item-manage">
-                        <a href="javascript:void(0)" onclick="__onclick__">
+                        <a href="javascript:void(0)" onclick="__onclick__" title="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-label="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-haspopup="dialog" aria-expanded="false">
                             <span class="bx-menu-item-icon bx-def-align-center"><i class="sys-icon ellipsis-v"></i></span>
                         </a>
                     </div>

+ 1 - 1
modules/boonex/timeline/template/load_more.html

@@ -1,6 +1,6 @@
 <div class="__style_prefix__-load-more bx-def-padding-sec-top bx-clearfix" style="display:__visible__;">
     <div class="__style_prefix__-load-more-cnt flex items-center justify-between">
-        <button class="bx-btn<bx_if:is_disabled> bx-btn-disabled</bx_if:is_disabled>" <bx_if:show_on_click>onclick="__on_click__"</bx_if:show_on_click>>
+        <button class="bx-btn<bx_if:is_disabled> bx-btn-disabled</bx_if:is_disabled>"__disabled__ <bx_if:show_on_click>onclick="__on_click__"</bx_if:show_on_click>>
             <bx_text:_bx_timeline_txt_load_more />
         </button>
         <bx_if:show_jump_to>

+ 1 - 1
modules/boonex/timeline/template/load_more_auto.html

@@ -1,3 +1,3 @@
 <div class="__style_prefix__-load-more __style_prefix__-lm-auto bx-def-padding-sec-topbottom bx-clearfix" style="display:__visible__;">
-    <button class="bx-btn bx-btn-disabled">__loading__</button>
+    <button class="bx-btn bx-btn-disabled" disabled="disabled">__loading__</button>
 </div>

+ 0 - 3
studio/template/scripts/BxBaseStudioMenu.php

@@ -46,9 +46,6 @@ class BxBaseStudioMenu extends BxDolStudioMenu
             $aItem['class_add'] = '';
         $aItem['class_add'] .= ' ' . str_replace('_', '-', $aItem['name']);
 
-        if(!empty($aItem['attrs_add']))
-            $aItem['attrs'] .= ' ' . $aItem['attrs_add'];
-
         // an item may keep its icon as an <img> (icon_inline => false): app tile artwork stays out of the document and its gradient ids never collide
         if($this->_bInlineIcons && ($aItem['icon_inline'] ?? true) && $aItem['bx_if:image']['condition'] && ($sImage = $this->_oTemplate->getIconContent($aItem['icon'])) !== false)
             $aItem = array_merge($aItem, [

+ 1 - 1
template/_page_content_beg.html

@@ -2,4 +2,4 @@ __informer__
 <div class="bx-page-wrapper bx-def-page-width mx-auto px-3 md:px-4 lg:px-6 box-border">
     <div id="bx-content-container" class="bx-content-container">
         <bx_injection:injection_content_before />
-        <main role="main" id="bx-content-main" class="bx-content-main my-4 lg:my-6">
+        <main role="main" id="bx-content-main" class="bx-content-main my-4 lg:my-6" tabindex="-1">

+ 1 - 1
template/_page_submenu.html

@@ -8,7 +8,7 @@
                         <bx_menu:sys_site_submenu />
                     </div>
                 </div>
-                <div class="flex-none">
+                <div class="flex-none z-0">
                     <bx_menu:sys_site_manage />
                 </div>
             </div>

+ 4 - 3
template/_page_toolbar_search.html

@@ -1,12 +1,13 @@
-<div class="bx-ti-search-box flex-auto flex items-start md:min-w-88 ltr:ml-2 rtl:mr-2 bg-white/95 dark:bg-gray-800/95 rounded-md shadow-md hidden">
+<div id="bx-ti-search-box" class="bx-ti-search-box flex-auto flex items-start md:min-w-88 ltr:ml-2 rtl:mr-2 bg-white/95 dark:bg-gray-800/95 rounded-md shadow-md hidden">
     <div class="relative w-full">__sys_site_search__</div>
 </div>
 <div class="bx-ti-search-button group relative inline-flex items-center ltr:ml-2 rtl:mr-2 text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 text-base font-medium leading-6 border border-transparent hover:border-gray-200/50 active:border-gray-300 dark:hover:border-gray-700/50 dark:active:border-gray-700 bg-gray-100 dark:bg-gray-700/50 active:bg-gray-300 dark:active:bg-black/50 hover:bg-gray-200/50 dark:hover:bg-gray-700/50 rounded-full">
-    <a href="javascript:void(0)" onclick="javascript:bx_site_search_show(this)">
+    <button type="button" class="inline-block rounded-full" onclick="javascript:bx_site_search_show(this)" aria-expanded="false" aria-controls="bx-ti-search-box">
         <span class="relative flex items-center justify-center h-10 w-10">
             <div class="bx-icon">
                 <bx_image_auto:search />
             </div>
         </span>
-    </a>
+        <span class="sr-only"><bx_text:_sys_menu_item_title_system_search /></span>
+    </button>
 </div>

+ 1 - 1
template/comments_uploader_bs.html

@@ -4,7 +4,7 @@
 <div class="bx-clear"></div>
 <div class="cmts-uploader px-2">
     <div id="__div_id__" class="filepond bx-uploader-html5-drop-area border-2 border-gray-300 border-dashed rounded-lg hidden"></div>
-    <input type="text" id="__focus_div_id__" class="bx-uploader-html5-paste-catcher" tabindex="1" style="display: none" />
+    <input type="text" id="__focus_div_id__" class="bx-uploader-html5-paste-catcher" tabindex="-1" aria-label="<bx_text_attribute:_sys_uploader_simple_submit_button />" style="display: none" />
     <div id="__errors_container_id__" class="bx-uploader-html5-errors-area bx-def-font-small"></div>
     <div class="bx-clear"></div>
     <div class="relative">

+ 1 - 1
template/connection_counter.html

@@ -2,6 +2,6 @@
     <span class="__class__" <bx_repeat:attrs>__key__="__value__"</bx_repeat:attrs>>__content__</span>
 </bx_if:show_text>
 <bx_if:show_link>
-    <a class="__class__ group flex items-center p-1 border-none rounded-full text-gray-500 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 text-sm font-normal" <bx_repeat:attrs>__key__="__value__"</bx_repeat:attrs>>__content__</a>
+    <a class="__class__ group flex items-center p-1 border-none rounded-full text-gray-600 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 text-sm font-normal" <bx_repeat:attrs>__key__="__value__"</bx_repeat:attrs>>__content__</a>
 </bx_if:show_link>
 __script__

+ 4 - 2
template/cover.html

@@ -16,9 +16,11 @@
                             <img class="bx-def-border bx-def-round-corners" style="background-image:url(__icon_url__)" src="<bx_icon_url:spacer.gif />" />
                         </div>
                     </bx_if:image>
-                    <div class="bx-cover-title bx-def-margin-sec-topbottom bx-def-font-h1" style="z-index:2;">
+                    <bx_if:title>
+                    <h1 class="bx-cover-title bx-def-margin-sec-topbottom bx-def-font-h1" style="z-index:2;">
                         <span class="bx-def-font-contrasted">__title__</span>
-                    </div>
+                    </h1>
+                    </bx_if:title>
                     <div class="bx-cover-actions">__actions__</div>
                 </div>
             </div>

+ 1 - 1
template/cover_empty.html

@@ -1 +1 @@
-<div class="bx-menu-toolbar-padding pt-16"></div>
+<div class="bx-menu-toolbar-padding pt-16"></div><bx_if:title><h1 class="sr-only">__title__</h1></bx_if:title>

+ 2 - 1
template/css/forms.css

@@ -201,7 +201,8 @@
 .bx-form-input-wrapper-password {
     padding: 0;
 }
-.bx-form-input-wrapper-password > a {
+.bx-form-input-wrapper-password > .password-show,
+.bx-form-input-wrapper-password > .password-hide {
     position: absolute;
     z-index: 1000;
     

+ 35 - 0
template/css/fullcalendar.css

@@ -3,3 +3,38 @@
     flex-direction: column;
     grid-row-gap: 5px;
 }
+
+/* WCAG 2.1 AA (1.4.3 Contrast Minimum).
+   FullCalendar dims the adjacent-month days to 30% opacity and tints the current
+   day's cell, which pushes both day numbers under 4.5:1 in the light and the dark
+   scheme alike. The month hierarchy is kept, but with explicit colours instead of
+   transparency. FullCalendar injects its own stylesheet from JS after this file,
+   so the opacity reset has to be flagged important. */
+.fc .fc-daygrid-day-number {
+    color: #374151;
+}
+
+.fc .fc-daygrid-day.fc-day-other .fc-daygrid-day-top {
+    opacity: 1 !important;
+}
+
+.fc .fc-daygrid-day.fc-day-other .fc-daygrid-day-number {
+    color: #6b7280;
+}
+
+.fc .fc-daygrid-day.fc-day-today .fc-daygrid-day-number {
+    color: #111827;
+    font-weight: 600;
+}
+
+.dark .fc .fc-daygrid-day-number {
+    color: #e5e7eb;
+}
+
+.dark .fc .fc-daygrid-day.fc-day-other .fc-daygrid-day-number {
+    color: #9ca3af;
+}
+
+.dark .fc .fc-daygrid-day.fc-day-today .fc-daygrid-day-number {
+    color: #f3f4f6;
+}

+ 45 - 6
template/css/tailwind.css

@@ -36,9 +36,37 @@
         @apply rounded;
     }
 
+    /* The logo link wraps a block level <img>, so as a plain inline element it has no inline box
+       of its own and the browser paints no focus ring on it at all. Giving it a box makes the
+       ring below visible without moving the logo. */
+    #bx-logo-container > a {
+        @apply inline-flex items-center align-middle rounded;
+    }
+
+    /* Public site only - Studio has its own .bx-std focus rings further down, and body.bx-std keeps
+       these off it. Anything focusable that is not a .bx-btn (those draw their own ring) would
+       otherwise fall back to the browser default ring, which Safari does not draw for links at all and
+       which Chrome tints with the OS accent colour - so the site showed blue rings on the menus and,
+       say, orange ones on the app tiles. One rule keeps every focus indicator identical. An outline is
+       used rather than a ring box-shadow because the toolbar's more-auto wrapper and the sidebar
+       scroller both clip overflow. */
+    body:not(.bx-std) a:not(.bx-btn):focus-visible,
+    body:not(.bx-std) button:not(.bx-btn):focus-visible,
+    body:not(.bx-std) summary:focus-visible,
+    body:not(.bx-std) [tabindex="0"]:focus-visible {
+        @apply outline outline-2 outline-offset-2 outline-blue-500 dark:outline-blue-400;
+    }
+
+    /* The main menu row is inside .bx-menu-more-auto-wrapper, which sets overflow:hidden, so an
+       offset outline would be clipped top and bottom - draw it on the border edge there. */
+    body:not(.bx-std) .bx-menu-more-auto-wrapper .bx-stl-mil:focus-visible,
+    body:not(.bx-std) .bx-menu-more-auto-wrapper .bx-stl-mil-sm:focus-visible {
+        @apply outline-offset-0;
+    }
+
     .bx-def-vanilla-html {
         @apply prose dark:prose-invert;
-        @apply prose-a:text-blue-500 prose-a:font-medium prose-a:no-underline hover:prose-a:underline visited:prose-a:text-purple-500;
+        @apply prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-a:font-medium prose-a:no-underline hover:prose-a:underline visited:prose-a:text-purple-700 dark:visited:prose-a:text-purple-400;
     }
     
     .bx-def-vanilla-html.bx-def-vh-sm {
@@ -62,7 +90,7 @@
     }
 
     .bx-artificer .bx-menthion-link {
-        @apply font-normal text-blue-600 hover:text-blue-700 dark:text-blue-500 dark:hover:text-blue-600;
+        @apply font-normal text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300;
     }
 
     .bx-artificer .bx-def-box-sizing {
@@ -487,7 +515,7 @@
     }
 
     .bx-def-font-grayed {
-        @apply text-gray-700 dark:text-gray-500 text-opacity-60;
+        @apply text-gray-600 dark:text-gray-400;
     }
 
     .bx-def-font-author,
@@ -506,7 +534,7 @@
     }
 
     .bx-artificer .bx-def-a-colored {
-        @apply text-blue-600 hover:text-blue-700 dark:text-blue-500 dark:hover:text-blue-600;
+        @apply text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300;
     }
 
     .bx-std a.bx-def-font-meta,
@@ -792,6 +820,17 @@
         @apply bg-gray-50 dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-400 hover:text-gray-400 dark:hover:text-gray-400 focus:ring-0 focus:ring-offset-0 shadow-none cursor-default !important;
     }
 
+    /* Help tour (Shepherd): the vendored plugins_public/shepherd/css/shepherd.css paints the primary button #3288e6 with 75% white text (#cce1f9, 2.71:1) and is
+       regenerated by `yarn build:shepherd`, so the fix lives here. The selector names .shepherd-button-primary because Tailwind keeps a component rule only when its
+       selector contains a class it saw while scanning content (that class is in template/homepage_tour.html and modules/boonex/help_tours/template/tour.html).
+       Specificity (0,3,0) beats the vendor .shepherd-button (0,1,0) even though shepherd.css is loaded in a later bundle. */
+    .shepherd-element .shepherd-button.shepherd-button-primary {
+        @apply bg-blue-600 text-white;
+    }
+    .shepherd-element .shepherd-button.shepherd-button-primary:not(:disabled):hover {
+        @apply bg-blue-700 text-white;
+    }
+
     /* Button sizes (height / corner radius): mini 28px/6px with the hit area extended to 44px, small 36px/8px, default 44px/10px, large 52px/12px, xlarge 60px/14px. */
     .bx-btn.bx-btn-mini {
         @apply min-h-7 px-2.5 py-1 text-xs rounded-md;
@@ -825,7 +864,7 @@
     .bx-artificer form a:not(.bx-btn),
     .bx-artificer .sys-jf-agreement a:not(.bx-btn), 
     .bx-artificer .sys-lf-agreement a:not(.bx-btn) {
-        @apply font-normal text-blue-600 hover:text-blue-700 dark:text-blue-500 dark:hover:text-blue-600;
+        @apply font-normal text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300;
     }
 
     .bx-artificer .bx-form-caption,
@@ -1373,7 +1412,7 @@
     .sys-ac-link .sys-action-counter {
         @apply flex items-center;
         @apply border-none;
-        @apply text-gray-500 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300;
+        @apply text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300;
         @apply rounded-full;
     }
     .sys-action-counter.sys-ac-only.sys-ac-link,

+ 1 - 1
template/designbox_1.html

@@ -9,7 +9,7 @@
                 <div class="bx-dbt-ic grow-0">__icon_html__</div>
             </bx_if:show_db_icon_html>
             <div class="bx-dbt-cnt">
-                <div class="bx-dbt-ttl">__title__</div>
+                <h2 class="bx-dbt-ttl">__title__</h2>
                 <bx_if:show_db_description>
                     <div class="bx-dbt-dsc text-sm font-normal">__description__</div>
                 </bx_if:show_db_description>

+ 1 - 1
template/designbox_11.html

@@ -9,7 +9,7 @@
                 <div class="bx-dbt-ic grow-0">__icon_html__</div>
             </bx_if:show_db_icon_html>
             <div class="bx-dbt-cnt">
-                <div class="bx-dbt-ttl">__title__</div>
+                <h2 class="bx-dbt-ttl">__title__</h2>
                 <bx_if:show_db_description>
                     <div class="bx-dbt-dsc text-sm font-normal">__description__</div>
                 </bx_if:show_db_description>

+ 1 - 1
template/designbox_14.html

@@ -9,7 +9,7 @@
                 <div class="bx-dbt-ic grow-0">__icon_html__</div>
             </bx_if:show_db_icon_html>
             <div class="bx-dbt-cnt">
-                <div class="bx-dbt-ttl">__title__</div>
+                <h2 class="bx-dbt-ttl">__title__</h2>
                 <bx_if:show_db_description>
                     <div class="bx-dbt-dsc text-sm font-normal">__description__</div>
                 </bx_if:show_db_description>

+ 1 - 1
template/designbox_4.html

@@ -9,7 +9,7 @@
                 <div class="bx-dbt-ic grow-0">__icon_html__</div>
             </bx_if:show_db_icon_html>
             <div class="bx-dbt-cnt">
-                <div class="bx-dbt-ttl">__title__</div>
+                <h2 class="bx-dbt-ttl">__title__</h2>
                 <bx_if:show_db_description>
                     <div class="bx-dbt-dsc text-sm font-normal">__description__</div>
                 </bx_if:show_db_description>

+ 1 - 1
template/form_field_password.html

@@ -1,2 +1,2 @@
 __input__
-<a class="password-show" href="javascript:void(0)" title="<bx_text_attribute:_sys_form_input_password_show />"><i class="sys-icon eye"></i></a>
+<button type="button" class="password-show text-blue-600 dark:text-blue-500" title="<bx_text_attribute:_sys_form_input_password_show />" aria-label="<bx_text_attribute:_sys_form_input_password_show />"><i class="sys-icon eye"></i></button>

+ 4 - 4
template/layout_2_columns.html

@@ -1,16 +1,16 @@
 <!-- layout 2 columns [ start ] -->
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-2-columns">
     <div class="bx-layout-row">
-        <aside class="bx-layout-col bx-layout-2-columns-column1 bx-layout-column-half md:w-1/2" aria-label="Sidebar">
+        <div class="bx-layout-col bx-layout-2-columns-column1 bx-layout-column-half md:w-1/2">
             <div class="bx-layout-cell" id="bx-layout-cell-1">
                 __cell_1__
             </div>
-        </aside>
-        <main class="bx-layout-col bx-layout-2-columns-column2 bx-layout-column-half md:w-1/2" aria-label="Main">
+        </div>
+        <div class="bx-layout-col bx-layout-2-columns-column2 bx-layout-column-half md:w-1/2">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </main>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 8 - 8
template/layout_3_columns.html

@@ -1,23 +1,23 @@
 <!-- layout 3 columns [ start ] -->
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-3-columns">
     <div class="bx-layout-row">
-        <section class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/3 flex-auto md:flex-none" aria-label="Sidebar" >
+        <div class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/3 flex-auto md:flex-none" >
             <div class="bx-layout-cell" id="bx-layout-cell-1">
                 __cell_1__
             </div>
-        </section>
-        <section aria-label="Content" class="max-w-full md:w-2/3 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
-            <main class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:flex-none lg:w-1/2" aria-label="Main">
+        </div>
+        <div class="max-w-full md:w-2/3 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
+            <div class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:flex-none lg:w-1/2">
                 <div class="bx-layout-cell" id="bx-layout-cell-2">
                     __cell_2__
                 </div>
-            </main>
-            <aside class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin lg:w-1/2 flex-auto" aria-label="Aside">
+            </div>
+            <div class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin lg:w-1/2 flex-auto">
                 <div class="bx-layout-cell" id="bx-layout-cell-3">
                     __cell_3__
                 </div>
-            </aside>
-        </section>
+            </div>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 8 - 8
template/layout_bar_content_bar.html

@@ -1,23 +1,23 @@
 <!-- layout bar content bar (bcb) [ start ] -->
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-bcb">
     <div class="bx-layout-row">
-        <section class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/4 flex-auto md:flex-none" aria-label="Sidebar" >
+        <div class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/4 flex-auto md:flex-none" >
             <div class="bx-layout-cell" id="bx-layout-cell-1">
                 __cell_1__
             </div>
-        </section>
-        <section aria-label="Content" class="max-w-full md:w-3/4 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
-            <main class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:w-2/3" aria-label="Main">
+        </div>
+        <div class="max-w-full md:w-3/4 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
+            <div class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:w-2/3">
                 <div class="bx-layout-cell" id="bx-layout-cell-2">
                     __cell_2__
                 </div>
-            </main>
-            <aside class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin lg:w-1/3" aria-label="Aside">
+            </div>
+            <div class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin lg:w-1/3">
                 <div class="bx-layout-cell" id="bx-layout-cell-3">
                     __cell_3__
                 </div>
-            </aside>
-        </section>
+            </div>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 4 - 4
template/layout_bar_left.html

@@ -1,16 +1,16 @@
 <!-- layout bar left [ start ] -->
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-bar-left">
     <div class="bx-layout-row">
-        <aside class="bx-layout-col bx-layout-bar-left-bar bx-layout-column-thin md:w-1/3" aria-label="Sidebar">
+        <div class="bx-layout-col bx-layout-bar-left-bar bx-layout-column-thin md:w-1/3">
             <div class="bx-layout-cell" id="bx-layout-cell-1">
                 __cell_1__
             </div>
-        </aside>
-        <main class="bx-layout-col bx-layout-bar-left-content bx-layout-column-wide md:w-2/3" aria-label="Main">
+        </div>
+        <div class="bx-layout-col bx-layout-bar-left-content bx-layout-column-wide md:w-2/3">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </main>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 4 - 4
template/layout_bar_right.html

@@ -1,16 +1,16 @@
 <!-- layout bar right [ start ] -->
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-bar-right">
     <div class="bx-layout-row">
-        <main class="bx-layout-col bx-layout-bar-right-content bx-layout-column-wide md:w-2/3" aria-label="Main">
+        <div class="bx-layout-col bx-layout-bar-right-content bx-layout-column-wide md:w-2/3">
             <div class="bx-layout-cell" id="bx-layout-cell-1">
                 __cell_1__
             </div>
-        </main>
-        <aside class="bx-layout-col bx-layout-bar-right-bar bx-layout-column-thin md:w-1/3" aria-label="Aside">
+        </div>
+        <div class="bx-layout-col bx-layout-bar-right-bar bx-layout-column-thin md:w-1/3">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </aside>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 4 - 4
template/layout_bottom_area_2_columns.html

@@ -1,16 +1,16 @@
 <!-- layout top area 2 columns [ start ] -->
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-bottom-area-2-columns">
     <div class="bx-layout-row">
-        <aside class="bx-layout-col bx-layout-2-columns-column1 bx-layout-column-half md:w-1/2" aria-label="Sidebar">
+        <div class="bx-layout-col bx-layout-2-columns-column1 bx-layout-column-half md:w-1/2">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </aside>
-        <main class="bx-layout-col bx-layout-2-columns-column2 bx-layout-column-half md:w-1/2" aria-label="Main">
+        </div>
+        <div class="bx-layout-col bx-layout-2-columns-column2 bx-layout-column-half md:w-1/2">
             <div class="bx-layout-cell" id="bx-layout-cell-3">
                 __cell_3__
             </div>
-        </main>
+        </div>
     </div>
     <bx_include_auto:_row_1_column.html />
     <bx_include_auto:_row_1_column_dump.html />

+ 4 - 4
template/layout_top_area_2_columns.html

@@ -2,16 +2,16 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-top-area-2-columns">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row">
-        <aside class="bx-layout-col bx-layout-2-columns-column1 bx-layout-column-half md:w-1/2" aria-label="Sidebar">
+        <div class="bx-layout-col bx-layout-2-columns-column1 bx-layout-column-half md:w-1/2">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </aside>
-        <main class="bx-layout-col bx-layout-2-columns-column2 bx-layout-column-half md:w-1/2" aria-label="Main">
+        </div>
+        <div class="bx-layout-col bx-layout-2-columns-column2 bx-layout-column-half md:w-1/2">
             <div class="bx-layout-cell" id="bx-layout-cell-3">
                 __cell_3__
             </div>
-        </main>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 8 - 8
template/layout_top_area_3_columns.html

@@ -2,23 +2,23 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-top-area-3-columns">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row" >
-        <section class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/3 flex-auto md:flex-none" aria-label="Sidebar">
+        <div class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/3 flex-auto md:flex-none">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </section>
-        <section aria-label="Content" class="max-w-full md:w-2/3 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap" >
-            <main class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:flex-none lg:w-1/2" aria-label="Main">
+        </div>
+        <div class="max-w-full md:w-2/3 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap" >
+            <div class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:flex-none lg:w-1/2">
                 <div class="bx-layout-cell" id="bx-layout-cell-3">
                     __cell_3__
                 </div>
-            </main>
-            <aside class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin flex-auto lg:w-1/2 " aria-label="Aside">
+            </div>
+            <div class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin flex-auto lg:w-1/2 ">
                 <div class="bx-layout-cell" id="bx-layout-cell-4">
                     __cell_4__
                 </div>
-            </aside>
-        </section>
+            </div>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 8 - 8
template/layout_top_area_bar_content_bar.html

@@ -2,23 +2,23 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-top-area-bcb">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row">
-        <section class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/4 flex-auto md:flex-none" aria-label="Sidebar" >
+        <div class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/4 flex-auto md:flex-none" >
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </section>
-        <section aria-label="Content" class="max-w-full md:w-3/4 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
-            <main class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:flex-none lg:w-2/3" aria-label="Main">
+        </div>
+        <div class="max-w-full md:w-3/4 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
+            <div class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:flex-none lg:w-2/3">
                 <div class="bx-layout-cell" id="bx-layout-cell-3">
                     __cell_3__
                 </div>
-            </main>
-            <aside class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin flex-auto lg:w-1/3" aria-label="Aside">
+            </div>
+            <div class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin flex-auto lg:w-1/3">
                 <div class="bx-layout-cell" id="bx-layout-cell-4">
                     __cell_4__
                 </div>
-            </aside>
-        </section>
+            </div>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 4 - 4
template/layout_top_area_bar_left.html

@@ -2,16 +2,16 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-top-area-bar-left">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row">
-        <main class="bx-layout-col bx-layout-bar-left-bar bx-layout-column-thin md:w-1/3" aria-label="Main">
+        <div class="bx-layout-col bx-layout-bar-left-bar bx-layout-column-thin md:w-1/3">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </main>
-        <aside class="bx-layout-col bx-layout-bar-left-content bx-layout-column-wide md:w-2/3" aria-label="Aside">
+        </div>
+        <div class="bx-layout-col bx-layout-bar-left-content bx-layout-column-wide md:w-2/3">
             <div class="bx-layout-cell" id="bx-layout-cell-3">
                 __cell_3__
             </div>
-        </aside>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 4 - 4
template/layout_top_area_bar_right.html

@@ -2,16 +2,16 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-top-area-bar-right">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row">
-        <main class="bx-layout-col bx-layout-bar-right-content bx-layout-column-wide md:w-2/3" aria-label="Main">
+        <div class="bx-layout-col bx-layout-bar-right-content bx-layout-column-wide md:w-2/3">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </main>
-        <aside class="bx-layout-col bx-layout-bar-right-bar bx-layout-column-thin md:w-1/3" aria-label="Aside">
+        </div>
+        <div class="bx-layout-col bx-layout-bar-right-bar bx-layout-column-thin md:w-1/3">
             <div class="bx-layout-cell" id="bx-layout-cell-3">
                 __cell_3__
             </div>
-        </aside>
+        </div>
     </div>
     <bx_include_auto:_row_1_column_dump.html />
 </div>

+ 4 - 4
template/layout_topbottom_area_2_columns.html

@@ -2,16 +2,16 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-topbottom-area-2-columns">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row">
-        <aside class="bx-layout-col bx-layout-2-columns-column1 bx-layout-column-half md:w-1/2" aria-label="Sidebar">
+        <div class="bx-layout-col bx-layout-2-columns-column1 bx-layout-column-half md:w-1/2">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </aside>
-        <main class="bx-layout-col bx-layout-2-columns-column2 bx-layout-column-half md:w-1/2" aria-label="Main">
+        </div>
+        <div class="bx-layout-col bx-layout-2-columns-column2 bx-layout-column-half md:w-1/2">
             <div class="bx-layout-cell" id="bx-layout-cell-3">
                 __cell_3__
             </div>
-        </main>
+        </div>
     </div>
     <div class="bx-layout-row">
         <div class="bx-layout-col bx-layout-1-column-column1 bx-layout-column-fullwidth">

+ 4 - 4
template/layout_topbottom_area_bar_left.html

@@ -2,16 +2,16 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-topbottom-area-bar-left">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row">
-        <aside class="bx-layout-col bx-layout-bar-left-bar bx-layout-column-thin md:w-1/3" aria-label="Sidebar">
+        <div class="bx-layout-col bx-layout-bar-left-bar bx-layout-column-thin md:w-1/3">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </aside>
-        <main class="bx-layout-col bx-layout-bar-left-content bx-layout-column-wide md:w-2/3" aria-label="Main">
+        </div>
+        <div class="bx-layout-col bx-layout-bar-left-content bx-layout-column-wide md:w-2/3">
             <div class="bx-layout-cell" id="bx-layout-cell-3">
                 __cell_3__
             </div>
-        </main>
+        </div>
     </div>
     <div class="bx-layout-row">
         <div class="bx-layout-col bx-layout-1-column-column1 bx-layout-column-fullwidth">

+ 4 - 4
template/layout_topbottom_area_bar_right.html

@@ -2,16 +2,16 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-topbottom-area-bar-right">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row">
-        <main class="bx-layout-col bx-layout-bar-right-content bx-layout-column-wide md:w-2/3" aria-label="Main">
+        <div class="bx-layout-col bx-layout-bar-right-content bx-layout-column-wide md:w-2/3">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </main>
-        <aside class="bx-layout-col bx-layout-bar-right-bar bx-layout-column-thin md:w-1/3" aria-label="Aside">
+        </div>
+        <div class="bx-layout-col bx-layout-bar-right-bar bx-layout-column-thin md:w-1/3">
             <div class="bx-layout-cell" id="bx-layout-cell-3">
                 __cell_3__
             </div>
-        </aside>
+        </div>
     </div>
     <div class="bx-layout-row">
         <div class="bx-layout-col bx-layout-1-column-column1 bx-layout-column-fullwidth">

+ 8 - 8
template/layout_topbottom_area_col1_col3_col2.html

@@ -3,23 +3,23 @@
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row flex flex-col md:flex-row">
         <div class="bx-layout-row">
-            <section class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/6 flex-auto md:flex-none" aria-label="Sidebar" >
+            <div class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-1/6 flex-auto md:flex-none" >
                 <div class="bx-layout-cell" id="bx-layout-cell-2">
                     __cell_2__
                 </div>
-            </section>
-            <section aria-label="Content" class="max-w-full md:w-5/6 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
-                <main class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto md:flex-none lg:w-3/5" aria-label="Main">
+            </div>
+            <div class="max-w-full md:w-5/6 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
+                <div class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto md:flex-none lg:w-3/5">
                     <div class="bx-layout-cell" id="bx-layout-cell-3">
                         __cell_3__
                     </div>
-                </main>
-                <aside class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin lg:w-2/5" aria-label="Aside">
+                </div>
+                <div class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin lg:w-2/5">
                     <div class="bx-layout-cell" id="bx-layout-cell-4">
                         __cell_4__
                     </div>
-                </aside>
-            </section>
+                </div>
+            </div>
         </div>
     </div>
     <div class="bx-layout-row">

+ 4 - 4
template/layout_topbottom_area_col1_col5.html

@@ -2,16 +2,16 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-topbottom-area-col1-col5">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row">
-        <aside class="bx-layout-col bx-layout-col1-col5-column1 bx-layout-column-thin md:w-1/6" aria-label="Sidebar">
+        <div class="bx-layout-col bx-layout-col1-col5-column1 bx-layout-column-thin md:w-1/6">
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </aside>
-        <main class="bx-layout-col bx-layout-col1-col5-column2 bx-layout-column-wide md:w-5/6" aria-label="Main">
+        </div>
+        <div class="bx-layout-col bx-layout-col1-col5-column2 bx-layout-column-wide md:w-5/6">
             <div class="bx-layout-cell" id="bx-layout-cell-3">
                 __cell_3__
             </div>
-        </main>
+        </div>
     </div>
     <div class="bx-layout-row">
         <div class="bx-layout-col bx-layout-1-column-column1 bx-layout-column-fullwidth">

+ 8 - 8
template/layout_topbottom_area_col2_col5_col3.html

@@ -2,23 +2,23 @@
 <div id="__page_id__" class="bx-layout-wrapper bx-layout-topbottom-area-col2-col5-col3">
     <bx_include_auto:_row_1_column.html />
     <div class="bx-layout-row">
-        <section class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-2/10 flex-auto md:flex-none" aria-label="Sidebar" >
+        <div class="bx-layout-col bx-layout-bcb-bar1 bx-layout-column-thin md:w-2/10 flex-auto md:flex-none" >
             <div class="bx-layout-cell" id="bx-layout-cell-2">
                 __cell_2__
             </div>
-        </section>
-        <section aria-label="Content" class="max-w-full md:w-8/10 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
-            <main class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:flex-none lg:w-3/5" aria-label="Main">
+        </div>
+        <div class="max-w-full md:w-8/10 flex-1 flex flex-wrap lg:flex-nowrap bx-layout-gap">
+            <div class="bx-layout-col bx-layout-bcb-content bx-layout-column-half flex-auto lg:flex-none lg:w-3/5">
                 <div class="bx-layout-cell" id="bx-layout-cell-3">
                     __cell_3__
                 </div>
-            </main>
-            <aside class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin lg:w-2/5" aria-label="Aside">
+            </div>
+            <div class="bx-layout-col bx-layout-bcb-bar2 bx-layout-column-thin lg:w-2/5">
                 <div class="bx-layout-cell" id="bx-layout-cell-4">
                     __cell_4__
                 </div>
-            </aside>
-        </section>
+            </div>
+        </div>
     </div>
     <div class="bx-layout-row">
         <div class="bx-layout-col bx-layout-1-column-column1 bx-layout-column-fullwidth">

+ 1 - 1
template/pt_application.html

@@ -61,7 +61,7 @@
                 __informer__
                 <div class="bx-page-wrapper bx-def-padding-sec-leftright bx-def-box-sizing">
                     <div id="bx-content-container" class="bx-content-container bx-def-padding-sec-leftright">
-                        <main role="main" id="bx-content-main" class="bx-content-main bx-def-margin-top">
+                        <main role="main" id="bx-content-main" class="bx-content-main bx-def-margin-top" tabindex="-1">
                             <bx_injection:injection_content_before />
                             __page_main_code__
                             <bx_injection:injection_content_after />

+ 15 - 1
template/scripts/BxBaseCover.php

@@ -68,6 +68,13 @@ class BxBaseCover extends BxDolCover
             $aParams = array_merge($this->_aOptiondDefault, $mixedOptions);
         }
 
+        //--- The cover title is the page's <h1>. Content view pages deliberately leave it empty and
+        //--- headline the content instead, so the heading element is only emitted when there is a title.
+        $aParams['bx_if:title'] = array (
+            'condition' => !empty($aParams['title']),
+            'content' => array('title' => isset($aParams['title']) ? $aParams['title'] : ''),
+        );
+
         /**
          * @hooks
          * @hookdef hook-system-display_cover 'system', 'display_cover' - hook to override page cover code to be output
@@ -102,7 +109,14 @@ class BxBaseCover extends BxDolCover
      */
     public function displayEmpty ()
     {
-    	return $this->_oTemplate->parseHtmlByName($this->_sTemplateNameEmpty, array());
+        $sTitle = $this->_oTemplate->getPageHeader();
+
+        return $this->_oTemplate->parseHtmlByName($this->_sTemplateNameEmpty, array(
+            'bx_if:title' => array(
+                'condition' => !empty($sTitle),
+                'content' => array('title' => bx_process_output(strip_tags($sTitle))),
+            ),
+        ));
     }
 
     /**

+ 12 - 0
template/scripts/BxBaseFunctions.php

@@ -553,6 +553,18 @@ class BxBaseFunctions extends BxDolFactory implements iBxDolSingleton
                 if(!empty($aButton['class']))
                     $aAttrs['class'] .= ' ' . trim($aButton['class']);
 
+                // an icon-only button renders no text, so it needs an accessible name of its own
+                if(empty($aButton['title'])) {
+                    $sButtonLabel = _t(!empty($aButton['area_label']) ? $aButton['area_label'] : '_sys_menu_item_title_system_more');
+                    $aAttrs['aria-label'] = $sButtonLabel;
+                }
+
+                // the popup opened by bx_menu_popup* is role="dialog", bx_menu_popup_inline keeps aria-expanded in sync
+                if(!empty($aAttrs['onclick']) && strpos($aAttrs['onclick'], 'bx_menu_popup') !== false) {
+                    $aAttrs['aria-haspopup'] = 'dialog';
+                    $aAttrs['aria-expanded'] = 'false';
+                }
+
                 $bTmplVarsButtonIcon = !empty($aButton['icon']);
                 $aTmplVarsButtonIcon = !$bTmplVarsButtonIcon ? array() : array(
                     'icon' => $aButton['icon']

+ 19 - 0
template/scripts/BxBaseGrid.php

@@ -23,6 +23,7 @@ class BxBaseGrid extends BxDolGrid
     protected $_aConfirmMessages = false;
     protected $_bSelectAll = false;
     protected $_isDisplayPopupOnTextOverflow = true;
+    protected $_aFilterAreaLabels = []; // filter name => accessible name (lang key or plain text); filter controls are rendered without a visible caption
 
     public function __construct ($aOptions, $oTemplate)
     {
@@ -1124,6 +1125,22 @@ class BxBaseGrid extends BxDolGrid
         return '';
     }
 
+    /**
+     * Grid filter controls are rendered without a visible caption, so each one needs its own accessible name:
+     * the name the grid declares in $_aFilterAreaLabels, else the "unfiltered" option the filter starts with
+     * ("All", "Any status", "Select one..."), else the generic "Filters".
+     */
+    protected function _getFilterAreaLabel($sFilterName, $aInputValues = [])
+    {
+        if(!empty($this->_aFilterAreaLabels[$sFilterName]))
+            return $this->_aFilterAreaLabels[$sFilterName];
+
+        if(!empty($aInputValues['']) && is_string($aInputValues['']))
+            return $aInputValues[''];
+
+        return '_Filters';
+    }
+
     protected function _getFilterSelectOne($sFilterName, $sFilterValue, $aFilterValues, $mixedAddSelectOne = true, $bAsArray = false)
     {
         if(empty($sFilterName))
@@ -1146,6 +1163,7 @@ class BxBaseGrid extends BxDolGrid
                 'id' => 'bx-grid-' . $sFilterName . '-' . $this->_sObject,
                 'onChange' => ($sOnChange = $this->_getFilterOnChange()) ? 'javascript:' . $sOnChange : '',
             ],
+            'area_label' => $this->_getFilterAreaLabel($sFilterName, $aInputValues),
             'value' => $sFilterValue,
             'values' => $aInputValues
         ];
@@ -1169,6 +1187,7 @@ class BxBaseGrid extends BxDolGrid
                 'id' => 'bx-grid-' . $sFilterName . '-' . $this->_sObject,
                 'onChange' => ($sOnChange = $this->_getFilterOnChange()) ? 'javascript:' . $sOnChange : '',
             ],
+            'area_label' => $this->_getFilterAreaLabel($sFilterName),
             'value' => $sFilterValue,
         ];
 

+ 53 - 11
template/scripts/BxBaseMenu.php

@@ -357,6 +357,12 @@ class BxBaseMenu extends BxDolMenu
 
         $a['link'] = isset($a['link']) ? $this->_oPermalinks->permalink($a['link']) : 'javascript:void(0);';
 
+        $aTmplVarsAddon = $this->_bDisplayAddons ? $this->_getTmplVarsAddon($mixedAddon, $a) : array('addon' => '', 'addonf' => '');
+        $a['bx_if:addon'] = array (
+            'condition' => $this->_bDisplayAddons && !empty($aTmplVarsAddon['addon']),
+            'content' => $aTmplVarsAddon
+        );
+
         $a['attrs'] = $this->_getMenuAttrs($a);
         $a['attrs_wrp'] = '';
 
@@ -420,12 +426,6 @@ class BxBaseMenu extends BxDolMenu
             'content' => $aOnClick
         ];
 
-        $aTmplVarsAddon = $this->_bDisplayAddons ? $this->_getTmplVarsAddon($mixedAddon, $a) : array('addon' => '', 'addonf' => '');
-        $a['bx_if:addon'] = array (
-            'condition' => $this->_bDisplayAddons && !empty($aTmplVarsAddon['addon']),
-            'content' => $aTmplVarsAddon
-        );
-
         $aTmplVarsSubitems = array('subitems' => '');
         $bTmplVarsSubitems = $this->isMultilevel() && !empty($a['subitems']);
         if($bTmplVarsSubitems) {
@@ -536,15 +536,26 @@ class BxBaseMenu extends BxDolMenu
     {
         $sAttrs = '';
 
-        if($sType == 'image' && ($sTitleAttr = $this->_getMenuTitle($a)))
-            $sAttrs .= ' alt="' . $sTitleAttr . '"';
+        if($sType == 'image')
+            $sAttrs .= ' alt="' . $this->_getMenuTitle($a) . '"';
 
         return $sAttrs;
     }
 
     protected function _getMenuTitle($a)
     {
-        return bx_html_attribute(strip_tags(($sTitleAttr = $a['title_attr'] ?? '') && ($sTitleAttr = _t($sTitleAttr)) ? $sTitleAttr : $a['title']));
+        $sTitle = ($sTitleAttr = $a['title_attr'] ?? '') && ($sTitleAttr = _t($sTitleAttr)) ? $sTitleAttr : ($a['title'] ?? '');
+
+        /**
+         * An icon only menu item (the toolbar hamburger, [+ Add], [Notifications], the 'more' triggers, ...) has an
+         * empty `title` in `sys_menu_items`, so it used to get no accessible name at all. Every menu item does have
+         * `title_system` - the label the Studio menu builder shows - so it is used as the fallback name. No new
+         * language keys are needed and every icon only menu item benefits, not just the toolbar.
+         */
+        if(trim(strip_tags($sTitle)) === '' && ($sTitleSystem = $a['title_system'] ?? ''))
+            $sTitle = _t($sTitleSystem);
+
+        return bx_html_attribute(strip_tags($sTitle));
     }
 
     protected function _getMenuAreaLabel($a)
@@ -552,6 +563,20 @@ class BxBaseMenu extends BxDolMenu
         return ($sAreaLabel = $a['area_label'] ?? '') && ($sAreaLabel = strip_tags(_t($sAreaLabel))) ? bx_html_attribute($sAreaLabel) : '';
     }
 
+    /**
+     * True when the visible content of the menu item link already carries its accessible name AND that content is
+     * richer than the title alone (an addon counter is rendered next to it). In that case an aria-label repeating
+     * only the title would hide the counter from the accessible name and break WCAG 2.5.3 Label in Name, so it is
+     * omitted and the link is named by its own text. Icon only items - and items whose template never prints the
+     * title - keep their aria-label.
+     */
+    protected function _isMenuLabelInContent($a)
+    {
+        $bTitle = !empty($a['title']) && (!isset($a['icon_only']) || (int)$a['icon_only'] == 0);
+
+        return $bTitle && !empty($a['bx_if:addon']['condition']);
+    }
+
     protected function _getMenuCallbackDataAPI($a)
     {
         return [];
@@ -565,7 +590,7 @@ class BxBaseMenu extends BxDolMenu
             'condition' => (bool)$sIconUrl,
             'content' => [
                 'icon_url' => $sIconUrl,
-                'attrs' => ''
+                'attrs' => 'alt=""'
             ],
         ];
         $a['bx_if:icon'] = array (
@@ -630,7 +655,24 @@ class BxBaseMenu extends BxDolMenu
         if($this->_bAddNoFollow && !empty($aMenuItem['link']) && preg_match('@^https?://@', $aMenuItem['link']) && strncmp($aMenuItem['link'], BX_DOL_URL_ROOT, strlen(BX_DOL_URL_ROOT)) !== 0)
             $sAttrs .= ' rel="noreferrer"';
 
-        if(($sAreaLabel = $this->_getMenuAreaLabel($aMenuItem) ?: $sTitleAttr))
+        /**
+         * `attrs_add` lets a menu item declare extra attributes of its own - the same convention as `class_add` -
+         * so that a PHP built item (a disclosure trigger, for example) can add aria-haspopup/aria-expanded without
+         * a mechanism of its own.
+         */
+        if(!empty($aMenuItem['attrs_add']))
+            $sAttrs .= ' ' . $aMenuItem['attrs_add'];
+
+        /**
+         * An explicit `area_label` always wins. Otherwise the item title is used as the accessible name, but only
+         * when the visible content of the link does not already provide one - an aria-label that repeats the title
+         * while the link also renders an addon (a counter) hides that counter from the accessible name and breaks
+         * WCAG 2.5.3 Label in Name.
+         */
+        if(!($sAreaLabel = $this->_getMenuAreaLabel($aMenuItem)) && !$this->_isMenuLabelInContent($aMenuItem))
+            $sAreaLabel = $sTitleAttr;
+
+        if($sAreaLabel)
             $sAttrs .= ' aria-label="' . $sAreaLabel . '"';
 
         return $sAttrs;

+ 1 - 1
template/scripts/BxBaseMenuManage.php

@@ -80,7 +80,7 @@ class BxBaseMenuManage extends BxTemplMenu
             return $this->_oObjectManage->getCode();
 
         $oMenu = new BxTemplMenu(['template' => 'menu_horizontal.html', 'menu_id' => $this->_sObjectManage . '_wrapper', 'menu_items' => [
-            ['id' => $this->_sObjectManage . '_more', 'name' => $this->_sObjectManage . '_more', 'link' => 'javascript:void(0)', 'onclick' => 'bx_menu_popup(\'' . $this->_sObjectManage . '\', this, {pointer: {el: $(this).parents(\'li:first\'), align:\'right\'}, cssClass: \'bx-popup-menu\'}, {id: ' . $this->_iContentId . '});', 'title' => '', 'icon' => $this->_oTemplate->getImageAuto('cog', false)]
+            ['id' => $this->_sObjectManage . '_more', 'name' => $this->_sObjectManage . '_more', 'link' => 'javascript:void(0)', 'onclick' => 'bx_menu_popup(\'' . $this->_sObjectManage . '\', this, {pointer: {el: $(this).parents(\'li:first\'), align:\'right\'}, cssClass: \'bx-popup-menu\'}, {id: ' . $this->_iContentId . '});', 'title' => '', 'title_attr' => '_sys_menu_item_title_system_more', 'attrs_add' => 'aria-haspopup="dialog" aria-expanded="false"', 'icon' => $this->_oTemplate->getImageAuto('cog', false)]
         ]]);
 
         return $oMenu->getCode();

+ 15 - 0
template/scripts/BxBaseMenuMoreAuto.php

@@ -133,6 +133,21 @@ class BxBaseMenuMoreAuto extends BxTemplMenu
         return parent::_getMenuItem($aItem);
     }
 
+    /**
+     * The 'more' trigger opens a popup that is rendered next to it (the __popup__ marker), so it is a disclosure
+     * for a dialog, not a plain link. Its accessible name comes from the generic title/title_system handling in
+     * BxBaseMenu::_getMenuTitle().
+     */
+    protected function _getMenuAttrs ($aMenuItem)
+    {
+        $sAttrs = parent::_getMenuAttrs($aMenuItem);
+
+        if(!empty($aMenuItem['name']) && $aMenuItem['name'] == BX_DEF_MENU_ITEM_MORE_AUTO)
+            $sAttrs .= ' aria-haspopup="dialog" aria-expanded="false" aria-controls="' . bx_html_attribute($this->_aHtmlIds['more_auto_popup']) . '"';
+
+        return $sAttrs;
+    }
+
     protected function _getHtmlIds()
     {
         return $this->_aHtmlIds;

+ 1 - 0
template/scripts/BxBaseSearch.php

@@ -140,6 +140,7 @@ class BxBaseSearch extends BxDolSearch
             unset($aForm['inputs']['section']);
             unset($aForm['inputs']['search']);
             unset($aForm['inputs']['keyword']['caption']);
+            $aForm['inputs']['keyword']['area_label'] = '_Search'; // the caption is dropped for the live variant, so name the field explicitly
             $aForm['inputs']['keyword']['attrs']['placeholder'] = _t('_sys_search_placeholder');
             $aForm['inputs']['keyword']['attrs']['onkeydown'] = "return bx_search_on_type(event, $sJsParams);";
             $aForm['inputs']['keyword']['attrs']['onpaste'] = $aForm['inputs']['keyword']['attrs']['onkeydown'];

+ 1 - 1
template/uploader_button_html5.html

@@ -1,4 +1,4 @@
 <!--<a __attrs__ href="javascript:void(0);" class="bx-btn bx-def-margin-sec-right __btn_class__">__button_title__</a>-->
 <div id="__div_id__" class="filepond bx-uploader-html5-drop-area m-2 border-2 border-gray-300 dark:border-gray-700 text-gray-700 dark:text-gray-300 bg-gray-50 dark:bg-gray-900/50 border-dashed rounded-lg"></div>
-<input type="text" id="__focus_div_id__" class="bx-uploader-html5-paste-catcher" tabindex="1" />
+<input type="text" id="__focus_div_id__" class="bx-uploader-html5-paste-catcher" tabindex="-1" aria-label="<bx_text_attribute:_sys_uploader_simple_submit_button />" />
 <div id="__errors_container_id__" class="bx-uploader-html5-errors-area bx-def-font-small"></div>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor