diff --git a/local/config/vufind/searches.ini b/local/config/vufind/searches.ini
index 1dbec8eddd33723afa4ba2786ee92204f0ada6a1..82440759a23ef798b0fbd54f85784c6f4c0e66d8 100644
--- a/local/config/vufind/searches.ini
+++ b/local/config/vufind/searches.ini
@@ -98,6 +98,15 @@ retain_filters_by_default = true
 ;default_filters[] = "institution:MyInstitution"
 ;default_filters[] = "(format:Book AND institution:MyInstitution)"
 
+; Avoid query rebuilding in case the user injects a query in lucene like syntax.
+; Provide an array of Search Types for which the lucene query syntax detection
+; MUST NOT be applied.
+; Note: this does not work for Search Types used in advanced search as avoiding
+;       advanced lucene detection needs would have to be set either for all
+;       Search Types used in advanced search or for none at all. Disabling
+;       advanced lucene detection for a search does not work partially!
+;override_advanced_lucene_detection[] = Signatur;
+
 [Cache]
 ; This controls whether the parsed searchspecs.yaml file will be stored to
 ; improve search performance; legal options are APC (use APC cache), File (store
diff --git a/module/fid/src/View/Helper/Root/GetIt.php b/module/fid/src/View/Helper/Root/GetIt.php
index b8a79995a376bc6b04a5eeb4374e6094fe6f0e27..f12571cd82d20455ef0ab824bcd1c3dc48a94b5c 100644
--- a/module/fid/src/View/Helper/Root/GetIt.php
+++ b/module/fid/src/View/Helper/Root/GetIt.php
@@ -241,7 +241,6 @@ class GetIt extends AbstractHelper
         $accordeonHeadline = $this->accordeonHeadlineDefault;
         $boxHeadline = $this->translate('Get it');
         $notice = $this->translate('getit_text_default');
-        $noticeWithLink = null;
         $showLinks = true;
         $showOrderButton = false;
         $showPartCopyButton = false;
@@ -250,6 +249,7 @@ class GetIt extends AbstractHelper
         $isEBCEBooks = false;
         $hideNotice = false;
         $isAiSidRecord = false;
+        $noticeLinkType = 'register';
 
         // let specific functions override defaults where necessary
         foreach ($this->sids as $sid_config) {
diff --git a/module/finc/config/module.config.php b/module/finc/config/module.config.php
index b2f39e304cdf7b8452a8434d147891356501df92..7673bcd88c9a4de514c7e6cf031600f08fd18083 100644
--- a/module/finc/config/module.config.php
+++ b/module/finc/config/module.config.php
@@ -164,6 +164,7 @@ $config = [
                     ],
                     'finc\RecordDriver\SolrMarcFinc' => [
                         'VuFind\RecordDriver\IlsAwareDelegatorFactory',
+                        'finc\RecordDriver\SolrMarcUrlRulesDelegatorFactory',
                     ],
                     'finc\RecordDriver\SolrMarcFincPDA' => [
                         'VuFind\RecordDriver\IlsAwareDelegatorFactory',
diff --git a/module/finc/src/finc/Controller/Admin/I18nController.php b/module/finc/src/finc/Controller/Admin/I18nController.php
index 107bde55196cb7ac9b76c5294e48c2ad6ac0c079..7052a038b9d04e14d16ef0be2e2c8b4e4e37eafd 100644
--- a/module/finc/src/finc/Controller/Admin/I18nController.php
+++ b/module/finc/src/finc/Controller/Admin/I18nController.php
@@ -20,18 +20,17 @@
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     https://vufind.org/wiki/development Wiki
  */
-
 namespace finc\Controller\Admin;
 
 use Symfony\Component\Filesystem\Filesystem as Fs;
 use VuFind\Auth\InvalidArgumentException;
 use VuFind\Config\Writer as ConfigWriter;
-use VuFind\Controller\AbstractBase;
 use VuFind\I18n\Translator\Loader\ExtendedIni;
+use VuFindAdmin\Controller\AbstractAdmin;
 use Zend\I18n\Translator\Translator;
 use Zend\ServiceManager\ServiceLocatorInterface;
 
-class I18nController extends AbstractBase
+class I18nController extends AbstractAdmin
 {
     /**
      * @var string[]
@@ -89,7 +88,6 @@ class I18nController extends AbstractBase
         $this->languages = array_combine($locales, $languages);
     }
 
-
     public function homeAction()
     {
         $params = $this->params();
@@ -165,7 +163,6 @@ class I18nController extends AbstractBase
             $locale,
             $reset ? null : $value
         );
-
     }
 
     protected function getTranslations(): array
@@ -243,14 +240,13 @@ class I18nController extends AbstractBase
     protected function saveTranslation($domain, $token, $locale, $value)
     {
         $fs = new FS();
-        list($filename) = array_slice($this->dirs, -1);;
+        list($filename) = array_slice($this->dirs, -1);
         if ($domain !== 'default') {
             $filename .= "/$domain";
         }
         $filename .= "/$locale.ini";
 
         try {
-
             if (empty($token)) {
                 throw new InvalidArgumentException(
                     $this->translate('This field is required') . ": Token"
@@ -366,4 +362,4 @@ class I18nController extends AbstractBase
         $response->setStatusCode(205);
         return $response;
     }
-}
\ No newline at end of file
+}
diff --git a/module/finc/src/finc/Controller/CustomTraits/SearchTrait.php b/module/finc/src/finc/Controller/CustomTraits/SearchTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..6b9fe2396111f7c735e698e1f97aabc85317f91d
--- /dev/null
+++ b/module/finc/src/finc/Controller/CustomTraits/SearchTrait.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Search Trait
+ *
+ * PHP version 7
+ *
+ * Copyright (C) Villanova University 2010.
+ * Copyright (C) Leipzig University Library 2021.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Controller
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Robert Lange <lange@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org   Main Site
+ */
+namespace finc\Controller\CustomTraits;
+
+use VuFindSearch\Query\Query as Query;
+
+/**
+ * Search Trait
+ *
+ * @category VuFind
+ * @package  Controller
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Robert Lange <lange@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org   Main Site
+ */
+trait SearchTrait
+{
+    /**
+     * Search for related records specified via field and values. Current Record may
+     * be explicity excluded from the search.
+     *
+     * Note: Location of trait is not optimal but a more appropriate location
+     * in the search backend seemed too complicated for implementation,
+     * therefore controller traits was chosen.
+     * TODO: find more appropriate location for trait
+     *
+     * Returns an array containing
+     * * 'first_results' - array of up to $limit record objects
+     * * 'more_query'    - query string to be used when tryiong to retrieve ALL
+     *                     related records
+     *
+     * @param string $field solr field
+     * @param array $values solr values to look for
+     * @param int $limit max results (default is 20)
+     * @param array $filters fq associative array $filterField => $value
+     * @param string $backend_id type of backend (default is Solr)
+     * @param bool $excludeUniqueId when THIS current record should be excluded TRUE, otherwise FALSE (default is true)
+     *
+     * @return mixed
+     */
+    public function searchRelatedRecords(
+        $field,
+        $values,
+        $limit = 20,
+        $filters = [],
+        $backend_id = 'Solr',
+        $excludeUniqueId = true
+    ) {
+        if (!empty($filters)) {
+            $fq = '';
+            foreach ($filters as $filterField => $value) {
+                $fq = (empty($fq) ? '' : ' AND ')
+                    . "$filterField:$value";
+            }
+        }
+
+        $query = new Query(
+            $field . ':(' . implode(' OR ', $values)
+            . ')' . ($excludeUniqueId ? ' AND NOT id:' . $this->getUniqueID() : '')
+            . (isset($fq) ? " AND $fq" : '')
+        );
+
+        $result = $this->searchService->search($backend_id, $query, 0, $limit);
+        $return['first_results'] = $result->getRecords();
+
+        if (isset($limit) && $result->getTotal() > $limit) {
+            $return['more_query'] = $query->getString();
+        }
+
+        return $return;
+    }
+}
diff --git a/module/finc/src/finc/ILS/Driver/FincILS.php b/module/finc/src/finc/ILS/Driver/FincILS.php
index edf613808c1d286beb5a95bfe5832a146bdc1ca4..fd6dee3b7a9956b03b1e90bff2d47e4b69205f09 100644
--- a/module/finc/src/finc/ILS/Driver/FincILS.php
+++ b/module/finc/src/finc/ILS/Driver/FincILS.php
@@ -30,9 +30,11 @@ namespace finc\ILS\Driver;
 use DateTime;
 use DateInterval;
 use DateTimeZone;
+use finc\Controller\CustomTraits\SearchTrait as SearchTrait;
 use Herrera\Json\Exception\Exception;
 use Sabre\VObject;
 use VuFind\Exception\ILS as ILSException;
+use VuFindSearch\ParamBag;
 use VuFindSearch\Query\Query;
 use VuFindSearch\Service as SearchService;
 use Zend\Log\LoggerAwareInterface as LoggerAwareInterface;
@@ -52,6 +54,8 @@ use ZfcRbac\Service\AuthorizationServiceAwareTrait;
  */
 class FincILS extends PAIA implements LoggerAwareInterface
 {
+    use SearchTrait;
+    const ILS_IDENTIFIER_BARCODE = 'barcode';
 
     // vCard ADR is an ordered list of the following values
     // 0 - the post office box;
@@ -78,7 +82,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
      * identifier retrieved by @getILSRecordId()
      *
      * @var array
-     * @access private
      * @deprecated
      */
     private $idMapper = [];
@@ -96,7 +99,7 @@ class FincILS extends PAIA implements LoggerAwareInterface
      *
      * @var array
      */
-    protected $dynamicFields = ['barcode'];
+    protected $dynamicFields = [self::ILS_IDENTIFIER_BARCODE];
 
     /**
      * ISIL used for identifying the correct ILS-identifier if array is returned
@@ -222,7 +225,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
                 ? $this->config['General']['ilsTestTimeout'] : 90;
     }
 
-
     /**
      * This optional method (introduced in VuFind 1.4) gets the online status of the
      * ILS – “ils-offline” for systems where the main ILS is offline, “ils-none” for
@@ -285,7 +287,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
      * @param array $item Item
      *
      * @return bool
-     * @access protected
      */
     protected function checkEmailHoldValidationCriteria($item)
     {
@@ -306,7 +307,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
      * settings in FincILS.ini.
      *
      * @return array
-     * @access protected
      */
     protected function getEmailHoldValidationCriteria()
     {
@@ -372,15 +372,70 @@ class FincILS extends PAIA implements LoggerAwareInterface
     /**
      * PAIA support method - try to find fincid for last segment of PAIA id
      *
-     * @param string $id     itemId
-     * @param string $idType id type to override ILS settings
+     * @param string|array  $id     itemId
+     * @param string        $idType id type to override ILS settings, default is barcode
      *
-     * @return string $id
+     * @return string|array
      */
-    protected function getAlternativeItemId($id, $idType = null)
+    protected function getAlternativeItemId($ids, $idType = null)
     {
-        $array = explode(":", $id);
-        return $this->getFincId(end($array), $idType);
+        $retval = [];
+
+        try {
+            if (!is_array($ids)) {
+                $ids = [$ids];
+                $isSingleId = true;
+            }
+
+            if ($idType === null) {
+                $idType = $this->ilsIdentifier;
+            }
+
+            if ($idType !== self::ILS_IDENTIFIER_BARCODE) {
+                foreach ($ids as &$id) {
+                    if ($pos = strrpos($id, ':')) {
+                        $id = substr($id,$pos + 1);
+                    }
+                }
+            }
+
+            $uniqueIds = array_unique($ids);
+            foreach ($uniqueIds as &$id) {
+                $id = addcslashes($id, ':');
+            }
+
+            if ($idType != "default") {
+                // different ilsIdentifier is configured, retrieve fincid
+                // if the given ilsIdentifier is known as a dynamic field it is suffixed
+                // with the isil
+                if (in_array($idType, $this->dynamicFields)) {
+                    if (isset($this->mainConfig->CustomIndex->indexExtension)) {
+                        $idType .= "_"
+                            . trim($this->mainConfig->CustomIndex->indexExtension);
+                    }
+                }
+            }
+
+            $new = $this->searchRelatedRecords($idType, $uniqueIds, 9999, [], 'Solr', false);
+            if (count($new['first_results']) > 0) {
+                $retval = array_fill(0, count($ids), false);
+                foreach ($new['first_results'] as $record) {
+                    /** @var \finc\RecordDriver\SolrDefault $record */
+                    $callNumbers = $record->getField($idType);
+                    $matches = array_intersect($ids, $callNumbers);
+                    foreach ($matches as $number => $match) {
+                        /* map identifier to solr id */
+                        $retval[$number] = $record->getUniqueID();
+                    }
+                }
+                ksort($retval);
+                return ($isSingleId ?? false) ? $retval[0] : array_values($retval);
+            }
+        } catch (\Exception $e) {
+            $this->debug($e);
+        }
+
+        return $retval;
     }
 
     /**
@@ -412,7 +467,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
      * @param string $id Identifier
      *
      * @return mixed parent::getStatus()
-     * @access protected
      */
     protected function doGetStatus($id)
     {
@@ -518,15 +572,13 @@ class FincILS extends PAIA implements LoggerAwareInterface
         // fee.item  0..1 URI    item that caused the fee
         // fee.feeid 0..1 URI    URI of the type of service that
         // caused the fee
-        $additionalData['feeid']      = (isset($fee['feeid'])
-            ? $fee['feeid'] : null);
-        $additionalData['about']      = (isset($fee['about'])
-            ? $fee['about'] : null);
-        $additionalData['item']       = (isset($fee['item'])
-            ? $fee['item'] : null);
+        $additionalData['feeid'] = ($fee['feeid'] ?? null);
+        $additionalData['about'] = ($fee['about'] ?? null);
+        $additionalData['item'] = ($fee['item'] ?? null);
 
         return $additionalData;
     }
+
     /**
      * Get Patron Profile
      *
@@ -580,14 +632,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
                             (string)$vcard->{'X-LIBRARY-ILS-PATRON-EDIT-ALLOW'}
                         );
                     }
-                    if (isset($vcard->{'X-LIBRARY-BORROWER-BLACK-LIST-INDICATOR'})) {
-                        $statuscodeInd
-                            = (string)$vcard->{'X-LIBRARY-BORROWER-BLACK-LIST-INDICATOR'};
-                    }
-                    if (isset($vcard->{'X-LIBRARY-BORROWER-BLACK-LIST-DESCRIPTION'})) {
-                        $statuscodeDesc
-                            = (string)$vcard->{'X-LIBRARY-BORROWER-BLACK-LIST-DESCRIPTION'};
-                    }
                 } catch (Exception $e) {
                     throw $e;
                 }
@@ -632,23 +676,19 @@ class FincILS extends PAIA implements LoggerAwareInterface
             }
 
             $idm = [
-                'firstname'  => $patron['firstname'],
-                'lastname'   => $patron['lastname'],
+                'firstname' => $patron['firstname'],
+                'lastname' => $patron['lastname'],
                 'group' => (!empty($group)) ? $group : null,
                 // PAIA specific custom values
-                'expires'    => isset($patron['expires'])
+                'expires' => isset($patron['expires'])
                     ? $this->convertDate($patron['expires']) : null,
-                'statuscode' => isset($patron['status'])
-                    ? $patron['status'] : null,
-                'statuscodeInd' => isset($statuscodeInd)
-                    ? $statuscodeInd : null,
-                'statuscodeDesc' => isset($statuscodeDesc)
-                    ? $statuscodeDesc : null,
-                'note' => isset($patron['note'])
-                    ? $patron['note'] : null,
-                'canWrite'   => in_array(self::SCOPE_WRITE_ITEMS, $this->getSession()->scope),
+                'statuscode' => $patron['status'] ?? null,
+                'statuscodeInd' => $statuscodeInd ?? null,
+                'statuscodeDesc' => $statuscodeDesc ?? null,
+                'note' => $patron['note'] ?? null,
+                'canWrite' => in_array(self::SCOPE_WRITE_ITEMS, $this->getSession()->scope),
                 // fincILS and PAIA specific custom values
-                'email'      => !empty($patron['email'])
+                'email' => !empty($patron['email'])
                     ? $patron['email'] : (!empty($emails[0]) ? $emails[0] : null),
                 'editableFields' => (!empty($editable)) ? $editable : null,
                 'home_library' => (!empty($home_library)) ? $home_library : null
@@ -664,7 +704,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
      * @param array $vcard_fields Fields of vcard which can be edited.
      *
      * @return array $fields     Translated form Field which can be modified
-     * @access private
      */
     private function getEditableProfileFields($vcard_fields)
     {
@@ -714,12 +753,11 @@ class FincILS extends PAIA implements LoggerAwareInterface
      * @param array $patron Patron data
      *
      * @return boolean true OK, false FAIL
-     * @access public
      */
     public function setMyProfile($inval, $patron)
     {
-        $params['memberCode']   = $patron['cat_username'];
-        $params['password']     = $patron['cat_password'];
+        $params['memberCode'] = $patron['cat_username'];
+        $params['password'] = $patron['cat_password'];
 
         if (isset($patron['address']) && strpos($patron['address'], 'BEGIN:VCARD') === 0) {
             $vcard = \Sabre\VObject\Reader::read($patron['address']);
@@ -764,7 +802,7 @@ class FincILS extends PAIA implements LoggerAwareInterface
             ? $this->config['PAIA']['profileFormEmptyInputReplacement'] : null;
 
         foreach ($inval as $key => $val) {
-            if (empty($val) && !is_null($replace)) {
+            if (empty($val) && null !== $replace) {
                 $val = $replace;
             }
 
@@ -860,7 +898,7 @@ class FincILS extends PAIA implements LoggerAwareInterface
             return true;
         }
 
-        $this->debug(__FUNCTION__.' '.$result['sysMessage']);
+        $this->debug(__FUNCTION__ . ' ' . $result['sysMessage']);
         return false;
     }
 
@@ -870,7 +908,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
      * @param string $address
      *
      * @return mixed
-     * @access private
      */
     private function splitAddress($address)
     {
@@ -886,7 +923,7 @@ class FincILS extends PAIA implements LoggerAwareInterface
         $conf = $this->config;
         $regex = '(\D+\d[^\,]*)(?:\,\s*(.*))?';
         $matches = [];
-        if (preg_match('/'.$regex.'/', $address, $matches)) {
+        if (preg_match('/' . $regex . '/', $address, $matches)) {
             return $matches;
         }
         return false;
@@ -960,7 +997,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
      *
      * @return mixed Associative array of patron info on successful login,
      * null on unsuccessful login.
-     * @access public
      * @throws \Exception
      * @throws ILSException
      */
@@ -1017,7 +1053,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
      *
      * @return mixed Associative array of patron info on successful login,
      * null on unsuccessful login.
-     * @access public
      */
     public function refreshLogin($username, $password)
     {
@@ -1071,7 +1106,7 @@ class FincILS extends PAIA implements LoggerAwareInterface
         if (!isset($itemsResponse) || $itemsResponse == null) {
             try {
                 $itemsResponse = $this->paiaGetAsArray(
-                    'core/'.$patron['cat_username'].'/items'
+                    'core/' . $patron['cat_username'] . '/items'
                 );
             } catch (\Exception $e) {
                 // all error handling is done in paiaHandleErrors so pass on the excpetion
@@ -1094,7 +1129,7 @@ class FincILS extends PAIA implements LoggerAwareInterface
                                 // check exclude filters
                                 $excludeCounter = 0;
                                 foreach ($filterValue as $excludeKey => $excludeValue) {
-                                    if ((isset($doc[$excludeKey]) && in_array($doc[$excludeKey], (array) $excludeValue))
+                                    if ((isset($doc[$excludeKey]) && in_array($doc[$excludeKey], (array)$excludeValue))
                                         || ($excludeValue == null && !isset($doc[$excludeKey]))
                                     ) {
                                         $excludeCounter++;
@@ -1125,7 +1160,7 @@ class FincILS extends PAIA implements LoggerAwareInterface
                             default:
                                 // any other filter is a positive filter, so the item
                                 // might be selected if the key-value pair does match
-                                if ((isset($doc[$filterKey]) && in_array($doc[$filterKey], (array) $filterValue))
+                                if ((isset($doc[$filterKey]) && in_array($doc[$filterKey], (array)$filterValue))
                                     || ($filterValue == null && !isset($doc[$filterKey]))
                                 ) {
                                     $filterCounter++;
@@ -1167,8 +1202,7 @@ class FincILS extends PAIA implements LoggerAwareInterface
     }
 
     /**
-     * Helper function to postprocess the PAIA items for display in catalog (e.g. retrieve
-     * fincid etc.).
+     * Helper function to postprocess the PAIA items for display in catalog (e.g. retrieve solr id etc.).
      *
      * @param array $items Array of PAIA items to be postprocessed
      *
@@ -1181,11 +1215,11 @@ class FincILS extends PAIA implements LoggerAwareInterface
 
         // item_id identifier - Solr field mapping
         $identifier = [
-            'barcode' => 'barcode' .
+            self::ILS_IDENTIFIER_BARCODE => self::ILS_IDENTIFIER_BARCODE .
                 (isset($this->mainConfig->CustomIndex->indexExtension)
-                    ? '_'.$this->mainConfig->CustomIndex->indexExtension : ''),
-            'fincid'  => 'id',
-            'ppn'     => 'record_id'
+                    ? '_' . $this->mainConfig->CustomIndex->indexExtension : ''),
+            'fincid' => 'id',
+            'ppn' => 'record_id'
         ];
 
         // try item_id with defined regex pattern and identifiers and use Solr to
@@ -1194,8 +1228,8 @@ class FincILS extends PAIA implements LoggerAwareInterface
             foreach ($identifier as $key => $value) {
                 $matches = [];
                 if (preg_match(sprintf($idPattern, $key), $itemId, $matches)) {
-                    return $this->getFincId(
-                        addcslashes($matches[3],':'),
+                    return $this->getAlternativeItemId(
+                        $matches[3],
                         $value
                     );
                 }
@@ -1243,9 +1277,9 @@ class FincILS extends PAIA implements LoggerAwareInterface
         $returnArray = [];
 
         if (count($items) && !empty($fieldName)) {
-            for ($i=0; $i<count($items); $i++) {
+            for ($i = 0; $i < count($items); $i++) {
                 if (isset($items[$i][$fieldName])) {
-                    $sortArray[$i]=$items[$i][$fieldName];
+                    $sortArray[$i] = $items[$i][$fieldName];
                 } else {
                     array_push($noSortArray, $items[$i]);
                 }
@@ -1311,7 +1345,7 @@ class FincILS extends PAIA implements LoggerAwareInterface
         $fines = $this->getMyFines($patron);
         $total = 0.0;
         foreach ($fines as $fee) {
-            $total += (float) $fee['amount'];
+            $total += (float)$fee['amount'];
         }
         return $total / 100;
     }
@@ -1347,12 +1381,12 @@ class FincILS extends PAIA implements LoggerAwareInterface
             $dateObj = new DateTime($date, new DateTimeZone($timezone));
 
             $intervalSpec = 'P' .
-                ($years   != null ? $years . 'Y'         : '') .
-                ($months  != null ? $months . 'M'        : '') .
-                ($days    != null ? $days . 'D'          : '') .
-                ($hours   != null ? $hours . 'H'         : '') .
+                ($years != null ? $years . 'Y' : '') .
+                ($months != null ? $months . 'M' : '') .
+                ($days != null ? $days . 'D' : '') .
+                ($hours != null ? $hours . 'H' : '') .
                 ($minutes != null ? 'T' . $minutes . 'M' : '') .
-                ($seconds != null ? $seconds . 'S'       : '');
+                ($seconds != null ? $seconds . 'S' : '');
             $dateInterval = new DateInterval($intervalSpec);
 
             return $dateObj->add($dateInterval)->format('Y-m-d\TH:i:s');
@@ -1386,17 +1420,17 @@ class FincILS extends PAIA implements LoggerAwareInterface
             );
             $context = [
                 'authenticator' => $this->auth,
-                'record' => $this->getRecord($id)
+                'record' => $this->getRecord($id),
             ];
             $context = $eval($context);
             return [[
-                'id'           => $id,
+                'id' => $id,
                 'availability' => $context['available'],
-                'status'       => $context['available'] ? 'available' : 'unavailable',
-                'reserve'      => 'false',
-                'location'     => '',
-                'callnumber'   => '',
-                'services'     => (array)$context['decider']
+                'status' => $context['available'] ? 'available' : 'unavailable',
+                'reserve' => 'false',
+                'location' => '',
+                'callnumber' => '',
+                'services' => (array)$context['decider']
             ]];
         }
         $permission = $this->getRecord($id)->tryMethod('getRecordPermission');
@@ -1405,13 +1439,13 @@ class FincILS extends PAIA implements LoggerAwareInterface
             ? $this->auth->isGranted($permission) : true;
 
         return [[
-            'id'           => $id,
+            'id' => $id,
             'availability' => $isGranted,
-            'status'       => $isGranted ? 'available' : $permission,
-            'reserve'      => 'false',
-            'location'     => '',
-            'callnumber'   => '',
-            'services'     => !$isGranted ? [$permission] : []
+            'status' => $isGranted ? 'available' : $permission,
+            'reserve' => 'false',
+            'location' => '',
+            'callnumber' => '',
+            'services' => !$isGranted ? [$permission] : []
         ]];
     }
 
@@ -1618,59 +1652,6 @@ class FincILS extends PAIA implements LoggerAwareInterface
         return $ids;
     }
 
-    /**
-     * Get the finc id of the record with the given ilsIdentifier value
-     *
-     * @param string $ilsId         Document to look up.
-     * @param string $ilsIdentifier Identifier to override config settings.
-     *
-     * @return string $fincId if ilsIdentifier is configured, otherwise $ilsId
-     */
-    private function getFincId($ilsId, $ilsIdentifier = null)
-    {
-        // override ilsIdentifier with the ilsIdentifier set in ILS driver config
-        if ($ilsIdentifier == null) {
-            $ilsIdentifier = $this->ilsIdentifier;
-        }
-
-        if ($ilsIdentifier != "default") {
-            // different ilsIdentifier is configured, retrieve fincid
-
-            // if the given ilsIdentifier is known as a dynamic field it is suffixed
-            // with the isil
-            if (in_array($ilsIdentifier, $this->dynamicFields)) {
-                if (isset($this->mainConfig->CustomIndex->indexExtension)) {
-                    $ilsIdentifier .= "_"
-                        . trim($this->mainConfig->CustomIndex->indexExtension);
-                }
-            }
-            try {
-                // todo: compatible implementation for any SearchBackend (currently Solr only)
-                $query = $ilsIdentifier . ':' . $ilsId;
-                $result = $this->searchService->search(
-                    'Solr',
-                    new Query($query)
-                );
-                if (count($result) === 0) {
-                    throw new \Exception(
-                        'Problem retrieving finc id for record with ' . $query
-                    );
-                }
-                return current($result->getRecords())->getUniqueId();
-            } catch (\Exception $e) {
-                $this->debug($e);
-                // refs #12318 return falls if no main identifier can delivered
-                // null will logically correct but throws exceptions in
-                // subsequential core methods
-                return false;
-            }
-        }
-        // todo: check if return $ilsId is reasonable in context.
-        // return will be only processed if $ilsIdentifier is defined as
-        // 'default'. therefore method hasn't been called properly.
-        return $ilsId;
-    }
-
     /**
      * Private service test method
      *
diff --git a/module/finc/src/finc/ILS/Driver/FincLibero.php b/module/finc/src/finc/ILS/Driver/FincLibero.php
index 8f562ec316f6d5d3018d1cb9004bc719fdbd4adf..8c552e7387710567d5bbd0afafb0fb8b81e6b827 100644
--- a/module/finc/src/finc/ILS/Driver/FincLibero.php
+++ b/module/finc/src/finc/ILS/Driver/FincLibero.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Finc specific Libero ILS Driver for VuFind, using PAIA, DAIA and LiberoDing
+ * Finc specific Libero ILS Driver for VuFind, using PAIA, DAIA and LiberoWachtl
  * services.
  *
  * PHP version 5
@@ -30,9 +30,10 @@ namespace finc\ILS\Driver;
 use VuFind\I18n\Translator\TranslatorAwareTrait;
 use VuFind\I18n\Translator\TranslatorAwareInterface,
     VuFind\Exception\ILS as ILSException;
+use VuFindSearch\Query\Query;
 
 /**
- * Finc specific Libero ILS Driver for VuFind, using PAIA, DAIA and LiberoDing
+ * Finc specific Libero ILS Driver for VuFind, using PAIA, DAIA and LiberoWachtl
  * services.
  *
  * @category VuFind2
@@ -45,7 +46,7 @@ class FincLibero extends FincILS implements TranslatorAwareInterface
 {
     const DELETE_NOTIFICATIONS_SUCCESS = '1';
     const DELETE_NOTIFICATIONS_ERROR = '0';
-    use LiberoDingTrait;
+    use LiberoWachtlTrait;
     use TranslatorAwareTrait;
 
     /**
@@ -106,6 +107,25 @@ class FincLibero extends FincILS implements TranslatorAwareInterface
      */
     protected $readingRoomURIs = [];
 
+    /**
+     * Regex pattern to detect bound item ID
+     * @var string
+     */
+    protected $boundItemIdPattern;
+
+    /**
+     * Regex pattern to detect bound item label
+     * @var string
+     */
+    protected $boundItemLabelPattern;
+
+    public function init()
+    {
+        parent::init();
+        $this->boundItemIdPattern = $this->config['General']['bound_item_id_pattern'] ?? null;
+        $this->boundItemLabelPattern = $this->config['General']['bound_item_label_pattern'] ?? null;
+    }
+
     /**
      * Helper function to extract the Namespace from the DAIA URI prefix.
      *
@@ -701,14 +721,199 @@ class FincLibero extends FincILS implements TranslatorAwareInterface
         return $pickUpLocations;
     }
 
+
     /**
-     * TODO: check status of this function
-     * de_15 -> getBoundItemId() vs. de_l152 -> getBoundItemInfo()
-     * @param $item
-     * @return array
+     * Helper method to check whether this item is bound with another item and needs
+     * to be ordered via this bound item
+     *
+     * @param array $item Array with DAIA item data
+     *
+     * @return null
      */
     protected function getBoundItemId($item)
     {
-        return [];
+        if (!isset($this->boundItemIdPattern)) return null;
+        $availabilities = ['available', 'unavailable'];
+
+        // start logic to check if we have a bound item that needs to be ordered
+        // via another record (see https://intern.finc.info/issues/5068)
+        foreach ($availabilities as $availability) {
+            if (isset($item[$availability])) {
+                foreach ($item[$availability] as $available) {
+                    if (isset($available['limitation'])) {
+                        foreach ($available['limitation'] as $limitation) {
+                            if (in_array($limitation['id'], $this->awlLimitations)) {
+                                // items with limitations identifying the record for
+                                // being bound to another item contain the RSN of the
+                                // bound item in their current available service href
+                                if (isset($available['href'])
+                                    && preg_match($this->boundItemIdPattern,
+                                        $available['href'],
+                                        $matches
+                                    )
+                                ) {
+                                    return $this->queryBoundItem($matches['id']);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // if we made it this far this item definitely is not bound to another item
+        return null;
+    }
+
+
+    /**
+     * Helper method to query bound item by rsn for record_id
+     *
+     * @param string $key
+     *
+     * @return string record_id
+     */
+    protected function queryBoundItem($key) {
+
+        $query = $this->getBoundItemQueryString($key);
+        if (empty($query)) {
+            return null;
+        }
+        try {
+            // let's search with the built query
+            $result = $this->searchService
+                ->search('VuFind', new Query($query));
+            if (count($result) === 0) {
+                $this->debug('Problem retrieving rsn ' .
+                    'for record with query:' . $query);
+                return null;
+            }
+            // pass the id from the first found record as
+            // awlRecordId to the controller
+            return current($result->getRecords())
+                ->getUniqueId();
+        } catch (\Exception $e) {
+            $this->debug($e);
+            return null;
+        }
+    }
+
+    /**
+     * Check if item is a pretended dummy to signify there is a title order
+     * possible.
+     *
+     * @param array $item DAIA item
+     *
+     * @return mixed
+     */
+    public function isTitleHold($item)
+    {
+        foreach ($this->titleHoldLimitations as $limitation) {
+            $regex = '/^' . trim($limitation) . '$/';
+            if (0 < preg_match($regex, $item['id'])) {
+                return true;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Place Title Hold
+     *
+     * Attempts to place a hold or recall on a particular item and returns
+     * an array with result details
+     *
+     * Make a request on a specific record
+     *
+     * @param array $holdDetails An array of item and patron data
+     *
+     * @return mixed An array of data on the request including
+     * whether or not it was successful and a system message (if available)
+     */
+    public function placeTitleHold($holdDetails)
+    {
+        $item = $holdDetails['item_id'];
+        $patron = $holdDetails['patron'];
+        $doc = [];
+        $doc['item'] = stripslashes($item);
+        if ($confirm = $this->getConfirmations(
+            $this->extendPickUpLocation($holdDetails)
+        )) {
+            $doc["confirm"] = $confirm;
+        }
+        $post_data['doc'][] = $doc;
+        try {
+            $array_response = $this->paiaPostAsArray(
+                'core/'.$patron['cat_username'].'/request', $post_data
+            );
+        } catch (Exception $e) {
+            $this->debug($e->getMessage());
+            return [
+                'success' => false,
+                'sysMessage' => $e->getMessage(),
+            ];
+        }
+        $details = [];
+        if (array_key_exists('error', $array_response)) {
+            $details = [
+                'success' => false,
+                'sysMessage' => $array_response['error_description']
+            ];
+        } else {
+            $elements = $array_response['doc'];
+            foreach ($elements as $element) {
+                if (array_key_exists('error', $element)) {
+                    $details = [
+                        'success' => false,
+                        'sysMessage' => $element['error']
+                    ];
+                } else {
+                    // FincLibero supports more expressive responses from paialibero
+                    // which should be shown instead to the user (localIlsStatus)
+                    $details = [
+                        'success' => true,
+                        'sysMessage' => isset($element['localIlsStatus'])
+                            ? $element['localIlsStatus'] : 'Successfully requested'
+                    ];
+                    // if caching is enabled for DAIA remove the cached data for the
+                    // current item otherwise the changed status will not be shown
+                    // before the cache expires
+                    if ($this->daiaCacheEnabled) {
+                        $this->removeCachedData($holdDetails['doc_id']);
+                    }
+                }
+            }
+        }
+        return $details;
+    }
+
+    /**
+     * Extend pickup location with base department URI
+     *
+     * @param array $holdDetails An array of item and patron data.
+     *
+     * @return array $holdDetails;
+     */
+    protected function extendPickUpLocation($holdDetails)
+    {
+        if (isset($holdDetails['pickUpLocation'])) {
+            $holdDetails['pickUpLocation']
+                = $this->departmentLocationBase . $holdDetails['pickUpLocation'];
+        }
+        return $holdDetails;
+    }
+
+    /**
+     * Helper function for queryBoundItem. Prepares instance specific query string
+     * to get the ID of the bound item
+     *
+     * Override in inherited FincLibero
+     *
+     * @param $key string   ID to search for
+     * @return string       SOLR query to be used as q parameter
+     */
+    protected function getBoundItemQueryString($key)
+    {
+        return '';
     }
 }
diff --git a/module/finc/src/finc/ILS/Driver/LiberoDingTrait.php b/module/finc/src/finc/ILS/Driver/LiberoWachtlTrait.php
similarity index 79%
rename from module/finc/src/finc/ILS/Driver/LiberoDingTrait.php
rename to module/finc/src/finc/ILS/Driver/LiberoWachtlTrait.php
index 3940de37c6ff605239895f050f3ee746be7f826f..6135ea641d59fa38bd564fea19572276f6edb3af 100644
--- a/module/finc/src/finc/ILS/Driver/LiberoDingTrait.php
+++ b/module/finc/src/finc/ILS/Driver/LiberoWachtlTrait.php
@@ -1,7 +1,7 @@
 <?php
 /**
- * Finc specific LiberoDing trait providing all the functions necessary for
- * communicating with the LiberoDing.
+ * Finc specific LiberoWachtl trait providing all the functions necessary for
+ * communicating with the LiberoWachtl.
  *
  * PHP version 5
  *
@@ -32,8 +32,8 @@ use VuFind\Exception\ILS as ILSException;
 use Zend\Log\LoggerAwareInterface as LoggerAwareInterface;
 
 /**
- * Finc specific LiberoDing trait providing all the functions necessary for
- * communicating with the LiberoDing.
+ * Finc specific LiberoWachtl trait providing all the functions necessary for
+ * communicating with the LiberoWachtl.
  *
  * @category VuFind
  * @package  ILS_Drivers
@@ -41,8 +41,13 @@ use Zend\Log\LoggerAwareInterface as LoggerAwareInterface;
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     https://vufind.org/wiki/development:plugins:ils_drivers Wiki
  */
-trait LiberoDingTrait
+trait LiberoWachtlTrait
 {
+    /**
+     * @var $liberoWachtlUrl string URL of wachtl API
+     */
+    protected $liberoWachtlUrl;
+
     /**
      * Get connection timeout of Libero request.
      *
@@ -53,9 +58,9 @@ trait LiberoDingTrait
      */
     protected function getConnectTimeout($connectTimeout = 500)
     {
-        return $test = (isset($this->config['LiberoDing']['connectTimeout'])
-            && is_numeric($this->config['LiberoDing']['connectTimeout']))
-            ? $this->config['LiberoDing']['connectTimeout']
+        return $test = (isset($this->config['LiberoWachtl']['connectTimeout'])
+            && is_numeric($this->config['LiberoWachtl']['connectTimeout']))
+            ? $this->config['LiberoWachtl']['connectTimeout']
             : $connectTimeout;
     }
 
@@ -69,25 +74,28 @@ trait LiberoDingTrait
      */
     protected function getResponseTimeout($responseTimeout = 1000)
     {
-        return (isset($this->config['LiberoDing']['responseTimeout'])
-            && is_numeric($this->config['LiberoDing']['responseTimeout']))
-            ? $this->config['LiberoDing']['responseTimeout']
+        return (isset($this->config['LiberoWachtl']['responseTimeout'])
+            && is_numeric($this->config['LiberoWachtl']['responseTimeout']))
+            ? $this->config['LiberoWachtl']['responseTimeout']
             : $responseTimeout;
     }
 
     /**
-     * gets the webscraper url from config
+     * gets the LiberoWachtl url from config
      *
      * @return string
-     * @throws \Exception Webscraper url not defined
+     * @throws \Exception LiberoWachtl url not defined
      */
-    protected function getWebScraperUrl()
+    protected function getLiberoWachtlUrl()
     {
-        if (!isset($this->config['LiberoDing']['webScraperUrl'])) {
-            throw new \Exception('no webscraper url defined');
+        if (!isset($this->liberoWachtlUrl)) {
+            if (!isset($this->config['LiberoWachtl']['liberoWachtlUrl'])) {
+                throw new \Exception('no LiberoWachtl url defined');
+            }
+            $this->liberoWachtlUrl = $this->config['LiberoWachtl']['liberoWachtlUrl'];
         }
 
-        return $this->config['LiberoDing']['webScraperUrl'];
+        return $this->liberoWachtlUrl;
     }
 
     /**
@@ -98,11 +106,11 @@ trait LiberoDingTrait
      */
     protected function getDbName()
     {
-        if (!isset($this->config['LiberoDing']['databaseName'])) {
+        if (!isset($this->config['LiberoWachtl']['databaseName'])) {
             throw new \Exception('no database name defined');
         }
 
-        return $this->config['LiberoDing']['databaseName'];
+        return $this->config['LiberoWachtl']['databaseName'];
     }
 
     /**
@@ -112,7 +120,7 @@ trait LiberoDingTrait
      * @return boolean    Returns true if a connection exists
      * @throws \Exception Throws ILSException
      */
-    public function checkLiberoDingConnection()
+    public function checkLiberoWachtlConnection()
     {
         $http_header['User-Agent']
             = 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)';
@@ -125,7 +133,7 @@ trait LiberoDingTrait
 
         try {
             $result = $this->httpService->post(
-                $this->getWebScraperUrl() .'liberoPing.jsp',
+                $this->getLiberoWachtlUrl() .'liberoPing.jsp',
                 http_build_query($params),
                 'application/json; charset=UTF-8',
                 null,
@@ -162,17 +170,17 @@ trait LiberoDingTrait
      */
     public function balanceFinesOfUser($patron, $amount)
     {
-        $params                 = $this->getLiberoDingRequestParams();
+        $params                 = $this->getLiberoWachtlRequestParams();
         $params['memberCode']   = $patron['cat_username'];
         $params['password']     = $patron['cat_password'];
         $params['amount']       = $amount;
 
         try {
             $result = $this->httpService->get(
-                $this->getWebScraperUrl() .'payAnyFee.jsp',
+                $this->getLiberoWachtlUrl() .'payAnyFee.jsp',
                 $params,
                 null,
-                $this->getLiberoDingRequestHeaders()
+                $this->getLiberoWachtlRequestHeaders()
             );
         } catch (\Exception $e) {
             throw new ILSException($e->getMessage());
@@ -189,7 +197,7 @@ trait LiberoDingTrait
         // reload PAIA session by paia login again
         $this->refreshLogin($patron['cat_username'], $patron['cat_password']);
 
-        return $this->getLiberoDingResultBool($result);
+        return $this->getLiberoWachtlResultBool($result);
     }
 
     /**
@@ -203,16 +211,16 @@ trait LiberoDingTrait
      */
     protected function getSystemMessages($patron)
     {
-        $params                 = $this->getLiberoDingRequestParams();
+        $params                 = $this->getLiberoWachtlRequestParams();
         $params['memberCode']   = $patron['cat_username'];
         $params['password']     = $patron['cat_password'];
 
         try {
             $result = $this->httpService->get(
-                $this->getWebScraperUrl() .'getMySystemMessages.jsp',
+                $this->getLiberoWachtlUrl() .'getMySystemMessages.jsp',
                 $params,
                 null,
-                $this->getLiberoDingRequestHeaders()
+                $this->getLiberoWachtlRequestHeaders()
             );
         } catch (\Exception $e) {
             throw new ILSException($e->getMessage());
@@ -227,7 +235,7 @@ trait LiberoDingTrait
             return false;
         }
 
-        return $this->getLiberoDingResult($result, 'getMySystemMessages');
+        return $this->getLiberoWachtlResult($result, 'getMySystemMessages');
     }
 
     /**
@@ -248,7 +256,7 @@ trait LiberoDingTrait
         $messageIdList = null,
         $toDate = null
     ) {
-        $params                 = $this->getLiberoDingRequestParams();
+        $params                 = $this->getLiberoWachtlRequestParams();
         $params['memberCode']   = $patron['cat_username'];
         $params['password']     = $patron['cat_password'];
 
@@ -261,10 +269,10 @@ trait LiberoDingTrait
 
         try {
             $result = $this->httpService->get(
-                $this->getWebScraperUrl() .'removeMySystemMessages.jsp',
+                $this->getLiberoWachtlUrl() .'removeMySystemMessages.jsp',
                 $params,
                 null,
-                $this->getLiberoDingRequestHeaders()
+                $this->getLiberoWachtlRequestHeaders()
             );
         } catch (\Exception $e) {
             throw new ILSException($e->getMessage());
@@ -279,7 +287,7 @@ trait LiberoDingTrait
             return false;
         }
 
-        return $this->getLiberoDingResult($result, 'removeMySystemMessages');
+        return $this->getLiberoWachtlResult($result, 'removeMySystemMessages');
     }
 
     /**
@@ -293,15 +301,15 @@ trait LiberoDingTrait
      */
     public function setLockMyAccount($patron)
     {
-        $params                 = $this->getLiberoDingRequestParams();
+        $params                 = $this->getLiberoWachtlRequestParams();
         $params['memberCode']   = $patron['cat_username'];
         $params['password']     = $patron['cat_password'];
         try {
             $result = $this->httpService->get(
-                $this->getWebScraperUrl() .'lockMyAccount.jsp',
+                $this->getLiberoWachtlUrl() .'lockMyAccount.jsp',
                 $params,
                 null,
-                $this->getLiberoDingRequestHeaders()
+                $this->getLiberoWachtlRequestHeaders()
             );
         } catch (\Exception $e) {
             throw new ILSException($e->getMessage());
@@ -315,7 +323,7 @@ trait LiberoDingTrait
             return false;
         }
         // Log error for debugging
-        if( true === ($bool = $this->getLiberoDingResultBool($result))) {
+        if( true === ($bool = $this->getLiberoWachtlResultBool($result))) {
             // Remove explicitly session vars of PAIA connection
             // Compliance security issue
             $session = $this->getSession();
@@ -357,7 +365,7 @@ trait LiberoDingTrait
     {
         $map = self::profileDataMapper(true);
 
-        $params                 = $this->getLiberoDingRequestParams();
+        $params                 = $this->getLiberoWachtlRequestParams();
         $params['memberCode']   = $patron['cat_username'];
         $params['password']     = $patron['cat_password'];
 
@@ -376,10 +384,10 @@ trait LiberoDingTrait
 
         try {
             $result = $this->httpService->get(
-                $this->getWebScraperUrl() .'setMyProfile.jsp',
+                $this->getLiberoWachtlUrl() .'setMyProfile.jsp',
                 $params,
                 null,
-                $this->getLiberoDingRequestHeaders()
+                $this->getLiberoWachtlRequestHeaders()
             );
         } catch (\Exception $e) {
             throw new ILSException($e->getMessage());
@@ -394,7 +402,7 @@ trait LiberoDingTrait
             return false;
         }
 
-        return $this->getLiberoDingResultBool($result);
+        return $this->getLiberoWachtlResultBool($result);
     }
 
     /**
@@ -404,8 +412,8 @@ trait LiberoDingTrait
      */
     public function getIgnoredProfileFields()
     {
-        return isset($this->config['LiberoDing']['ignoredProfileFields']) ?
-          $this->config['LiberoDing']['ignoredProfileFields'] : [];
+        return isset($this->config['LiberoWachtl']['ignoredProfileFields']) ?
+          $this->config['LiberoWachtl']['ignoredProfileFields'] : [];
     }
 
     /**
@@ -415,8 +423,8 @@ trait LiberoDingTrait
      */
     public function getRestrictedUserGroups()
     {
-        return isset($this->config['LiberoDing']['restrictedUserGroups']) ?
-            $this->config['LiberoDing']['restrictedUserGroups'] : [];
+        return isset($this->config['LiberoWachtl']['restrictedUserGroups']) ?
+            $this->config['LiberoWachtl']['restrictedUserGroups'] : [];
     }
 
     /**
@@ -427,12 +435,12 @@ trait LiberoDingTrait
      */
     public function getItemsPerViewLoanHistory()
     {
-        return isset($this->config['LiberoDing']['itemsPerPageLoanHistory']) ?
-            $this->config['LiberoDing']['itemsPerPageLoanHistory'] : 20;
+        return isset($this->config['LiberoWachtl']['itemsPerPageLoanHistory']) ?
+            $this->config['LiberoWachtl']['itemsPerPageLoanHistory'] : 20;
     }
 
     /**
-     * This method queries the LiberoDing-ILS for a patron's current profile
+     * This method queries the LiberoWachtl-ILS for a patron's current profile
      * information.
      *
      * @param array   $patron Patron array returned by patronLogin method.
@@ -443,18 +451,18 @@ trait LiberoDingTrait
      * @see For content variables see method profileDataMapper
      * @throws \Exception Throws ILSException
      */
-    protected function getLiberoDingProfile($patron, $mapped = true)
+    protected function getLiberoWachtlProfile($patron, $mapped = true)
     {
-        $params                 = $this->getLiberoDingRequestParams();
+        $params                 = $this->getLiberoWachtlRequestParams();
         $params['memberCode']   = $patron['cat_username'];
         $params['password']     = $patron['cat_password'];
 
         try {
             $result = $this->httpService->get(
-                $this->getWebScraperUrl() .'getMyProfile.jsp',
+                $this->getLiberoWachtlUrl() .'getMyProfile.jsp',
                 $params,
                 null,
-                $this->getLiberoDingRequestHeaders()
+                $this->getLiberoWachtlRequestHeaders()
             );
         } catch (\Exception $e) {
             throw new ILSException($e->getMessage());
@@ -473,7 +481,7 @@ trait LiberoDingTrait
             // define of disabled fields
             $mappeddata = [];
             $map = self::profileDataMapper();
-            $data = $this->getLiberoDingResult($result, 'getMyProfile');
+            $data = $this->getLiberoWachtlResult($result, 'getMyProfile');
 
             foreach ($data as $key => $value) {
                 if ($key == 'disabledInputs') {
@@ -492,12 +500,12 @@ trait LiberoDingTrait
             return $mappeddata;
         }
 
-        return $this->getLiberoDingResult($result, 'getMyProfile');
+        return $this->getLiberoWachtlResult($result, 'getMyProfile');
     }
 
 
     /**
-     * This method sends a PIN changing request to the LiberoDing.
+     * This method sends a PIN changing request to the LiberoWachtl.
      *
      * @param string  $newPin New pin.
      * @param array   $patron Patron array returned by patronLogin method.
@@ -507,17 +515,17 @@ trait LiberoDingTrait
      */
     public function changeUserPin($newPin, $patron)
     {
-        $params                 = $this->getLiberoDingRequestParams();
+        $params                 = $this->getLiberoWachtlRequestParams();
         $params['memberCode']   = $patron['cat_username'];
         $params['password']     = $patron['cat_password'];
         $params['newPin']       = $newPin;
 
         try {
             $result = $this->httpService->get(
-                $this->getWebScraperUrl() .'changeUserPin.jsp',
+                $this->getLiberoWachtlUrl() .'changeUserPin.jsp',
                 $params,
                 null,
-                $this->getLiberoDingRequestHeaders()
+                $this->getLiberoWachtlRequestHeaders()
             );
         } catch (\Exception $e) {
             throw new ILSException($e->getMessage());
@@ -532,7 +540,7 @@ trait LiberoDingTrait
             return false;
         }
 
-        return $this->getLiberoDingResult($result, 'changeUserPinOk');
+        return $this->getLiberoWachtlResult($result, 'changeUserPinOk');
     }
 
     /**
@@ -575,11 +583,11 @@ trait LiberoDingTrait
     }
 
     /**
-     * Private Helper function to return LiberoDing request parameters
+     * Private Helper function to return LiberoWachtl request parameters
      *
      * @return array
      */
-    private function getLiberoDingRequestParams()
+    private function getLiberoWachtlRequestParams()
     {
         return [
             'dbName'            => $this->getDbName(),
@@ -589,11 +597,11 @@ trait LiberoDingTrait
     }
 
     /**
-     * Private Helper function to return LiberoDing request headers
+     * Private Helper function to return LiberoWachtl request headers
      *
      * @return array
      */
-    private function getLiberoDingRequestHeaders()
+    private function getLiberoWachtlRequestHeaders()
     {
         return [
             'User-Agent' => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)'
@@ -609,7 +617,7 @@ trait LiberoDingTrait
      *
      * @return mixed
      */
-    private function getLiberoDingResult($result, $resultKey)
+    private function getLiberoWachtlResult($result, $resultKey)
     {
         // get result as array
         $details = json_decode($result->getBody(), true);
@@ -630,7 +638,7 @@ trait LiberoDingTrait
      * @return array
      * @access private
      */
-    private function getLiberoDingResultBool($result)
+    private function getLiberoWachtlResultBool($result)
     {
         // get result as array
         $details = json_decode($result->getBody(), true);
@@ -646,7 +654,7 @@ trait LiberoDingTrait
      * Customized getMyLoanHistory
      *
      * @param array $patron   Array returned from patronLogin()
-     * @param int   $lastLine Integer until LiberoDing should process history
+     * @param int   $lastLine Integer until LiberoWachtl should process history
      *                        incrementally
      *
      * @return array $retval
@@ -657,16 +665,16 @@ trait LiberoDingTrait
      */
     public function getMyLoanHistory($patron, $lastLine)
     {
-        $params = $this->getLiberoDingRequestParams();
+        $params = $this->getLiberoWachtlRequestParams();
         $params['memberCode'] = $patron['cat_username'];
         $params['password'] = $patron['cat_password'];
         $params['pageNumber'] = 1;
         try {
             $result = $this->httpService->get(
-                $this->getWebScraperUrl() . 'getMyLoanHistory.jsp',
+                $this->getLiberoWachtlUrl() . 'getMyLoanHistory.jsp',
                 $params,
                 null,
-                $this->getLiberoDingRequestHeaders()
+                $this->getLiberoWachtlRequestHeaders()
             );
         } catch (\Exception $e) {
             throw new ILSException($e->getMessage());
@@ -699,10 +707,10 @@ trait LiberoDingTrait
                 $params['pageNumber'] = $page;
                 try {
                     $result = $this->httpService->get(
-                        $this->getWebScraperUrl() . 'getMyLoanHistory.jsp',
+                        $this->getLiberoWachtlUrl() . 'getMyLoanHistory.jsp',
                         $params,
                         null,
-                        $this->getLiberoDingRequestHeaders()
+                        $this->getLiberoWachtlRequestHeaders()
                     );
                 } catch (\Exception $e) {
                     throw new ILSException($e->getMessage());
@@ -718,7 +726,7 @@ trait LiberoDingTrait
                 // merge with previous request
                 $retval['items'] = array_merge(
                     $retval['items'],
-                    $this->getLiberoDingResult($result, 'getMyLoanHistory')
+                    $this->getLiberoWachtlResult($result, 'getMyLoanHistory')
                 );
                 // If there are requested lines collected break the iteration
                 if (count($retval['items']) > $lastLine) {
@@ -726,10 +734,10 @@ trait LiberoDingTrait
                 }
             }
         }
-        // refs #11535 enable getDriverForILSRecord
-        foreach ($retval['items'] as &$current) {
-            $current['id'] =
-                $this->getAlternativeItemId($current['barcode'], "barcode");
+
+        $ids = $this->getAlternativeItemId(array_column($retval['items'], FincILS::ILS_IDENTIFIER_BARCODE), FincILS::ILS_IDENTIFIER_BARCODE);
+        foreach ($retval['items'] as $number => &$current) {
+            $current['id'] = $ids[$number] ?? false;
         }
         return $retval;
     }
@@ -748,16 +756,16 @@ trait LiberoDingTrait
      */
     public function getMyLoanHistoryItems($patron)
     {
-        $params = $this->getLiberoDingRequestParams();
+        $params = $this->getLiberoWachtlRequestParams();
         $params['memberCode'] = $patron['cat_username'];
         $params['password'] = $patron['cat_password'];
         $params['pageNumber'] = 1;
         try {
             $result = $this->httpService->get(
-                $this->getWebScraperUrl() . 'getMyLoanHistory.jsp',
+                $this->getLiberoWachtlUrl() . 'getMyLoanHistory.jsp',
                 $params,
                 null,
-                $this->getLiberoDingRequestHeaders()
+                $this->getLiberoWachtlRequestHeaders()
             );
         } catch (\Exception $e) {
             throw new ILSException($e->getMessage());
diff --git a/module/finc/src/finc/RecordDriver/SolrMarcFincTrait.php b/module/finc/src/finc/RecordDriver/SolrMarcFincTrait.php
index a81cf67cd39e26d782fa9c41e5af53dd1e920e36..c17bd5e99f6029bf368c46cdf01dccda9e2e53d8 100644
--- a/module/finc/src/finc/RecordDriver/SolrMarcFincTrait.php
+++ b/module/finc/src/finc/RecordDriver/SolrMarcFincTrait.php
@@ -28,6 +28,8 @@
  */
 namespace finc\RecordDriver;
 
+use File_MARC_Field;
+use finc\Controller\CustomTraits\SearchTrait as SearchTrait;
 use VuFindSearch\Query\Query as Query;
 
 /**
@@ -42,6 +44,8 @@ use VuFindSearch\Query\Query as Query;
  */
 trait SolrMarcFincTrait
 {
+    use SearchTrait;
+
     /**
      * Returns true if the record supports real-time AJAX status lookups.
      *
@@ -63,6 +67,39 @@ trait SolrMarcFincTrait
         return $this->getFirstFieldValue('040', ['e']) == 'rda';
     }
 
+    /**
+     * Helper function for getURLs()
+     * Decides which sub results from getURLs to choose.
+     * Standard version takes
+     * instance-specific URLs if present or choses LEFER over default otherwise
+     * 
+     * @param array $resultsPerIsil
+     * @return mixed|null
+     */
+    protected function extractUrls(array $resultsPerIsil)
+    {
+        $subresult = null;
+        // if we have a local entry for the current instance (i.e. ISIL)
+        // use that one
+        foreach ($this->isil as $isil) {
+            if (isset($resultsPerIsil[$isil])) {
+                $subresult = $resultsPerIsil[$isil];
+                break;
+            }
+        }
+        // LFER ("Lizenzfreie elektronische Ressourcen",
+        // "license free electronic resources") may have a designated entry,
+        // if there is no instance specific url try the one for LFER
+        if (empty($subresult) && isset($resultsPerIsil['LFER'])) {
+            $subresult = $resultsPerIsil['LFER'];
+        }
+        // if we still have no URL, look for the unspecific entry
+        if (empty($subresult) && isset($resultsPerIsil['default'])) {
+            $subresult = $resultsPerIsil['default'];
+        }
+        return $subresult;
+    }
+
     /**
      * Return an array of associative URL arrays with one or more of the following
      * keys:
@@ -150,25 +187,8 @@ trait SolrMarcFincTrait
                     }
                 }
             }
-            $subresult = null;
-            // if we have a local entry for the current instance (i.e. ISIL)
-            // use that one
-            foreach ($this->isil as $isil) {
-                if (isset($resultsPerIsil[$isil])) {
-                    $subresult = $resultsPerIsil[$isil];
-                    break;
-                }
-            }
-            // LFER ("Lizenzfreie elektronische Ressourcen",
-            // "license free electronic resources") may have a designated entry,
-            // if there is no instance specific url try the one for LFER
-            if (empty($subresult) && isset($resultsPerIsil['LFER'])) {
-                $subresult = $resultsPerIsil['LFER'];
-            }
-            // if we still have no URL, look for the unspecific entry
-            if (empty($subresult) && isset($resultsPerIsil['default'])) {
-                $subresult = $resultsPerIsil['default'];
-            }
+
+            $subresult = $this->extractUrls($resultsPerIsil);
 
             if (!empty($subresult)) {
                 foreach ($subresult as $current) {
@@ -1731,7 +1751,7 @@ trait SolrMarcFincTrait
                  ] as $source) {
             $return = [];
             foreach ($retval as $entry) {
-                if (isset($entry['source']) && strpos($entry['source'],$source) !== false) {
+                if (isset($entry['source']) && strpos($entry['source'], $source) !== false) {
                     $return[] = $entry;
                 }
             }
@@ -1772,7 +1792,7 @@ trait SolrMarcFincTrait
                 return array_map(
                     'unserialize',
                     array_unique(
-                        array_map('serialize',$retval[$thesaurus])
+                        array_map('serialize', $retval[$thesaurus])
                     )
                 );
             }
@@ -2034,37 +2054,22 @@ trait SolrMarcFincTrait
         }
     }
 
-    public function searchRelatedRecords($field, $values, $limit = 20,
-        $filters = [], $backend_id = 'Solr'
-    ) {
-
-        if (!empty($filters)) {
-            $fq = '';
-            foreach ($filters as $filterField => $value) {
-                $fq = (empty($fq) ? '' : ' AND ')
-                    . "$filterField:$value";
-            }
-        }
-
-        $query = new Query(
-            $field . ':(' . implode(' OR ', $values)
-            . ') AND NOT id:' . $this->getUniqueID()
-            . (isset($fq) ? " AND $fq" : '')
-        );
-
-        $result = $this->searchService->search($backend_id, $query, 0, $limit);
-        $return['first_results'] = $result->getRecords();
-
-        if (isset($limit) && $result->getTotal() > $limit) {
-            $return['more_query'] = $query->getString();
-        }
-        return $return;
-
-    }
-
+    /**
+     * Finds related records from the K10plus source. Relations are specified in
+     * a specified subfield of applicable fields (standard |w)
+     *
+     * @param File_MARC_Field   $line           MARC field entry with relation
+     *                                          information
+     * @param int               $limit          number of records to return as
+     *                                          direct results, if there are more,
+     *                                          a search link will be provided
+     * @param string            $linkSubField   name of the subfield that contains
+     *                                          relation info
+     * @return array|mixed|null
+     */
     public function getRelatedKxpRecord($line, $limit = 1, $linkSubField = 'w') {
 
-        if ($linkFields = $line->getSubfields('w')) {
+        if ($linkFields = $line->getSubfields($linkSubField)) {
             $linked = [];
             foreach ($linkFields as $current) {
                 $text = $current->getData();
diff --git a/module/finc/src/finc/RecordDriver/SolrMarcUrlRulesDelegatorFactory.php b/module/finc/src/finc/RecordDriver/SolrMarcUrlRulesDelegatorFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..7160540c640834bc211dcb014672dc24b6bbc2d2
--- /dev/null
+++ b/module/finc/src/finc/RecordDriver/SolrMarcUrlRulesDelegatorFactory.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Delegator Factory for SolrMarc record drivers. Enables specialized rules
+ * for \finc\RecordDriver\SolrMarcFincTrait::getURLs
+ *
+ * PHP version 7
+ *
+ * Copyright (C) Villanova University 2021.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  RecordDrivers
+ * @author   Dorian Merz <mer@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development Wiki
+ */
+namespace finc\RecordDriver;
+
+use Interop\Container\ContainerInterface;
+
+/**
+ * Delegator Factory for SolrMarc record drivers. Enables specialized rules
+ * for \finc\RecordDriver\SolrMarcFincTrait::getURLs
+ *
+ * @category VuFind
+ * @package  RecordDrivers
+ * @author   Dorian Merz <mer@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development Wiki
+ */
+class SolrMarcUrlRulesDelegatorFactory
+{
+    /**
+     * Creates a delegator of VuFind/Search to register several listeners.
+     *
+     * @param ContainerInterface $container
+     * @param string $name
+     * @param callable $callback
+     * @param array|null $options
+     *
+     * @return mixed
+     */
+    public function __invoke(
+        ContainerInterface $container,
+        $name,
+        callable $callback,
+        array $options = null
+    ) {
+        $instance = call_user_func($callback);
+
+        $urlRules = $container->get('VuFind\YamlReader')->get('SolrMarcUrlRules.yaml');
+        if (!empty($urlRules)) {
+            if (isset($urlRules['rules']) && isset($urlRules['stopFlags'])) {
+                $instance->urlRules = $urlRules;
+            }
+        }
+
+        return $instance;
+    }
+}
diff --git a/module/finc/src/finc/Service/LuceneSyntaxHelperOverride.php b/module/finc/src/finc/Service/LuceneSyntaxHelperOverride.php
new file mode 100644
index 0000000000000000000000000000000000000000..0629e85c8cf240640ce84b2b5f5ef3dde0416e69
--- /dev/null
+++ b/module/finc/src/finc/Service/LuceneSyntaxHelperOverride.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * LuceneSyntaxHelper Override
+ *
+ * A Delegator Factory that registers several listeners at events triggered by the
+ * VuFind\Search service.
+ *
+ * PHP version 7
+ *
+ * Copyright (C) Leipzig University Library 2021.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Finc/Service
+ * @author   Dorian Merz <merz@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org Main Page
+ */
+namespace finc\Service;
+
+/**
+ * LuceneSyntaxHelper Override
+ *
+ * @category VuFind
+ * @package  Finc/Service
+ * @author   Dorian Merz <merz@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org Main Page
+ */
+class LuceneSyntaxHelperOverride extends \VuFindSearch\Backend\Solr\LuceneSyntaxHelper
+{
+    public function __construct(\VuFindSearch\Backend\Solr\LuceneSyntaxHelper $parentHelper)
+    {
+        parent::__construct(
+            $parentHelper->caseSensitiveBooleans,
+            $parentHelper->caseSensitiveRanges
+        );
+    }
+
+    /**
+     * {@inheritDoc}
+     * overridden to avoid query rebuilding
+     *
+     * @param string $searchString
+     * @return false
+     */
+    public function containsAdvancedLuceneSyntax($searchString)
+    {
+        return false;
+    }
+}
diff --git a/module/finc/src/finc/Service/MungerInjectionDelegatorFactory.php b/module/finc/src/finc/Service/MungerInjectionDelegatorFactory.php
index 9bc29e20a830a8464dd35d3ca4f6f96f97e3d59c..a7e35943f00dcb5a95f4e1dcfb49fb93c9599912 100644
--- a/module/finc/src/finc/Service/MungerInjectionDelegatorFactory.php
+++ b/module/finc/src/finc/Service/MungerInjectionDelegatorFactory.php
@@ -65,6 +65,11 @@ class MungerInjectionDelegatorFactory implements DelegatorFactoryInterface
      */
     protected $shards_to_register;
 
+    /**
+     * @var array search types to be excluded from lucene query syntax detection
+     */
+    protected $override_advanced_lucene_detection;
+
     /**
      * Creates a delegator of VuFind/Search to register several listeners.
      *
@@ -106,6 +111,12 @@ class MungerInjectionDelegatorFactory implements DelegatorFactoryInterface
             $this->shards_to_register = $shards;
             $e->attach('VuFindSearch', 'pre', [$this, 'registerShards']);
         }
+        if (isset($searchConfig->General->override_advanced_lucene_detection)) {
+            $this->override_advanced_lucene_detection = array_flip($searchConfig->General->override_advanced_lucene_detection->toArray());
+            if (!empty($this->override_advanced_lucene_detection)) {
+                $e->attach('VuFindSearch', 'pre', [$this, 'overrideLuceneSyntaxHelper']);
+            }
+        }
         return $instance;
     }
 
@@ -180,4 +191,48 @@ class MungerInjectionDelegatorFactory implements DelegatorFactoryInterface
             $params->set('shards', implode(',', $this->shards_to_register));
         }
     }
+
+    public function overrideLuceneSyntaxHelper(EventInterface $event)
+    {
+        $params = $event->getParams();
+        if (
+            $params['context'] == 'search'
+            && isset($params['query'])
+            && $this->isLuceneReducible($params['query'])
+        ) {
+            $builder = $event->getTarget()->getQueryBuilder();
+            $currentHelper = $builder->getLuceneHelper();
+            $newHelper = new LuceneSyntaxHelperOverride($currentHelper);
+            $builder->setLuceneHelper($newHelper);
+        }
+    }
+
+
+    /**
+     * Escapes colons in Queries or recursively in QueryGroups.
+     * This prevents queries from being interpreted as advanced queries in Lucene syntax.
+     * cf. \VuFindSearch\Backend\Solr\LuceneSyntaxHelper::containsAdvancedLuceneSyntax
+     *
+     * @param Query|QueryGroup $queryOrGroup
+     *
+     * @return mixed
+     */
+    private function isLuceneReducible($queryOrGroup)
+    {
+        if ($queryOrGroup instanceof QueryGroup) {
+            $handler = $queryOrGroup->getReducedHandler();
+            if (is_null($handler) || isset($this->override_advanced_lucene_detection[$handler])) {
+                foreach ($queryOrGroup->getQueries() as $query) {
+                    // cycle through all recursive subqueries, if any of these matches
+                    // the whole query should not be checked for lucene syntax
+                    if ($this->isLuceneReducible($query)) {
+                        return true;
+                    }
+                }
+            }
+        } elseif (isset($this->override_advanced_lucene_detection[$queryOrGroup->getHandler()])) {
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/themes/finc-accessibility/js/vendor/bootstrap-accessibility-de.min.js b/themes/finc-accessibility/js/vendor/bootstrap-accessibility-de.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..e10770a83219ba52528d475215ee4a0c8b96d175
--- /dev/null
+++ b/themes/finc-accessibility/js/vendor/bootstrap-accessibility-de.min.js
@@ -0,0 +1,4 @@
+/*! bootstrap-accessibility-plugin - v1.0.6 - 2020-05-07
+* https://github.com/paypal/bootstrap-accessibility-plugin
+* Copyright (c) 2020 PayPal Accessibility Team; Licensed BSD */
+!function($){"use strict";var uniqueId=function(prefix){return(prefix||"ui-id")+"-"+Math.floor(1e3*Math.random()+1)},focusable=function(element,isTabIndexNotNaN){var map,mapName,img,nodeName=element.nodeName.toLowerCase();return"area"===nodeName?(map=element.parentNode,mapName=map.name,element.href&&mapName&&"map"===map.nodeName.toLowerCase()?(img=$("img[usemap='#"+mapName+"']")[0],!!img&&visible(img)):!1):(/input|select|textarea|button|object/.test(nodeName)?!element.disabled:"a"===nodeName?element.href||isTabIndexNotNaN:isTabIndexNotNaN)&&visible(element)},visible=function(element){return $.expr.filters.visible(element)&&!$(element).parents().addBack().filter(function(){return"hidden"===$.css(this,"visibility")}).length};$.extend($.expr[":"],{data:$.expr.createPseudo?$.expr.createPseudo(function(dataName){return function(elem){return!!$.data(elem,dataName)}}):function(elem,i,match){return!!$.data(elem,match[3])},focusable:function(element){return focusable(element,!isNaN($.attr(element,"tabindex")))},tabbable:function(element){var tabIndex=$.attr(element,"tabindex"),isTabIndexNaN=isNaN(tabIndex);return(isTabIndexNaN||tabIndex>=0)&&focusable(element,!isTabIndexNaN)}}),$(".modal-dialog").attr({role:"document"});var modalhide=$.fn.modal.Constructor.prototype.hide;$.fn.modal.Constructor.prototype.hide=function(){modalhide.apply(this,arguments),$(document).off("keydown.bs.modal")};var modalfocus=$.fn.modal.Constructor.prototype.enforceFocus;$.fn.modal.Constructor.prototype.enforceFocus=function(){var $content=this.$element.find(".modal-content"),focEls=$content.find(":tabbable"),$lastEl=$(focEls[focEls.length-1]),$firstEl=$(focEls[0]);$lastEl.on("keydown.bs.modal",$.proxy(function(ev){9!==ev.keyCode||ev.shiftKey|ev.ctrlKey|ev.metaKey|ev.altKey||(ev.preventDefault(),$firstEl.focus())},this)),$firstEl.on("keydown.bs.modal",$.proxy(function(ev){9===ev.keyCode&&ev.shiftKey&&(ev.preventDefault(),$lastEl.focus())},this)),modalfocus.apply(this,arguments)};var $par,firstItem,toggle="[data-toggle=dropdown]",focusDelay=200,menus=$(toggle).parent().find("ul").attr("role","menu"),lis=menus.find("li").attr("role","presentation");lis.find("a").attr({role:"menuitem",tabIndex:"-1"}),$(toggle).attr({"aria-haspopup":"true","aria-expanded":"false"}),$(toggle).parent().on("shown.bs.dropdown",function(e){$par=$(this);var $toggle=$par.find(toggle);$toggle.attr("aria-expanded","true"),$toggle.on("keydown.bs.dropdown",$.proxy(function(ev){setTimeout(function(){firstItem=$(".dropdown-menu [role=menuitem]:visible",$par)[0];try{firstItem.focus()}catch(ex){}},focusDelay)},this))}).on("hidden.bs.dropdown",function(e){$par=$(this);var $toggle=$par.find(toggle);$toggle.attr("aria-expanded","false")}),$(document).on("focusout.dropdown.data-api",".dropdown-menu",function(e){var $this=$(this),that=this;$this.parent().hasClass("open")&&setTimeout(function(){$.contains(that,document.activeElement)||$this.parent().find("[data-toggle=dropdown]").dropdown("toggle")},150)}).on("keydown.bs.dropdown.data-api",toggle+", [role=menu]",$.fn.dropdown.Constructor.prototype.keydown);var $tablist=$(".nav-tabs, .nav-pills"),$lis=$tablist.children("li"),$tabs=$tablist.find('[data-toggle="tab"], [data-toggle="pill"]');$tabs&&($tablist.attr("role","tablist"),$lis.attr("role","presentation"),$tabs.attr("role","tab")),$tabs.each(function(index){var tabpanel=$($(this).attr("href")),tab=$(this),tabid=tab.attr("id")||uniqueId("ui-tab");tab.attr("id",tabid),tab.parent().hasClass("active")?(tab.attr({tabIndex:"0","aria-selected":"true","aria-controls":tab.attr("href").substr(1)}),tabpanel.attr({role:"tabpanel",tabIndex:"0","aria-hidden":"false","aria-labelledby":tabid})):(tab.attr({tabIndex:"-1","aria-selected":"false","aria-controls":tab.attr("href").substr(1)}),tabpanel.attr({role:"tabpanel",tabIndex:"-1","aria-hidden":"true","aria-labelledby":tabid}))}),$.fn.tab.Constructor.prototype.keydown=function(e){var $items,index,$this=$(this),$ul=$this.closest("ul[role=tablist] "),k=e.which||e.keyCode;if($this=$(this),/(37|38|39|40)/.test(k)){$items=$ul.find("[role=tab]:visible"),index=$items.index($items.filter(":focus")),(38==k||37==k)&&index--,(39==k||40==k)&&index++,0>index&&(index=$items.length-1),index==$items.length&&(index=0);var nextTab=$items.eq(index);"tab"===nextTab.attr("role")&&nextTab.tab("show").focus(),e.preventDefault(),e.stopPropagation()}},$(document).on("keydown.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',$.fn.tab.Constructor.prototype.keydown);var tabactivate=$.fn.tab.Constructor.prototype.activate;$.fn.tab.Constructor.prototype.activate=function(element,container,callback){var $active=container.find("> .active");$active.find("[data-toggle=tab], [data-toggle=pill]").attr({tabIndex:"-1","aria-selected":!1}),$active.filter(".tab-pane").attr({"aria-hidden":!0,tabIndex:"-1"}),tabactivate.apply(this,arguments),element.addClass("active"),element.find("[data-toggle=tab], [data-toggle=pill]").attr({tabIndex:"0","aria-selected":!0}),element.filter(".tab-pane").attr({"aria-hidden":!1,tabIndex:"0"})};var $colltabs=$('[data-toggle="collapse"]');$colltabs.each(function(index){var colltab=$(this),collpanel=$(colltab.attr("data-target")?colltab.attr("data-target"):colltab.attr("href")),parent=colltab.attr("data-parent"),collparent=parent&&$(parent),collid=colltab.attr("id")||uniqueId("ui-collapse"),parentpanel=collpanel.parent(),parentfirstchild=collparent?collparent.find(".panel.panel-default:first-child"):null,hasopenpanel=collparent?collparent.find(".panel-collapse.in").length>0:!1;colltab.attr("id",collid),collparent&&(colltab.attr({"aria-controls":collpanel.attr("id"),role:"tab","aria-selected":"false","aria-expanded":"false"}),$(collparent).find("div:not(.collapse,.panel-body), h4").attr("role","presentation"),collparent.attr({role:"tablist","aria-multiselectable":"true"}),collpanel.attr({role:"tabpanel","aria-labelledby":collid}),!hasopenpanel&&parentpanel.is(parentfirstchild)?(colltab.attr({tabindex:"0"}),collpanel.attr({tabindex:"-1"})):collpanel.hasClass("in")?(colltab.attr({"aria-selected":"true","aria-expanded":"true",tabindex:"0"}),collpanel.attr({tabindex:"0","aria-hidden":"false"})):(colltab.attr({tabindex:"-1"}),collpanel.attr({tabindex:"-1","aria-hidden":"true"})))});var collToggle=$.fn.collapse.Constructor.prototype.toggle;$.fn.collapse.Constructor.prototype.toggle=function(){var href,prevTab=this.$parent&&this.$parent.find('[aria-expanded="true"]');if(prevTab){var curTab,prevPanel=prevTab.attr("data-target")||(href=prevTab.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,""),$prevPanel=$(prevPanel),$curPanel=this.$element;this.$parent;this.$parent&&(curTab=this.$parent.find('[data-toggle=collapse][href="#'+this.$element.attr("id")+'"]')),collToggle.apply(this,arguments),$.support.transition&&this.$element.one($.support.transition.end,function(){prevTab.attr({"aria-selected":"false","aria-expanded":"false",tabIndex:"-1"}),$prevPanel.attr({"aria-hidden":"true",tabIndex:"-1"}),curTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:"0"}),$curPanel.hasClass("in")?$curPanel.attr({"aria-hidden":"false",tabIndex:"0"}):(curTab.attr({"aria-selected":"false","aria-expanded":"false"}),$curPanel.attr({"aria-hidden":"true",tabIndex:"-1"}))})}else collToggle.apply(this,arguments)},$.fn.collapse.Constructor.prototype.keydown=function(e){var $items,index,$this=$(this),$tablist=$this.closest("div[role=tablist] "),k=e.which||e.keyCode;$this=$(this),/(32|37|38|39|40)/.test(k)&&(32==k&&$this.click(),$items=$tablist.find("[role=tab]"),index=$items.index($items.filter(":focus")),(38==k||37==k)&&index--,(39==k||40==k)&&index++,0>index&&(index=$items.length-1),index==$items.length&&(index=0),$items.eq(index).focus(),e.preventDefault(),e.stopPropagation())},$(document).on("keydown.collapse.data-api",'[data-toggle="collapse"]',$.fn.collapse.Constructor.prototype.keydown),$(".carousel").each(function(index){function setTablistHighlightBox(){var $tab,offset,height,width,highlightBox={};highlightBox.top=0,highlightBox.left=32e3,highlightBox.height=0,highlightBox.width=0;for(var i=0;i<$tabs.length;i++){$tab=$tabs[i],offset=$($tab).offset(),height=$($tab).height(),width=$($tab).width(),highlightBox.top<offset.top&&(highlightBox.top=Math.round(offset.top)),highlightBox.height<height&&(highlightBox.height=Math.round(height)),highlightBox.left>offset.left&&(highlightBox.left=Math.round(offset.left));var w=offset.left-highlightBox.left+Math.round(width);highlightBox.width<w&&(highlightBox.width=w)}$tablistHighlight.style.top=highlightBox.top-2+"px",$tablistHighlight.style.left=highlightBox.left-2+"px",$tablistHighlight.style.height=highlightBox.height+7+"px",$tablistHighlight.style.width=highlightBox.width+8+"px"}var $tabpanel,$tablistHighlight,$pauseCarousel,$complementaryLandmark,$tab,i,$this=$(this),$prev=$this.find('[data-slide="prev"]'),$next=$this.find('[data-slide="next"]'),$tablist=$this.find(".carousel-indicators"),$tabs=$this.find(".carousel-indicators li"),$tabpanels=$this.find(".item"),$is_paused=!1,id_title="id_title",id_desc="id_desc";for($tablist.attr("role","tablist"),$tabs.focus(function(){$this.carousel("pause"),$is_paused=!0,$pauseCarousel.innerHTML="Bilderkarussel starten",$(this).parent().addClass("active"),setTablistHighlightBox(),$($tablistHighlight).addClass("focus"),$(this).parents(".carousel").addClass("contrast")}),$tabs.blur(function(event){$(this).parent().removeClass("active"),$($tablistHighlight).removeClass("focus"),$(this).parents(".carousel").removeClass("contrast")}),i=0;i<$tabpanels.length;i++)$tabpanel=$tabpanels[i],$tabpanel.setAttribute("role","tabpanel"),$tabpanel.setAttribute("id","tabpanel-"+index+"-"+i),$tabpanel.setAttribute("aria-labelledby","tab-"+index+"-"+i);for("string"!=typeof $this.attr("role")&&($this.attr("role","complementary"),$this.attr("aria-labelledby",id_title),$this.attr("aria-describedby",id_desc),$this.prepend('<p  id="'+id_desc+'" class="sr-only">Dieser Bilderkarussell können Sie über Tastatur oder Maus steuern. Mit den Tabs bzw. den Vorher- und Nachher-Schaltflächen können Sie zwischen den Bildern wechseln.</p>'),$this.prepend('<h2 id="'+id_title+'" class="sr-only">Bilderkarussel mit '+$tabpanels.length+" Bildern.</h2>")),i=0;i<$tabs.length;i++){$tab=$tabs[i],$tab.setAttribute("role","tab"),$tab.setAttribute("id","tab-"+index+"-"+i),$tab.setAttribute("aria-controls","tabpanel-"+index+"-"+i);var tpId="#tabpanel-"+index+"-"+i,caption=$this.find(tpId).find("h1").text();("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).text()),("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).find("h3").text()),("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).find("h4").text()),("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).find("h5").text()),("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).find("h6").text()),("string"!=typeof caption||0===caption.length)&&(caption="no title");var tabName=document.createElement("span");tabName.setAttribute("class","sr-only"),tabName.innerHTML="Slide "+(i+1),caption&&(tabName.innerHTML+=": "+caption),$tab.appendChild(tabName)}$tablistHighlight=document.createElement("div"),$tablistHighlight.className="carousel-tablist-highlight",document.body.appendChild($tablistHighlight),$complementaryLandmark=document.createElement("aside"),$complementaryLandmark.setAttribute("class","carousel-aside-pause"),$complementaryLandmark.setAttribute("aria-label","Stopp- und Startsteuerung für Bildkarussel"),$this.prepend($complementaryLandmark),$pauseCarousel=document.createElement("button"),$pauseCarousel.className="carousel-pause-button",$pauseCarousel.innerHTML="Bilderkarussel stoppen",$pauseCarousel.setAttribute("title","Sie können diese Schaltfläche nutzen, um die Karussellanimationen zu stoppen."),$($complementaryLandmark).append($pauseCarousel),$($pauseCarousel).click(function(){$is_paused?($pauseCarousel.innerHTML="Karussel anhalten",$this.carousel("cycle"),$is_paused=!1):($pauseCarousel.innerHTML="Bilderkarussel starten",$this.carousel("pause"),$is_paused=!0)}),$($pauseCarousel).focus(function(){$(this).addClass("focus")}),$($pauseCarousel).blur(function(){$(this).removeClass("focus")}),setTablistHighlightBox(),$(window).resize(function(){setTablistHighlightBox()}),$prev.attr("aria-label","Vorheriges Bild"),$prev.keydown(function(e){var k=e.which||e.keyCode;/(13|32)/.test(k)&&(e.preventDefault(),e.stopPropagation(),$prev.trigger("click"))}),$prev.focus(function(){$(this).parents(".carousel").addClass("contrast")}),$prev.blur(function(){$(this).parents(".carousel").removeClass("contrast")}),$next.attr("aria-label","Nächstes Bild"),$next.keydown(function(e){var k=e.which||e.keyCode;/(13|32)/.test(k)&&(e.preventDefault(),e.stopPropagation(),$next.trigger("click"))}),$next.focus(function(){$(this).parents(".carousel").addClass("contrast")}),$next.blur(function(){$(this).parents(".carousel").removeClass("contrast")}),$(".carousel-inner a").focus(function(){$(this).parents(".carousel").addClass("contrast")}),$(".carousel-inner a").blur(function(){$(this).parents(".carousel").removeClass("contrast")}),$tabs.each(function(){var item=$(this);item.hasClass("active")?item.attr({"aria-selected":"true",tabindex:"0"}):item.attr({"aria-selected":"false",tabindex:"-1"})})});var slideCarousel=$.fn.carousel.Constructor.prototype.slide;$.fn.carousel.Constructor.prototype.slide=function(type,next){var $id,$element=this.$element,$active=$element.find("[role=tabpanel].active"),$next=next||$active[type](),$tab_count=$element.find("[role=tabpanel]").length,$prev_side=$element.find('[data-slide="prev"]'),$next_side=$element.find('[data-slide="next"]'),$index=0,$prev_index=$tab_count-1,$next_index=1;$next&&$next.attr("id")&&($id=$next.attr("id"),$index=$id.lastIndexOf("-"),$index>=0&&($index=parseInt($id.substring($index+1),10)),$prev_index=$index-1,1>$prev_index&&($prev_index=$tab_count-1),$next_index=$index+1,$next_index>=$tab_count&&($next_index=0)),$prev_side.attr("aria-label","Zeige Bild "+($prev_index+1)+" von "+$tab_count),$next_side.attr("aria-label","Zeige Bild "+($next_index+1)+" von "+$tab_count),slideCarousel.apply(this,arguments),$active.one("bsTransitionEnd",function(){var $tab;$tab=$element.find('li[aria-controls="'+$active.attr("id")+'"]'),$tab&&$tab.attr({"aria-selected":!1,tabIndex:"-1"}),$tab=$element.find('li[aria-controls="'+$next.attr("id")+'"]'),$tab&&$tab.attr({"aria-selected":!0,tabIndex:"0"})})};var $this;$.fn.carousel.Constructor.prototype.keydown=function(e){function selectTab(index){index>=$tabs.length||0>index||($carousel.carousel(index),setTimeout(function(){$tabs[index].focus()},150))}$this=$this||$(this),this instanceof Node&&($this=$(this));var index,$carousel=$(e.target).closest(".carousel"),$tabs=$carousel.find("[role=tab]"),k=e.which||e.keyCode;/(37|38|39|40)/.test(k)&&(index=$tabs.index($tabs.filter(".active")),(37==k||38==k)&&(index--,selectTab(index)),(39==k||40==k)&&(index++,selectTab(index)),e.preventDefault(),e.stopPropagation())},$(document).on("keydown.carousel.data-api","li[role=tab]",$.fn.carousel.Constructor.prototype.keydown)}(jQuery);
\ No newline at end of file
diff --git a/themes/finc-accessibility/js/vendor/bootstrap-accessibility-en.min.js b/themes/finc-accessibility/js/vendor/bootstrap-accessibility-en.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..423c963b4fd7b5fe345689b89a3c94233085d8e4
--- /dev/null
+++ b/themes/finc-accessibility/js/vendor/bootstrap-accessibility-en.min.js
@@ -0,0 +1,4 @@
+/*! bootstrap-accessibility-plugin - v1.0.6 - 2020-05-07
+* https://github.com/paypal/bootstrap-accessibility-plugin
+* Copyright (c) 2020 PayPal Accessibility Team; Licensed BSD */
+!function($){"use strict";console.log('en');var uniqueId=function(prefix){return(prefix||"ui-id")+"-"+Math.floor(1e3*Math.random()+1)},focusable=function(element,isTabIndexNotNaN){var map,mapName,img,nodeName=element.nodeName.toLowerCase();return"area"===nodeName?(map=element.parentNode,mapName=map.name,element.href&&mapName&&"map"===map.nodeName.toLowerCase()?(img=$("img[usemap='#"+mapName+"']")[0],!!img&&visible(img)):!1):(/input|select|textarea|button|object/.test(nodeName)?!element.disabled:"a"===nodeName?element.href||isTabIndexNotNaN:isTabIndexNotNaN)&&visible(element)},visible=function(element){return $.expr.filters.visible(element)&&!$(element).parents().addBack().filter(function(){return"hidden"===$.css(this,"visibility")}).length};$.extend($.expr[":"],{data:$.expr.createPseudo?$.expr.createPseudo(function(dataName){return function(elem){return!!$.data(elem,dataName)}}):function(elem,i,match){return!!$.data(elem,match[3])},focusable:function(element){return focusable(element,!isNaN($.attr(element,"tabindex")))},tabbable:function(element){var tabIndex=$.attr(element,"tabindex"),isTabIndexNaN=isNaN(tabIndex);return(isTabIndexNaN||tabIndex>=0)&&focusable(element,!isTabIndexNaN)}}),$(".modal-dialog").attr({role:"document"});var modalhide=$.fn.modal.Constructor.prototype.hide;$.fn.modal.Constructor.prototype.hide=function(){modalhide.apply(this,arguments),$(document).off("keydown.bs.modal")};var modalfocus=$.fn.modal.Constructor.prototype.enforceFocus;$.fn.modal.Constructor.prototype.enforceFocus=function(){var $content=this.$element.find(".modal-content"),focEls=$content.find(":tabbable"),$lastEl=$(focEls[focEls.length-1]),$firstEl=$(focEls[0]);$lastEl.on("keydown.bs.modal",$.proxy(function(ev){9!==ev.keyCode||ev.shiftKey|ev.ctrlKey|ev.metaKey|ev.altKey||(ev.preventDefault(),$firstEl.focus())},this)),$firstEl.on("keydown.bs.modal",$.proxy(function(ev){9===ev.keyCode&&ev.shiftKey&&(ev.preventDefault(),$lastEl.focus())},this)),modalfocus.apply(this,arguments)};var $par,firstItem,toggle="[data-toggle=dropdown]",focusDelay=200,menus=$(toggle).parent().find("ul").attr("role","menu"),lis=menus.find("li").attr("role","presentation");lis.find("a").attr({role:"menuitem",tabIndex:"-1"}),$(toggle).attr({"aria-haspopup":"true","aria-expanded":"false"}),$(toggle).parent().on("shown.bs.dropdown",function(e){$par=$(this);var $toggle=$par.find(toggle);$toggle.attr("aria-expanded","true"),$toggle.on("keydown.bs.dropdown",$.proxy(function(ev){setTimeout(function(){firstItem=$(".dropdown-menu [role=menuitem]:visible",$par)[0];try{firstItem.focus()}catch(ex){}},focusDelay)},this))}).on("hidden.bs.dropdown",function(e){$par=$(this);var $toggle=$par.find(toggle);$toggle.attr("aria-expanded","false")}),$(document).on("focusout.dropdown.data-api",".dropdown-menu",function(e){var $this=$(this),that=this;$this.parent().hasClass("open")&&setTimeout(function(){$.contains(that,document.activeElement)||$this.parent().find("[data-toggle=dropdown]").dropdown("toggle")},150)}).on("keydown.bs.dropdown.data-api",toggle+", [role=menu]",$.fn.dropdown.Constructor.prototype.keydown);var $tablist=$(".nav-tabs, .nav-pills"),$lis=$tablist.children("li"),$tabs=$tablist.find('[data-toggle="tab"], [data-toggle="pill"]');$tabs&&($tablist.attr("role","tablist"),$lis.attr("role","presentation"),$tabs.attr("role","tab")),$tabs.each(function(index){var tabpanel=$($(this).attr("href")),tab=$(this),tabid=tab.attr("id")||uniqueId("ui-tab");tab.attr("id",tabid),tab.parent().hasClass("active")?(tab.attr({tabIndex:"0","aria-selected":"true","aria-controls":tab.attr("href").substr(1)}),tabpanel.attr({role:"tabpanel",tabIndex:"0","aria-hidden":"false","aria-labelledby":tabid})):(tab.attr({tabIndex:"-1","aria-selected":"false","aria-controls":tab.attr("href").substr(1)}),tabpanel.attr({role:"tabpanel",tabIndex:"-1","aria-hidden":"true","aria-labelledby":tabid}))}),$.fn.tab.Constructor.prototype.keydown=function(e){var $items,index,$this=$(this),$ul=$this.closest("ul[role=tablist] "),k=e.which||e.keyCode;if($this=$(this),/(37|38|39|40)/.test(k)){$items=$ul.find("[role=tab]:visible"),index=$items.index($items.filter(":focus")),(38==k||37==k)&&index--,(39==k||40==k)&&index++,0>index&&(index=$items.length-1),index==$items.length&&(index=0);var nextTab=$items.eq(index);"tab"===nextTab.attr("role")&&nextTab.tab("show").focus(),e.preventDefault(),e.stopPropagation()}},$(document).on("keydown.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',$.fn.tab.Constructor.prototype.keydown);var tabactivate=$.fn.tab.Constructor.prototype.activate;$.fn.tab.Constructor.prototype.activate=function(element,container,callback){var $active=container.find("> .active");$active.find("[data-toggle=tab], [data-toggle=pill]").attr({tabIndex:"-1","aria-selected":!1}),$active.filter(".tab-pane").attr({"aria-hidden":!0,tabIndex:"-1"}),tabactivate.apply(this,arguments),element.addClass("active"),element.find("[data-toggle=tab], [data-toggle=pill]").attr({tabIndex:"0","aria-selected":!0}),element.filter(".tab-pane").attr({"aria-hidden":!1,tabIndex:"0"})};var $colltabs=$('[data-toggle="collapse"]');$colltabs.each(function(index){var colltab=$(this),collpanel=$(colltab.attr("data-target")?colltab.attr("data-target"):colltab.attr("href")),parent=colltab.attr("data-parent"),collparent=parent&&$(parent),collid=colltab.attr("id")||uniqueId("ui-collapse"),parentpanel=collpanel.parent(),parentfirstchild=collparent?collparent.find(".panel.panel-default:first-child"):null,hasopenpanel=collparent?collparent.find(".panel-collapse.in").length>0:!1;colltab.attr("id",collid),collparent&&(colltab.attr({"aria-controls":collpanel.attr("id"),role:"tab","aria-selected":"false","aria-expanded":"false"}),$(collparent).find("div:not(.collapse,.panel-body), h4").attr("role","presentation"),collparent.attr({role:"tablist","aria-multiselectable":"true"}),collpanel.attr({role:"tabpanel","aria-labelledby":collid}),!hasopenpanel&&parentpanel.is(parentfirstchild)?(colltab.attr({tabindex:"0"}),collpanel.attr({tabindex:"-1"})):collpanel.hasClass("in")?(colltab.attr({"aria-selected":"true","aria-expanded":"true",tabindex:"0"}),collpanel.attr({tabindex:"0","aria-hidden":"false"})):(colltab.attr({tabindex:"-1"}),collpanel.attr({tabindex:"-1","aria-hidden":"true"})))});var collToggle=$.fn.collapse.Constructor.prototype.toggle;$.fn.collapse.Constructor.prototype.toggle=function(){var href,prevTab=this.$parent&&this.$parent.find('[aria-expanded="true"]');if(prevTab){var curTab,prevPanel=prevTab.attr("data-target")||(href=prevTab.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,""),$prevPanel=$(prevPanel),$curPanel=this.$element;this.$parent;this.$parent&&(curTab=this.$parent.find('[data-toggle=collapse][href="#'+this.$element.attr("id")+'"]')),collToggle.apply(this,arguments),$.support.transition&&this.$element.one($.support.transition.end,function(){prevTab.attr({"aria-selected":"false","aria-expanded":"false",tabIndex:"-1"}),$prevPanel.attr({"aria-hidden":"true",tabIndex:"-1"}),curTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:"0"}),$curPanel.hasClass("in")?$curPanel.attr({"aria-hidden":"false",tabIndex:"0"}):(curTab.attr({"aria-selected":"false","aria-expanded":"false"}),$curPanel.attr({"aria-hidden":"true",tabIndex:"-1"}))})}else collToggle.apply(this,arguments)},$.fn.collapse.Constructor.prototype.keydown=function(e){var $items,index,$this=$(this),$tablist=$this.closest("div[role=tablist] "),k=e.which||e.keyCode;$this=$(this),/(32|37|38|39|40)/.test(k)&&(32==k&&$this.click(),$items=$tablist.find("[role=tab]"),index=$items.index($items.filter(":focus")),(38==k||37==k)&&index--,(39==k||40==k)&&index++,0>index&&(index=$items.length-1),index==$items.length&&(index=0),$items.eq(index).focus(),e.preventDefault(),e.stopPropagation())},$(document).on("keydown.collapse.data-api",'[data-toggle="collapse"]',$.fn.collapse.Constructor.prototype.keydown),$(".carousel").each(function(index){function setTablistHighlightBox(){var $tab,offset,height,width,highlightBox={};highlightBox.top=0,highlightBox.left=32e3,highlightBox.height=0,highlightBox.width=0;for(var i=0;i<$tabs.length;i++){$tab=$tabs[i],offset=$($tab).offset(),height=$($tab).height(),width=$($tab).width(),highlightBox.top<offset.top&&(highlightBox.top=Math.round(offset.top)),highlightBox.height<height&&(highlightBox.height=Math.round(height)),highlightBox.left>offset.left&&(highlightBox.left=Math.round(offset.left));var w=offset.left-highlightBox.left+Math.round(width);highlightBox.width<w&&(highlightBox.width=w)}$tablistHighlight.style.top=highlightBox.top-2+"px",$tablistHighlight.style.left=highlightBox.left-2+"px",$tablistHighlight.style.height=highlightBox.height+7+"px",$tablistHighlight.style.width=highlightBox.width+8+"px"}var $tabpanel,$tablistHighlight,$pauseCarousel,$complementaryLandmark,$tab,i,$this=$(this),$prev=$this.find('[data-slide="prev"]'),$next=$this.find('[data-slide="next"]'),$tablist=$this.find(".carousel-indicators"),$tabs=$this.find(".carousel-indicators li"),$tabpanels=$this.find(".item"),$is_paused=!1,id_title="id_title",id_desc="id_desc";for($tablist.attr("role","tablist"),$tabs.focus(function(){$this.carousel("pause"),$is_paused=!0,$pauseCarousel.innerHTML="Start Image Carousel",$(this).parent().addClass("active"),setTablistHighlightBox(),$($tablistHighlight).addClass("focus"),$(this).parents(".carousel").addClass("contrast")}),$tabs.blur(function(event){$(this).parent().removeClass("active"),$($tablistHighlight).removeClass("focus"),$(this).parents(".carousel").removeClass("contrast")}),i=0;i<$tabpanels.length;i++)$tabpanel=$tabpanels[i],$tabpanel.setAttribute("role","tabpanel"),$tabpanel.setAttribute("id","tabpanel-"+index+"-"+i),$tabpanel.setAttribute("aria-labelledby","tab-"+index+"-"+i);for("string"!=typeof $this.attr("role")&&($this.attr("role","complementary"),$this.attr("aria-labelledby",id_title),$this.attr("aria-describedby",id_desc),$this.prepend('<p  id="'+id_desc+'" class="sr-only">You can control this image carousel using your keyboard or pointing device. Use the tabs or the previous and next buttons to change the image displayed.</p>'),$this.prepend('<h2 id="'+id_title+'" class="sr-only">Carousel with '+$tabpanels.length+" images.</h2>")),i=0;i<$tabs.length;i++){$tab=$tabs[i],$tab.setAttribute("role","tab"),$tab.setAttribute("id","tab-"+index+"-"+i),$tab.setAttribute("aria-controls","tabpanel-"+index+"-"+i);var tpId="#tabpanel-"+index+"-"+i,caption=$this.find(tpId).find("h1").text();("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).text()),("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).find("h3").text()),("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).find("h4").text()),("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).find("h5").text()),("string"!=typeof caption||0===caption.length)&&(caption=$this.find(tpId).find("h6").text()),("string"!=typeof caption||0===caption.length)&&(caption="no title");var tabName=document.createElement("span");tabName.setAttribute("class","sr-only"),tabName.innerHTML="Slide "+(i+1),caption&&(tabName.innerHTML+=": "+caption),$tab.appendChild(tabName)}$tablistHighlight=document.createElement("div"),$tablistHighlight.className="carousel-tablist-highlight",document.body.appendChild($tablistHighlight),$complementaryLandmark=document.createElement("aside"),$complementaryLandmark.setAttribute("class","carousel-aside-pause"),$complementaryLandmark.setAttribute("aria-label","Carousel pause/start control"),$this.prepend($complementaryLandmark),$pauseCarousel=document.createElement("button"),$pauseCarousel.className="carousel-pause-button",$pauseCarousel.innerHTML="Pause Carousel",$pauseCarousel.setAttribute("title","Use the pause/start carousel button to stop/start carousel animations."),$($complementaryLandmark).append($pauseCarousel),$($pauseCarousel).click(function(){$is_paused?($pauseCarousel.innerHTML="Pause Carousel",$this.carousel("cycle"),$is_paused=!1):($pauseCarousel.innerHTML="Start Carousel",$this.carousel("pause"),$is_paused=!0)}),$($pauseCarousel).focus(function(){$(this).addClass("focus")}),$($pauseCarousel).blur(function(){$(this).removeClass("focus")}),setTablistHighlightBox(),$(window).resize(function(){setTablistHighlightBox()}),$prev.attr("aria-label","Previous image"),$prev.keydown(function(e){var k=e.which||e.keyCode;/(13|32)/.test(k)&&(e.preventDefault(),e.stopPropagation(),$prev.trigger("click"))}),$prev.focus(function(){$(this).parents(".carousel").addClass("contrast")}),$prev.blur(function(){$(this).parents(".carousel").removeClass("contrast")}),$next.attr("aria-label","Next Slide"),$next.keydown(function(e){var k=e.which||e.keyCode;/(13|32)/.test(k)&&(e.preventDefault(),e.stopPropagation(),$next.trigger("click"))}),$next.focus(function(){$(this).parents(".carousel").addClass("contrast")}),$next.blur(function(){$(this).parents(".carousel").removeClass("contrast")}),$(".carousel-inner a").focus(function(){$(this).parents(".carousel").addClass("contrast")}),$(".carousel-inner a").blur(function(){$(this).parents(".carousel").removeClass("contrast")}),$tabs.each(function(){var item=$(this);item.hasClass("active")?item.attr({"aria-selected":"true",tabindex:"0"}):item.attr({"aria-selected":"false",tabindex:"-1"})})});var slideCarousel=$.fn.carousel.Constructor.prototype.slide;$.fn.carousel.Constructor.prototype.slide=function(type,next){var $id,$element=this.$element,$active=$element.find("[role=tabpanel].active"),$next=next||$active[type](),$tab_count=$element.find("[role=tabpanel]").length,$prev_side=$element.find('[data-slide="prev"]'),$next_side=$element.find('[data-slide="next"]'),$index=0,$prev_index=$tab_count-1,$next_index=1;$next&&$next.attr("id")&&($id=$next.attr("id"),$index=$id.lastIndexOf("-"),$index>=0&&($index=parseInt($id.substring($index+1),10)),$prev_index=$index-1,1>$prev_index&&($prev_index=$tab_count-1),$next_index=$index+1,$next_index>=$tab_count&&($next_index=0)),$prev_side.attr("aria-label","Show image "+($prev_index+1)+" of "+$tab_count),$next_side.attr("aria-label","Show image "+($next_index+1)+" of "+$tab_count),slideCarousel.apply(this,arguments),$active.one("bsTransitionEnd",function(){var $tab;$tab=$element.find('li[aria-controls="'+$active.attr("id")+'"]'),$tab&&$tab.attr({"aria-selected":!1,tabIndex:"-1"}),$tab=$element.find('li[aria-controls="'+$next.attr("id")+'"]'),$tab&&$tab.attr({"aria-selected":!0,tabIndex:"0"})})};var $this;$.fn.carousel.Constructor.prototype.keydown=function(e){function selectTab(index){index>=$tabs.length||0>index||($carousel.carousel(index),setTimeout(function(){$tabs[index].focus()},150))}$this=$this||$(this),this instanceof Node&&($this=$(this));var index,$carousel=$(e.target).closest(".carousel"),$tabs=$carousel.find("[role=tab]"),k=e.which||e.keyCode;/(37|38|39|40)/.test(k)&&(index=$tabs.index($tabs.filter(".active")),(37==k||38==k)&&(index--,selectTab(index)),(39==k||40==k)&&(index++,selectTab(index)),e.preventDefault(),e.stopPropagation())},$(document).on("keydown.carousel.data-api","li[role=tab]",$.fn.carousel.Constructor.prototype.keydown)}(jQuery);
\ No newline at end of file
diff --git a/themes/finc-accessibility/js/vendor/bootstrap-accessibility.min.js b/themes/finc-accessibility/js/vendor/bootstrap-accessibility.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..87ceae0771270dc50adf5f4ac212c3df8280bdd5
--- /dev/null
+++ b/themes/finc-accessibility/js/vendor/bootstrap-accessibility.min.js
@@ -0,0 +1 @@
+/*! override bootstrap - use specific language versions */
\ No newline at end of file
diff --git a/themes/finc-accessibility/templates/RecordTab/similaritemscarousel.phtml b/themes/finc-accessibility/templates/RecordTab/similaritemscarousel.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..f112e618638e5d1d11e52ae77beee3bfc6380b46
--- /dev/null
+++ b/themes/finc-accessibility/templates/RecordTab/similaritemscarousel.phtml
@@ -0,0 +1,75 @@
+<?php /* add language specific translations for carousel */ ?>
+<?php if (strcmp($this->layout()->userLang, 'de') == 0): ?>
+  <?=$this->inlineScript(\Zend\View\Helper\HeadScript::FILE, 'vendor/bootstrap-accessibility-de.min.js', 'SET');?>
+<?php endif; ?>
+<h2><?=$this->transEsc('Similar Items')?></h2>
+<?php $similarRecords = $this->tab->getResults(); ?>
+<?php if (!empty($similarRecords)): ?>
+  <?php $perPage = 4 ?>
+  <div id="similar-items-carousel" class="carousel slide" data-ride="carousel">
+    <!-- Indicators -->
+    <ol class="carousel-indicators">
+      <li data-target="#similar-items-carousel" data-slide-to="0" class="active"></li>
+      <?php for($i = 1;$i < count($similarRecords) / $perPage;$i++): ?>
+        <li data-target="#similar-items-carousel" data-slide-to="<?=$i ?>"></li>
+      <?php endfor; ?>
+    </ol>
+
+    <!-- Wrapper for slides -->
+    <div class="carousel-inner">
+      <div class="item active">
+        <?php foreach ($similarRecords as $index => $data): ?>
+          <div class="carousel-item">
+            <a class="hover-overlay" href="<?=$this->recordLink()->getUrl($data)?>">
+              <?php $thumb = $this->record($data)->getThumbnail('large'); ?>
+              <img src="<?=$thumb ?>" title="<?=$data->getTitle() ?>"/>
+              <div class="content">
+                <?php $formats = $data->getFormats(); ?>
+                <i class="fa fa-x<?php if (count($formats) > 0): ?> fa-<?=preg_replace('/[^a-z0-9]/', '', strtolower($formats[0]))?>" title="<?=$formats[0] ?><?php endif; ?>"></i>
+                <b><?=$this->escapeHtml($data->getTitle())?></b>
+                <?php $authors = $data->getPrimaryAuthors(); if (!empty($authors)): ?>
+                  <br/><?=$this->transEsc('by')?>: <?=$this->escapeHtml($authors[0]);?><?php if (count($authors) > 1): ?>, <?=$this->transEsc('more_authors_abbrev')?><?php endif; ?>
+                <?php endif; ?>
+                <?php $pubDates = $data->getPublicationDates(); if (!empty($pubDates)): ?>
+                  <br/><?=$this->transEsc('Published')?>: (<?=$this->escapeHtml($pubDates[0])?>)
+                <?php endif; ?>
+              </div>
+            </a>
+          </div>
+          <?php if(($index + 1) % $perPage == 0 && $index < count($similarRecords) - 1): ?>
+      </div>
+      <div class="item">
+          <?php endif; ?>
+        <?php endforeach; ?>
+      </div>
+    </div>
+
+    <!-- Controls -->
+    <a class="left carousel-control" href="#similar-items-carousel" role="button" data-slide="prev" aria-label="<?=$this->transEsc('Prev') ?>">
+      <span class="fa fa-chevron-left glyphicon-chevron-left" title="<?=$this->transEsc('Prev') ?>"></span>
+    </a>
+    <a class="right carousel-control" href="#similar-items-carousel" role="button" data-slide="next" aria-label="<?=$this->transEsc('Next') ?>">
+      <span class="fa fa-chevron-right glyphicon-chevron-right" title="<?=$this->transEsc('Next') ?>"></span>
+    </a>
+  </div>
+<?php else: ?>
+  <p><?=$this->transEsc('Cannot find similar records')?></p>
+<?php endif; ?>
+<?php
+  $script = <<<JS
+var normalizeHeightCount = $('#similar-items-carousel img').length;
+function normalizeHeights() {
+  if(--normalizeHeightCount > 0) return;
+  var tallest = 0;
+  var items = $('#similar-items-carousel .hover-overlay');
+  items.each(function() { //add heights to array
+    if(tallest < $(this).height()) {
+      tallest = $(this).height();
+    }
+  });
+  items.css('min-height', (tallest+25) + 'px');
+}
+$('#similar-items-carousel img').load(normalizeHeights);
+JS;
+?>
+<?=$this->inlineScript(\Zend\View\Helper\HeadScript::SCRIPT, $script, 'SET') ?>
diff --git a/themes/finc/scss/_customMixins.scss b/themes/finc/scss/_customMixins.scss
index b511a3e60b4bb88632453e18cca574ad0a7ff279..460b1cce5117d8a23c1ab8ccd142af2425add8ad 100644
--- a/themes/finc/scss/_customMixins.scss
+++ b/themes/finc/scss/_customMixins.scss
@@ -23,7 +23,7 @@
 }
 
 // Outline Mixin -- complements BS outline mixin in partials/mixin but does not rewrite it
-@mixin outline($size: $outline-default-size-finc, $color: $outline-default-color-finc, $style: $outline-default-style-finc) {
+@mixin outline($size: $outline-default-size, $color: $outline-default-color, $style: $outline-default-style) {
   outline: $style $size $color;
 }
 
diff --git a/themes/finc/scss/_customVariables.scss b/themes/finc/scss/_customVariables.scss
index 29bdd7bb4c4dd89e9cf6d91289b3e4d5242021a1..24e6a91e497583bba2a0a5a8b7c307d04615d495 100644
--- a/themes/finc/scss/_customVariables.scss
+++ b/themes/finc/scss/_customVariables.scss
@@ -115,10 +115,10 @@ $border-default-white: 1px solid $white !default;
 $border-right-width: 1px !default;
 $margin-right-width: inherit !default;
 
-//// Outlines (focus, accessibility etc.) -- complements similar BS values
-$outline-default-color-finc: $black !default;
-$outline-default-size-finc: 1px !default;
-$outline-default-style-finc: solid !default;
+//// Outlines (focus, accessibility etc.) -- overriding default bootstrap accessibility plugin scss variables
+$outline-default-color: $black !default;
+$outline-default-size: 1px !default;
+$outline-default-style: solid !default;
 
 //// PAGER
 $pagination-disabled-color: $gainsboro !default;
diff --git a/themes/finc/scss/compiled.scss b/themes/finc/scss/compiled.scss
index f225ac9b883d6d17fb55761d494c0673d47fdc47..a7fbd375f82075f348503611d72770e940b5b340 100644
--- a/themes/finc/scss/compiled.scss
+++ b/themes/finc/scss/compiled.scss
@@ -191,6 +191,13 @@ h2 {
 //// h3
 h3 {
   font-size: 1.5rem;
+
+  // H3 in MyAccount needs to be pushed in
+  #myresearch-sidebar & {
+    @media screen and (max-width: $screen-xs-max) {
+      padding-left: $half-gutter;
+    }
+  }
 }
 
 //// h4
@@ -2079,16 +2086,16 @@ footer {
   .search-filter-toggle::before {
     content: '\f100\00a0';
   }
-}
 
-.offcanvas-left .record {
-  .media-left.img-col {
-    // push record view icon to right (Desktop) on left-aligned sidebars -- pls NOTE: required offcanvas = true
-    @media (min-width: $screen-sm-min) {
-      float: right;
-      margin-left: $grid-gutter-width / 2;
-      margin-right: 0;
-      padding-right: 0;
+  .record {
+    .media-left.img-col {
+      // push record view icon to right (Desktop) on left-aligned sidebars -- pls NOTE: required offcanvas = true
+      @media (min-width: $screen-sm-min) {
+        float: right;
+        margin-left: $grid-gutter-width / 2;
+        margin-right: 0;
+        padding-right: 0;
+      }
     }
   }
 }
@@ -2708,11 +2715,18 @@ body:not(.offcanvas) .sidebar {
 
 //// Style myaccount sidebar menues to get the same look as facets
 .myresearch-menu {
-  border: 1px solid $border-color;
 
-  a:not(:last-of-type) {
-    border-bottom: 1px solid $border-color;
-    padding: $sidebar-item-padding; // overwrite values from BS with more sensible values
+  a {
+    width: 100%;
+
+    &:not(:last-of-type) {
+      border-bottom: 1px solid $border-color;
+      padding: $sidebar-item-padding; // overwrite values from BS with more sensible values
+    }
+  }
+
+  .facet {
+    padding: 0 !important;
   }
 }
 
@@ -2738,6 +2752,11 @@ body:not(.offcanvas) .sidebar {
     }
   }
 
+  > li {
+    margin: 0;
+    padding: 0;
+  }
+
   ////// Pull exclude facets to the right, align with accordion/collapse triangles and headings
   .facet.excludable {
     padding-left: 1.5em;
@@ -2759,8 +2778,8 @@ body:not(.offcanvas) .sidebar {
 
 
 //// Offcanvas is used to widths of 767px ($screen-xs-max)
-@media (max-width: $screen-xs-max) {
-  .offcanvas.active .sidebar {
+.offcanvas.active .sidebar {
+  @media (max-width: $screen-xs-max) {
     padding-right: ($grid-gutter-width / 2);
   }
 }
@@ -2828,10 +2847,28 @@ body:not(.offcanvas) .sidebar {
     -ms-word-break: break-all;
     word-break: break-all; // fallback for hyphens: auto (Chrome on Desktop and bug on Mozilla for capitalized words)
 
+    a,
     .text {
       -ms-word-break: break-word;
       word-break: break-word;
     }
+
+    a {
+      text-decoration: none;
+    }
+  }
+
+  // special case: on sm-size AND search result facats
+  @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
+    & div[id^='side-panel-'] {
+      .facet {
+        a,
+        .text {
+          -ms-word-break: initial;
+          word-break: initial;
+        }
+      }
+    }
   }
 }
 
@@ -2878,6 +2915,8 @@ body:not(.offcanvas) .sidebar {
   &.overdue {
     .myresearch-menu & {
       color: $white;
+      // unset height attribute from .facet .badge {} definition for better looks
+      max-height: unset;
       padding: 3px 7px;
     }
   }
@@ -3257,13 +3296,12 @@ input {
 
 
 // CHANNELS
-
-.slick-arrow:not(.slick-disabled).slick-next:focus:before,
-.slick-arrow:not(.slick-disabled).slick-next:hover:before,
-.slick-arrow:not(.slick-disabled).slick-prev:focus:before,
-.slick-arrow:not(.slick-disabled).slick-prev:hover:before {
-  color: $slick-arrow-hover-color;
-  outline: 2px $black dotted;
+.slick-arrow:not(.slick-disabled).slick-next,
+.slick-arrow:not(.slick-disabled).slick-prev {
+  &:focus::before,
+  &:hover::before {
+    color: $slick-arrow-hover-color;
+    outline: 2px $black dotted;
+  }
 }
-
 // CHANNELS - END
diff --git a/themes/finc/templates/RecordDriver/DefaultRecord/list-entry.phtml b/themes/finc/templates/RecordDriver/DefaultRecord/list-entry.phtml
index 3412cfef99ca6959911d15635e8671a04dcd5879..3c1233c8b90ba4f5341f0a60d79e1a1bfa024bae 100644
--- a/themes/finc/templates/RecordDriver/DefaultRecord/list-entry.phtml
+++ b/themes/finc/templates/RecordDriver/DefaultRecord/list-entry.phtml
@@ -38,8 +38,8 @@ $thumbnailAlignment = $this->record($this->driver)->getThumbnailAlignment('list'
       <div class="result-body">
         <div class="resultItemLine1">
           <?php $missing = $this->driver instanceof \VuFind\RecordDriver\Missing; ?>
-          <?php $describedById = $driver->getSourceIdentifier() . '|' . $driver->getUniqueId(); ?>
             <?php if ($missing && $this->driver->isCachedRecord()): ?>
+                <?php $describedById = $driver->getSourceIdentifier() . '|' . $driver->getUniqueId(); ?>
                 <span id="<?=$describedById?>" class="title" lang=""><?=$this->record($this->driver)->getTitleHtml()?></span>
                 <p class="alert alert-info">
                     <?= $this->translate('record_from_cache')?>
@@ -48,6 +48,7 @@ $thumbnailAlignment = $this->record($this->driver)->getThumbnailAlignment('list'
                     <?php endif; ?>
                 </p>
             <?php elseif (!$missing): ?>
+                <?php $describedById = $driver->getSourceIdentifier() . '|' . $driver->getUniqueId(); ?>
                 <a href="<?=$this->recordLink()->getUrl($this->driver)?>" class="getFull" data-view="<?=$this->params->getOptions()->getListViewOption() ?>">
                     <span id="<?=$describedById?>" class="title" lang=""><?=$this->record($this->driver)->getTitleHtml()?></span>
                 </a>
diff --git a/themes/finc/templates/footer.phtml b/themes/finc/templates/footer.phtml
index b39d33f6adef441e6b1a61844b7c4a6b7531d49c..e0e0eae30b028c7913c59d682515273782a6d5ad 100644
--- a/themes/finc/templates/footer.phtml
+++ b/themes/finc/templates/footer.phtml
@@ -38,7 +38,7 @@
           <?= $this->transEsc("Footer-Powered-By-Text") ?>
         </span>
         <?= $this->externalLink("https://vufind.org", '<img src="' . $this->imageLink('vufind_logo.png') . '" alt="' . $this->translate('vufind-logo_alt') . '" aria-hidden="true"/>', ['title' => $this->translate('vufind-logo_title')]) ?>
-        <?= $this->externalLink("http://blog.finc.info", '<img src="' . $this->imageLink('finc_logo.png') . '" alt="' . $this->translate('finc-logo_alt') . '" aria-hidden="true"/>', ['title' => $this->translate('finc-logo_title'), 'aria-hidden' => 'true']) ?>
+        <?= $this->externalLink("https://finc.info", '<img src="' . $this->imageLink('finc_logo.png') . '" alt="' . $this->translate('finc-logo_alt') . '" aria-hidden="true"/>', ['title' => $this->translate('finc-logo_title'), 'aria-hidden' => 'true']) ?>
       </div>
     </div>
 </footer>
diff --git a/themes/finc/templates/layout/layout.phtml b/themes/finc/templates/layout/layout.phtml
index c2b6a370feb8ac53c20deecea4b26f0bd41c64b7..898b0e194a6543dee78370def3c9e928c51b3e5e 100644
--- a/themes/finc/templates/layout/layout.phtml
+++ b/themes/finc/templates/layout/layout.phtml
@@ -24,6 +24,13 @@
   <?php if ($this->layout()->rtl) {
     $this->headLink()->appendStylesheet('vendor/bootstrap-rtl.min.css');
   } ?>
+  <?php
+    if (strcmp($this->layout()->userLang, 'de') == 0) {
+      $this->headScript()->appendFile('vendor/bootstrap-accessibility-de.min.js');
+    } else {
+      $this->headScript()->appendFile('vendor/bootstrap-accessibility-en.min.js');
+    }
+  ?>
   <?=$this->headLink()?>
   <?=$this->headStyle()?>
   <?php
diff --git a/themes/finc/templates/myresearch/menu.phtml b/themes/finc/templates/myresearch/menu.phtml
index 32dd7c7cc725e4eb4a729bd3695345644e61b83c..a2348fc565404adbfdcaae793f20c57a52d8b1f2 100644
--- a/themes/finc/templates/myresearch/menu.phtml
+++ b/themes/finc/templates/myresearch/menu.phtml
@@ -8,114 +8,144 @@ $capabilityParams = $patron ? ['patron' => $patron] : [];
 
 <h2><?=$this->transEsc('Your Account')?></h2>
 <?php /* finc needs to add .facet-group class and classes on sub items for borders - CK */ ?>
-<div class="myresearch-menu account-menu facet-group">
+<ul class="myresearch-menu account-menu facet-group">
   <?php if ($this->userlist()->getMode() !== 'disabled'): ?>
 
-    <a href="<?=$this->url('myresearch-favorites')?>"<?=$this->active == 'favorites' ? ' class="active"' : ''?>>
+    <li class="facet">
+      <a href="<?=$this->url('myresearch-favorites')?>"<?=$this->active == 'favorites' ? ' class="active"' : ''?>>
       <i class="fa fa-fw fa-star" aria-hidden="true"></i> <?=$this->transEsc('Favorites')?>
     </a>
+    </li>
 
   <?php endif; ?>
   <?php if ('ils-none' !== $this->ils()->getOfflineMode()): ?>
     <?php if ($this->ils()->checkCapability('getMyTransactions', $capabilityParams)): ?>
 
-      <a href="<?=$this->url('myresearch-checkedout')?>" class="flex checkedout<?=$this->active == 'checkedout' ? ' active' : ''?>">
-        <span class="flex-col"><i class="fa fa-fw fa-book" aria-hidden="true"></i>&nbsp;<?=$this->transEsc('Checked Out Items')?></span>
-        <span class="checkedout-status status hidden"><i class="fa fa-spin fa-spinner" aria-hidden="true"></i></span>
-        <?php /* nxt line finc specific - CK */ ?>
-        <span id="getMyTransactions" class="itemCount pull-right no-padding"></span>
-      </a>
+      <li class="facet">
+        <a href="<?=$this->url('myresearch-checkedout')?>" class="flex checkedout<?=$this->active == 'checkedout' ? ' active' : ''?>">
+          <span class="flex-col"><i class="fa fa-fw fa-book" aria-hidden="true"></i>&nbsp;<?=$this->transEsc('Checked Out Items')?></span>
+          <span class="checkedout-status status hidden"><i class="fa fa-spin fa-spinner" aria-hidden="true"></i></span>
+            <?php /* nxt line finc specific - CK */ ?>
+          <span id="getMyTransactions" class="itemCount pull-right no-padding"></span>
+        </a>
+      </li>
     <?php endif; ?>
     <?php if ($this->ils()->checkFunction('getMyTransactionHistory', $capabilityParams)): ?>
-      <a href="<?=$this->url('myresearch-historicloans')?>"<?=$this->active == 'historicloans' ? ' class="active"' : ''?>>
+      <li class="facet">
+        <a href="<?=$this->url('myresearch-historicloans')?>"<?=$this->active == 'historicloans' ? ' class="active"' : ''?>>
         <i class="fa fa-fw fa-history" aria-hidden="true"></i> <?=$this->transEsc('Loan History')?>
       </a>
+      </li>
     <?php endif; ?>
     <?php if ($this->ils()->checkCapability('getMyHolds', $capabilityParams)): ?>
 
-      <a href="<?=$this->url('myresearch-holds')?>" class="flex<?=$this->active == 'holds' ? ' active' : ''?>">
+      <li class="facet">
+        <a href="<?=$this->url('myresearch-holds')?>" class="flex<?=$this->active == 'holds' ? ' active' : ''?>">
         <span class="flex-col"><i class="fa fa-fw fa-flag" aria-hidden="true"></i>&nbsp;<?=$this->transEsc('Holds and Recalls')?></span>
         <span class="holds-status status hidden"><i class="fa fa-spin fa-spinner" aria-hidden="true"></i></span>
         <?php /* nxt line finc specific - CK */ ?>
         <span id="getMyHolds" class="itemCount pull-right no-padding"></span>
       </a>
+      </li>
     <?php endif; ?>
     
     <?php if ($this->ils()->checkFunction('StorageRetrievalRequests', $capabilityParams)): ?>
-      <a href="<?=$this->url('myresearch-storageretrievalrequests')?>" class="flex<?=$this->active == 'storageRetrievalRequests' ? ' active' : ''?>">
+      <li class="facet">
+        <a href="<?=$this->url('myresearch-storageretrievalrequests')?>" class="flex<?=$this->active == 'storageRetrievalRequests' ? ' active' : ''?>">
         <span class="flex-col"><i class="fa fa-fw fa-archive" aria-hidden="true"></i> <?=$this->transEsc('Storage Retrieval Requests')?></span>
         <span class="storageretrievalrequests-status status hidden"><i class="fa fa-spin fa-spinner" aria-hidden="true"></i></span>
         <?php /* nxt line finc specific - CK */ ?>
         <span id="getMyStorageRetrievalRequests" class="itemCount pull-right no-padding"></span>
       </a>
+      </li>
     <?php endif; ?>
     
     <?php if ($this->ils()->checkFunction('ILLRequests', $capabilityParams)): ?>
-      <a href="<?=$this->url('myresearch-illrequests')?>" class="flex<?=$this->active == 'ILLRequests' ? ' active' : ''?>">
+      <li class="facet">
+        <a href="<?=$this->url('myresearch-illrequests')?>" class="flex<?=$this->active == 'ILLRequests' ? ' active' : ''?>">
         <span class="flex-col"><i class="fa fa-fw fa-exchange" aria-hidden="true"></i>&nbsp;<?=$this->transEsc('Interlibrary Loan Requests')?></span>
         <span class="illrequests-status status hidden"><i class="fa fa-spin fa-spinner" aria-hidden="true"></i></span>
         <?php /* nxt line finc specific - CK */ ?>
         <span id="getMyILLRequests" class="itemCount pull-right no-padding"></span>
       </a>
+      </li>
     <?php endif; ?>
     
     <?php if ($this->ils()->checkCapability('getMyFines', $capabilityParams)): ?>
-      <a href="<?=$this->url('myresearch-fines')?>" class="flex<?=$this->active == 'fines' ? ' active' : ''?>">
+      <li class="facet">
+        <a href="<?=$this->url('myresearch-fines')?>" class="flex<?=$this->active == 'fines' ? ' active' : ''?>">
         <span class="flex-col"><i class="fa fa-fw fa-usd" aria-hidden="true"></i>&nbsp;<?=$this->transEsc('Fines')?></span>
         <span class="fines-status status hidden"><i class="fa fa-spin fa-spinner" aria-hidden="true"></i></span>
       </a>
+      </li>
     <?php endif; ?>
-    <a href="<?=$this->url('myresearch-profile')?>"<?=$this->active == 'profile' ? ' class="active"' : ''?>>
+    <li class="facet">
+      <a href="<?=$this->url('myresearch-profile')?>"<?=$this->active == 'profile' ? ' class="active"' : ''?>>
       <i class="fa fa-fw fa-user" aria-hidden="true"></i> <?=$this->transEsc('Profile')?>
     </a>
+    </li>
     <?php if ($user && $user->libraryCardsEnabled()): ?>
-      <a href="<?=$this->url('librarycards-home')?>"<?=$this->active == 'librarycards' ? ' class="active"' : ''?>>
+      <li class="facet">
+        <a href="<?=$this->url('librarycards-home')?>"<?=$this->active == 'librarycards' ? ' class="active"' : ''?>>
         <i class="fa fa-fw fa-barcode" aria-hidden="true"></i> <?=$this->transEsc('Library Cards')?>
       </a>
+      </li>
     <?php endif; ?>
   <?php endif; ?>
   <?php if ($this->accountCapabilities()->getSavedSearchSetting() === 'enabled'): ?>
-    <a href="<?=$this->url('search-history')?>?require_login"<?=$this->active == 'history' ? ' class="active"' : ''?>>
+    <li class="facet">
+      <a href="<?=$this->url('search-history')?>?require_login"<?=$this->active == 'history' ? ' class="active"' : ''?>>
       <i class="fa fa-fw fa-search" aria-hidden="true"></i> <?=$this->transEsc('history_saved_searches')?>
     </a>
+    </li>
   <?php endif; ?>
   <?php if ($user): ?>
-    <a href="<?=$this->url('myresearch-logout')?>">
+    <li class="facet">
+      <a href="<?=$this->url('myresearch-logout')?>">
       <i class="fa fa-fw fa-sign-out" aria-hidden="true"></i> <?=$this->transEsc("Log Out")?>
     </a>
+    </li>
   <?php endif; ?>
-</div>
+</ul>
 
 <?php if ($this->auth()->isLoggedIn() && $this->auth()->getManager()->supportsPasswordChange()): ?>
   <h3><?=$this->transEsc('Preferences')?></h3>
-  <div class="myresearch-menu facet-group">
-    <a href="<?=$this->url('myresearch-changepassword')?>"<?=$this->active == 'newpassword' ? ' class="active"' : ''?>>
+  <ul class="myresearch-menu facet-group">
+    <li class="facet">
+      <a href="<?=$this->url('myresearch-changepassword')?>"<?=$this->active == 'newpassword' ? ' class="active"' : ''?>>
       <i class="fa fa-fw fa-lock" aria-hidden="true"></i> <?=$this->transEsc('Change Password')?>
     </a>
-  </div>
+    </li>
+  </ul>
 <?php endif; ?>
 
 <?php if ($user && $this->userlist()->getMode() !== 'disabled'): ?>
   <h3><?=$this->transEsc('Your Lists')?></h3>
-  <div class="myresearch-menu facet-group">
-    <a href="<?=$this->url('myresearch-favorites')?>"<?=$this->active == 'favorites' ? ' class="active"' : ''?>>
+  <ul class="myresearch-menu facet-group">
+    <li class="facet">
+      <a href="<?=$this->url('myresearch-favorites')?>"<?=$this->active == 'favorites' ? ' class="active"' : ''?>>
       <i class="fa fa-fw fa-star" aria-hidden="true"></i> <?=$this->transEsc('Your Favorites')?>
     </a>
+    </li>
 
     <?php $lists = $user->getLists() ?>
     <?php foreach ($lists as $list): ?>
       <?php /* finc: keep icon inside + keep braces in badge!; CK*/ ?>
-      <a href="<?=$this->url('userList', ['id' => $list['id']])?>"<?=$this->active == 'list' . $list['id'] ? ' class="active"' : ''?>>
+      <li class="facet">
+        <a href="<?=$this->url('userList', ['id' => $list['id']])?>"<?=$this->active == 'list' . $list['id'] ? ' class="active"' : ''?>>
         <i class="fa fa-fw fa-star-o" aria-hidden="true"></i> <?=$this->escapeHtml($list['title'])?>
         <span class="badge">(<?=$list->cnt?>)</span>
       </a>
+      </li>
 
     <?php endforeach; ?>
-    <a href="<?=$this->url('editList', ['id' => 'NEW'])?>"<?=$this->active == 'editlist/NEW' ? ' class="active"' : ''?>>
+    <li class="facet">
+      <a href="<?=$this->url('editList', ['id' => 'NEW'])?>"<?=$this->active == 'editlist/NEW' ? ' class="active"' : ''?>>
       <i class="fa fa-fw fa-plus" aria-hidden="true"></i> <?=$this->transEsc('Create a List')?>
     </a>
+    </li>
 
-  </div>
+  </ul>
 <?php endif ?>
 <?php /* finc: This script is finc-specific - CK */ ?>
 <?php $script = <<<JS