PageSourceSearch

https://keelesu.com/yourunion/electedofficers/blogs/DDOfficer/

html keelesu.com collected 2026-09-25 06:05:16 UTC 106,440 bytes, 2,329 lines download raw bytes

1
2
3<!DOCTYPE html>
4
5<html lang="en-GB">
6<head><!-- Powered by www.ukmsl.com - v8.90.2609.303 --><title>
7	Development &amp; Democracy Officer Blog
8</title><meta charset="utf-8" /><link href="//static-uk.ukmsl.net/8.90/skins/print.css" rel="stylesheet" type="text/css" media="print" />
9<link href="//static-uk.ukmsl.net/8.90/skins/system.css" rel="stylesheet" type="text/css" media="all" />
10<link href="//static-uk.ukmsl.net/8.90/skins/icons.css" rel="stylesheet" type="text/css" media="all" />
11<link href="//static-uk.ukmsl.net/8.90/skins/Froala.css" rel="stylesheet" type="text/css" media="all" />
12
13<!-- start of su-meta snippet -->
14<!-- Basic Meta Tags -->
15<meta charset="utf-8">
16<meta name="viewport" content="width=device-width, initial-scale=1.0">
17<meta name="referrer" content="strict-origin-when-cross-origin">
18<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin="">
19<link rel="preload" href="/assets/site_resources/Lato-Light.woff2" as="font" type="font/woff2" crossorigin>
20<link rel="preload" href="/assets/site_resources/league-spartan-700.woff2" as="font" type="font/woff2" crossorigin>
21
22<!-- Branding -->
23<meta name="theme-color" content="#22004d">
24<meta name="msapplication-TileColor" content="#22004d">
25<!--
26  Removed msapplication-navbutton-color: Windows Phone IE only, no modern
27  browser reads it (same dead-platform relic as the old UA-sniffing code).
28-->
29
30<!-- iOS / mobile web app -->
31<!-- apple-mobile-web-app-status-bar-style only accepts "default",
32     "black", or "black-translucent" — a hex color is invalid and is
33     silently ignored by iOS. Using "black-translucent" as the closest
34     supported equivalent for a dark theme-color; adjust if you want the
35     plain black bar instead. -->
36<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
37<!-- apple-mobile-web-app-capable is required for standalone/home-screen
38     mode on iOS versions before 16.4; mobile-web-app-capable alone is not
39     enough for those older Safari versions. Keeping both. -->
40<meta name="apple-mobile-web-app-capable" content="yes">
41<meta name="mobile-web-app-capable" content="yes">
42<meta name="apple-itunes-app" content="app-id=1579307063">
43
44<!-- App Titles -->
45<meta name="application-name" content="Keele SU">
46<meta name="apple-mobile-web-app-title" content="Keele SU">
47
48<!-- Icons -->
49<link rel="apple-touch-icon" sizes="180x180" href="https://keelesu.com/stylesheet/Brand/apple-touch-icon.png">
50<link rel="icon" type="image/png" sizes="32x32" href="https://keelesu.com/stylesheet/Brand/favicon-32x32.png">
51<link rel="icon" type="image/png" sizes="16x16" href="https://keelesu.com/stylesheet/Brand/favicon-16x16.png">
52<link rel="manifest" href="https://keelesu.com/stylesheet/Brand/site.webmanifest">
53<link rel="mask-icon" href="https://keelesu.com/stylesheet/Brand/safari-pinned-tab.svg" color="#2e1a47">
54<link rel="shortcut icon" href="https://keelesu.com/stylesheet/Brand/favicon.ico">
55
56<!-- Open Graph (Global defaults via MSL fields) -->
57<meta property="og:type" content="website">
58<meta property="og:site_name" content="Keele SU">
59<meta property="og:locale" content="en_GB">
60<meta property="og:url" content="https://keelesu.com/yourunion/electedofficers/blogs/ddofficer/">
61<meta property="og:title" content="Officer Blogs">
62<meta property="og:description" content="">
63<meta property="og:image" content="https://keelesu.com/pageassets/yourunion/electedofficers/blogs/Elected-Officers.jpeg">
64
65<!-- Twitter -->
66<meta name="twitter:card" content="summary_large_image">
67<meta name="twitter:site" content="@keelesu">
68<meta name="twitter:url" content="https://keelesu.com/yourunion/electedofficers/blogs/ddofficer/">
69<meta name="twitter:title" content="Officer Blogs">
70<meta name="twitter:description" content="">
71<meta name="twitter:image" content="https://keelesu.com/pageassets/yourunion/electedofficers/blogs/Elected-Officers.jpeg">
72
73<!-- General -->
74<meta name="author" content="Keele SU">
75<meta name="url" content="https://keelesu.com/yourunion/electedofficers/blogs/ddofficer/">
76<meta name="title" content="Officer Blogs">
77<meta name="description" content="">
78<meta name="image" content="https://keelesu.com/pageassets/yourunion/electedofficers/blogs/Elected-Officers.jpeg">
79<!--
80  NOTE: <meta name="title"> is not a recognised SEO tag — it does nothing
81  for search engines or browsers. Confirm the CMS also emits a real
82  <title>...</title> element somewhere in this head; none is present in
83  this fragment.
84-->
85
86<!-- Facebook Verify -->
87<meta name="facebook-domain-verification" content="j8zqeuyega64aha524xuxeb1913wri" />
88
89<!--
90  Meta Pixel Code
91  NOTE: this fires unconditionally on every page load. As a UK site,
92  this is subject to UK GDPR/PECR, which requires consent before
93  non-essential tracking pixels/cookies load. If a consent-management
94  layer elsewhere gates this script (e.g. only injecting it after
95  opt-in, or holding it via a tag manager's consent mode), that's fine —
96  but as a standalone unconditional 
96<script> it loads Facebook's
97  tracker before any opt-in choice is made. Verify a consent gate wraps
98  this before shipping.
99-->
100<script>
vendor: 408 bytes, lines 100-109
100
101!function(f,b,e,v,n,t,s)
102{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
103n.callMethod.apply(n,arguments):n.queue.push(arguments)};
104if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
105n.queue=[];t=b.createElement(e);t.async=!0;
106t.src=v;s=b.getElementsByTagName(e)[0];
107s.parentNode.insertBefore(t,s)}(window, document,'script',
108'https://connect.facebook.net/en_GB/fbevents.js');
109fbq('init', '
1092123049768236773
vendor: 32 bytes, lines 109-110
109');
110fbq('track', 'PageView');
111</script>
111
112<noscript><img height="1" width="1" style="display:none"
113src="https://www.facebook.com/tr?id=2123049768236773&ev=PageView&noscript=1"
114/></noscript>
115<!-- End Meta Pixel Code -->
116
117<!-- Structured Data (Unified Organization/EducationalOrganization) -->
118<script type="application/ld+json">
119{
120  "@context": "https://schema.org",
121  "@type": ["Organization", "EducationalOrganization"],
122  "@id": "https://keelesu.com/#organization",
123  "name": "Keele University Students' Union",
124  "alternateName": "Keele SU",
125  "url": "https://keelesu.com/",
126  "logo": "https://keelesu.com/stylesheet/Brand/keelesu_rich_blue_logo_long.png",
127  "sameAs": [
128    "https://www.facebook.com/keelestudentsunion/",
129    "https://www.instagram.com/keelesu/",
130    "https://www.tiktok.com/@keelesu",
131    "https://www.youtube.com/@KeeleSU",
132    "https://www.linkedin.com/company/keele-students-union/",
133    "https://linktr.ee/keelesu"
134  ],
135  "address": {
136    "@type": "PostalAddress",
137    "streetAddress": "Keele University",
138    "addressLocality": "Keele",
139    "addressRegion": "Staffordshire",
140    "postalCode": "ST5 5BJ",
141    "addressCountry": "GB"
142  },
143  "contactPoint": {
144    "@type": "ContactPoint",
145    "telephone": "+44 1782 733700",
146    "email": "[email protected]",
147    "contactType": "Customer Service",
148    "availableLanguage": "English"
149  },
150  "parentOrganization": {
151    "@type": "CollegeOrUniversity",
152    "name": "Keele University",
153    "url": "https://www.keele.ac.uk/"
154  }
155}
156</script>
156
157
158<!-- ========================= -->
159<!-- Structured Data: Consistent Author -->
160<!-- ========================= -->
161<!--
162  This now correctly resolves: the "@id" above matches the "@id" this
163  block references below, so search engines can actually connect the
164  two entities. Previously the first schema had no "@id" at all, so the
165  link was broken.
166-->
167<script type="application/ld+json">
168{
169  "@context": "https://schema.org",
170  "@type": "Organization",
171  "@id": "https://keelesu.com/#author",
172  "name": "Keele SU Team",
173  "url": "https://keelesu.com/yoursu/aboutus/",
174  "parentOrganization": {
175    "@id": "https://keelesu.com/#organization"
176  }
177}
178</script>
178
179
180<!--
181  Canonical link.
182  IMPORTANT: this is still a client-side fallback, kept only for parity
183  with the original snippet. A canonical tag this important should
184  ideally be rendered server-side directly into the HTML <head> by the
185  CMS/MSL template, since crawlers that don't execute JavaScript (and
186  even Googlebot, under rendering-budget constraints) may never see a
187  tag injected this way. Treat this script as a safety net, not the
188  primary mechanism, and prefer wiring MSL's own canonical/URL field
189  into a real <link rel="canonical"> tag if one exists.
190
191  Fixes applied vs the original inline script:
192  - Skips entirely if a canonical <link> already exists in <head>, to
193    avoid emitting a duplicate (which causes Google to ignore or
194    arbitrarily choose between them).
195  - Does NOT force a trailing slash onto paths that already end in a
196    file extension (.aspx, .pdf, .jpg, etc.) — this site's markup
197    (ctl00_basket_lnk... control IDs) indicates ASP.NET/MSL, where many
198    real URLs end in .aspx and would 404 if forced to end in "/".
199  - Uses the built-in URL API instead of ad hoc string/regex surgery to
200    avoid double slashes or malformed protocols.
201  - Deliberately still drops the query string, matching the original
202    behavior. If any pages rely on query strings for distinct content
203    (pagination, filters, search results), those pages need their own
204    canonical logic — this generic script should not run on them.
205-->
206<script>
207(function () {
208  if (document.querySelector('link[rel="canonical"]')) return;
209
210  var url = new URL(window.location.href);
211  var path = url.pathname;
212
213  // Only add a trailing slash if the last path segment has no file
214  // extension (i.e. looks like a directory/route, not a file).
215  var lastSegment = path.split('/').pop();
216  var looksLikeFile = lastSegment.indexOf('.') !== -1;
217
218  if (!looksLikeFile && !path.endsWith('/')) {
219    path += '/';
220  }
221
222  var canonicalURL = url.origin + path;
223
224  var link = document.createElement('link');
225  link.rel = 'canonical';
226  link.href = canonicalURL;
227
228  document.head.appendChild(link);
229})();
230</script>
230
231
232<!-- Google tag (gtag.js) -->
vendor: 65 bytes, lines 232-233
232
233<script async src="https://www.googletagmanager.com/gtag/js?id=
233AW-18398694871
vendor: 13 bytes, line 233
233"></script>
234<script>
235  
vendor: 138 bytes, lines 235-239
235window.dataLayer = window.dataLayer || [];
236  function gtag(){dataLayer.push(arguments);}
237  gtag('js', new Date());
238
239  gtag('config', '
239AW-18398694871
vendor: 5 bytes, line 239
239');
240</script>
240
241
242 <!-- Google Tag Manager -->
243<script>
vendor: 331 bytes, lines 243-247
243(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
244new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
245j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
246'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
247})(window,document,'script','dataLayer','
247GTM-W8L44PJ6
vendor: 3 bytes, line 247
247');
247</script>
247
248<!-- End Google Tag Manager -->
249<!-- end of su-meta snippet -->
250
251
252<!-- start of novus-head snippet -->
253<!-- JavaScript Bundle with Popper -->
254<script defer src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.8/js/bootstrap.bundle.min.js" integrity="sha512-HvOjJrdwNpDbkGJIG2ZNqDlVqMo77qbs4Me4cah0HoDrfhrbA+8SBlZn1KrvAQw7cILLPFJvdwIgphzQmMm+Pw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
vendor: 2 bytes, line 254
254
255<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
255
256<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css" integrity="sha512-2SwdPD6INVrV/lHTZbO2nodKhrnDdJK9/kg2XD1r9uGqPo1cUbujc+IYdlYdEErWNu69gVcYgdxlmVmzTWnetw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
257
258<!-- Self‑hosted fonts -->
259<style>
260/* Lato Light — Weight 300 */
261@font-face {
262  font-family: "Lato";
263  font-style: normal;
264  font-weight: 300;
265  font-display: swap;
266  src: url("https://keelesu.com/assets/site_resources/Lato-Light.woff2") format("woff2");
267}
268
269/* League Spartan Bold — Weight 700 
270@font-face {
271  font-family: "League Spartan";
272  font-style: normal;
273  font-weight: 700;
274  font-display: swap;
275  src: url("https://keelesu.com/assets/site_resources/league-spartan-700.woff2") format("woff2");
276}
277
278/* League Spartan Bold — Weight 700 */
279@font-face {
280  font-family: "League Spartan";
281  font-style: normal;
282  font-weight: 600;
283  font-display: swap;
284  src: url("https://keelesu.com/assets/site_resources/Spartan-Bold.ttf") format("ttf");
285}
286</style>
287
288
289
290
291<script>
292  (function() {
293    const canonicalLink = document.createElement('link');
294    canonicalLink.rel = 'canonical';
295    canonicalLink.href = 'https://keelesu.com' + window.location.pathname;
296    document.head.appendChild(canonicalLink);
297  })();
298</script>
298
299<!-- end of novus-head snippet -->
300
301<link href="//static-uk.ukmsl.net/8.90/skins/Controls/Breadcrumb.css" rel="stylesheet" type="text/css" media="all" />
302<link href="//static-uk.ukmsl.net/8.90/skins/Controls/BasketLink.css" rel="stylesheet" type="text/css" media="all" />
303<link href="//static-uk.ukmsl.net/8.90/skins/Modules/Blogs/Default.css" rel="stylesheet" type="text/css" media="all" />
304<link href="/stylesheet/novus/core.css?v=1405" rel="stylesheet" type="text/css" />
305<link href="/stylesheet/novus/navigation.css?v=380" rel="stylesheet" type="text/css" />
306<link href="/stylesheet/novus/bootstrap.css?v=152" rel="stylesheet" type="text/css" />
307<link href="/stylesheet/novus/core-2026.css?v=82" rel="stylesheet" type="text/css" />
308<link href="/pagestylesheet/yourunion/electedofficers/blogs/ddofficer/styles.css?v=22" rel="stylesheet" type="text/css" media="all" /><link rel="alternate" type="application/rss+xml" title="DDOfficer" href="https://keelesu.com/blogs/rss/DDOfficer/" /><!-- Global site tag (gtag.js) - Google Analytics -->
vendor: 65 bytes, lines 308-309
308
309<script async src="https://www.googletagmanager.com/gtag/js?id=
309G-6L5N1C41XV
vendor: 13 bytes, line 309
309"></script>
310<script>
311	
vendor: 133 bytes, lines 311-314
311window.dataLayer = window.dataLayer || [];
312	function gtag(){dataLayer.push(arguments);}
313	gtag('js', new Date());
314	gtag('config', '
314G-6L5N1C41XV
vendor: 5 bytes, line 314
314');
315</script>
315
316<link href="https://ajax.aspnetcdn.com/ajax/act/16_1_1/Content/AjaxControlToolkit/Styles/Backgrounds.min.css" type="text/css" rel="stylesheet" /></head>
317<body id="msl">
318    <form method="post" action="./" id="aspnetForm">
319<div class="aspNetHidden">
320<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
321<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
322<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="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" />
323</div>
324
325<script type="text/javascript">
326//<![CDATA[
327var theForm = document.forms['aspnetForm'];
328if (!theForm) {
329    theForm = document.aspnetForm;
330}
331function __doPostBack(eventTarget, eventArgument) {
332    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
333        theForm.__EVENTTARGET.value = eventTarget;
334        theForm.__EVENTARGUMENT.value = eventArgument;
335        theForm.submit();
336    }
337}
338//]]>
339</script>
339
340
341
342<script src="https://ajax.aspnetcdn.com/ajax/4.6/1/WebForms.js" type="text/javascript"></script>
vendor: 2 bytes, line 342
342
343<script type="text/javascript">
344//<![CDATA[
345window.WebForm_PostBackOptions||document.write('
345<script type="text/javascript" src="/WebResource.axd?d=pynGkmcFUV13He1Qd6_TZA5Pm6HoQodZMTRqDRmkRQVgWn7tOgQlDkJJRuri60lphrOTNQ2&amp;t=639190869332169432"><\/script>');//]]>
346</script>
346
347
348
349
350<script type="text/javascript">
351//<![CDATA[
352var __cultureInfo = {"name":"en-GB","numberFormat":{"CurrencyDecimalDigits":2,"CurrencyDecimalSeparator":".","IsReadOnly":true,"CurrencyGroupSizes":[3],"NumberGroupSizes":[3],"PercentGroupSizes":[3],"CurrencyGroupSeparator":",","CurrencySymbol":"£","NaNSymbol":"NaN","CurrencyNegativePattern":1,"NumberNegativePattern":1,"PercentPositivePattern":1,"PercentNegativePattern":1,"NegativeInfinitySymbol":"-∞","NegativeSign":"-","NumberDecimalDigits":2,"NumberDecimalSeparator":".","NumberGroupSeparator":",","CurrencyPositivePattern":0,"PositiveInfinitySymbol":"∞","PositiveSign":"+","PercentDecimalDigits":2,"PercentDecimalSeparator":".","PercentGroupSeparator":",","PercentSymbol":"%","PerMilleSymbol":"‰","NativeDigits":["0","1","2","3","4","5","6","7","8","9"],"DigitSubstitution":1},"dateTimeFormat":{"AMDesignator":"AM","Calendar":{"MinSupportedDateTime":"\/Date(-62135596800000)\/","MaxSupportedDateTime":"\/Date(253402300799999)\/","AlgorithmType":1,"CalendarType":1,"Eras":[1],"TwoDigitYearMax":2049,"IsReadOnly":true},"DateSeparator":"/","FirstDayOfWeek":1,"CalendarWeekRule":2,"FullDateTimePattern":"dd MMMM yyyy HH:mm:ss","LongDatePattern":"dd MMMM yyyy","LongTimePattern":"HH:mm:ss","MonthDayPattern":"d MMMM","PMDesignator":"PM","RFC1123Pattern":"ddd, dd MMM yyyy HH\u0027:\u0027mm\u0027:\u0027ss \u0027GMT\u0027","ShortDatePattern":"dd/MM/yyyy","ShortTimePattern":"HH:mm","SortableDateTimePattern":"yyyy\u0027-\u0027MM\u0027-\u0027dd\u0027T\u0027HH\u0027:\u0027mm\u0027:\u0027ss","TimeSeparator":":","UniversalSortableDateTimePattern":"yyyy\u0027-\u0027MM\u0027-\u0027dd HH\u0027:\u0027mm\u0027:\u0027ss\u0027Z\u0027","YearMonthPattern":"MMMM yyyy","AbbreviatedDayNames":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"ShortestDayNames":["Su","Mo","Tu","We","Th","Fr","Sa"],"DayNames":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"AbbreviatedMonthNames":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",""],"MonthNames":["January","February","March","April","May","June","July","August","September","October","November","December",""],"IsReadOnly":true,"NativeCalendarName":"Gregorian Calendar","AbbreviatedMonthGenitiveNames":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",""],"MonthGenitiveNames":["January","February","March","April","May","June","July","August","September","October","November","December",""]},"eras":[1,"A.D.",null,0]};//]]>
353</script>
353
354
355<script src="https://ajax.aspnetcdn.com/ajax/4.6/1/MicrosoftAjax.js" type="text/javascript"></script>
vendor: 2 bytes, line 355
355
356<script type="text/javascript">
357//<![CDATA[
358(window.Sys && Sys._Application && Sys.Observer)||document.write('
358<script type="text/javascript" src="/ScriptResource.axd?d=NJmAwtEo3Ipnlaxl6CMhvl6DVv6mN-f_T9GleXprYSdJat24ORSRp2MgHzKTv7RMDyjpmNp17kiLYmqNfTjOiH9ZwxJObGjuiB_78QzmIFo3Ld4bu-KqIXFacyxI7uv3b6pZYUkoIdYqrIdUk5FZxvfOUcU1&t=ffffffffbec1863d"><\/script>');//]]>
359</script>
359
360
361<script src="https://ajax.aspnetcdn.com/ajax/4.6/1/MicrosoftAjaxWebForms.js" type="text/javascript"></script>
vendor: 2 bytes, line 361
361
362<script type="text/javascript">
363//<![CDATA[
364(window.Sys && Sys.WebForms)||document.write('
364<script type="text/javascript" src="/ScriptResource.axd?d=dwY9oWetJoJoVpgL6Zq8OD0U5mUkqMO8C1rKJavZtjUNmyiUn5yn5Q5faVPjJjfK5g40WTCxLeZxWbrkdd5QwCtfh1f5-qqjMpEsCSjGTZF0ygktRjoYsDEZlkO91nN0JfonM1IFsswLnVxGcfk9jAVQXU01&t=ffffffffbec1863d"><\/script>');//]]>
365</script>
365
366
367<div class="aspNetHidden">
368
369	<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="CA0B0334" />
370	<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="J6sNVfsC5YbNE0GLZ8ILK8Z8qBKg689vl7D887ybT+YiqVF3RZ51FytJis5MXSiyGjvjfmMaqsNxKgNRdf6KfAEfNJdyXPs2VOzkcO9uUwluOX2iAVZOhRn57O/jbbLt+LazHxiwrC6D9MUcSrrFPOSZgvo=" />
371</div>
372
373        
374	
374<script id="ctl00_commonjs" type="text/javascript" src="//static-uk.ukmsl.net/8.90/scripts/common.js"></script>
374
375        
375<script type="text/javascript" src="/pagestylesheet/yourunion/electedofficers/blogs/ddofficer/scripts.js?v=22"></script>
375
376
377
378        
379
380        
381
382        <div id="ctl00_pnlCatchEnter" class="CatchEnter" onkeypress="javascript:return WebForm_FireDefaultButton(event, &#39;ctl00_btnCatchEnter&#39;)">
383	
384            <input type="submit" name="ctl00$btnCatchEnter" value="" onclick="javascript:return false;" id="ctl00_btnCatchEnter" style="display:none;" />
385        
386</div>
387
388        
388<script type="text/javascript">
389//<![CDATA[
390Sys.WebForms.PageRequestManager._initialize('ctl00$ctl04', 'aspnetForm', [], [], [], 90, 'ctl00');
391//]]>
392</script>
392
393
394
395        <div id="skin_novus" class="page_yourunion page_electedofficers page_blogs">
396        
397<!-- start of novus-header-redesign snippet -->
398<header class="slim no-padding">
399    <div class="container">
400        <div class="row">
401            <div class="col-sm-4 hidden-sm-down branding no-padding ">
402                <a href="/"><img src="https://keelesu.com/stylesheet/Brand/navbar-logo.png" alt="KeeleSU Logo" URL='/' width="120" height="85"></a>
403                <a class="toggle-left dsk-navigation-toggle" id="navMenu" href="https://keelesu.com/" aria-expanded="false" aria-label="Open menu">
404                    <i class="nav-menu-icon fa-solid fa-bars" aria-hidden="true"></i>
405                    <span class="nav-menu-label">Menu</span>
406                </a>
407
408            </div>
409            <div class="controls col-12 col-md-8 no-padding">
410                <div id="search-form" class="search-form d-none">
411                    
412<div id="search">
413    <div role="search" id="site-search" class="mslwidget">
414	<div id="ctl00_search_pnlSearch" onkeypress="javascript:return WebForm_FireDefaultButton(event, &#39;ctl00_search_btnSubmit&#39;)">
415	
416		<label for="ctl00_search_txtSearchStr" id="ctl00_search_lblSearch" class="msl-visually-hidden">Search</label>
417	    <input name="ctl00$search$txtSearchStr" type="text" id="ctl00_search_txtSearchStr" class="textbox" placeholder="Search text..." />
418	    
419	    <input type="submit" name="ctl00$search$btnSubmit" value="Search" id="ctl00_search_btnSubmit" class="button" />
420	
421</div>
422	</div>
423</div>
424</MSL:search>
425                </div>
426                <div id="login-controls">
427                    <a id="ctl00_ctl31_lnkLogin" class="msl-loginbutton msl-loggedout " href="/login/">Log in</a>
428</MSL:Loginbutton>
429                </div>
430                <div class="admin-links desktop-admin-links">
431                    <ul class="nav-icons icons">
432                        <li>
433                            
434
435<div id="msl-basket-summary">
436    <a title="Review Basket" class="msl-basket-link" href="/shop/basket/">Basket</a>
437	<div class="msl-basket-summary-items">   
438        
439            <div class="msl-basket-itemcount-container">
440                
441                    <span class="msl-basket-noitems-text"></span>
442                
443    		        <div class="msl-basket-itemcount">0</div> 
444                
445            </div>
446        
447        
448
449        
450
451	</div> 
452</div></MSL:BasketLink>
453                            <div class="hidden-xl-down">
454                            </div>
455                        </li>
456                        <!-- CHANGED: was class="fa-solid fa-user"aria-hidden="true" - missing space
457                             meant the class and aria-hidden attributes ran together. Harmless in
458                             most browsers' lenient parsing, but invalid HTML; fixed the spacing. -->
459                        <li class="profile"><a href="https://keelesu.com/profile/"><i class="fa-solid fa-user" aria-hidden="true"></i><span class="hidden-xl-down">My Account</span></a></li>
460                        <li class="admin-container">
461                            <a href="https://keelesu.com/admin/" class="notext" id="admin-trigger"><i class="fas fa-cog" aria-hidden="true"></i><span class="hidden-xl-down">Admin Panel</span></a>
462
463                        </li>
464                        <li> <a class="searchbar" role="button" aria-label="Site Search" href="https://keelesu.com/search/"> <i class="fas fa-search fa-inverse" aria-hidden="true"></i><span class="hidden-xl-down">Site Search</span> </a> </li>
465                    </ul>
466                                                <div class="dropdown-menu">
467                                </MSL:ControlPanel>
468                                </MSL:Admin>
469                            </div>
470                </div>
471            </div>
472        </div>
473    </div>
474    <div class="container mainnav dsk-nav-c">
475        <div class="row">
476            <div class="col-xl-12">
477                </div>
478                  <div class="mobile-admin-links">
479                     <div id="login-controls">
480                    <a id="ctl00_ctl37_lnkLogin" class="msl-loginbutton msl-loggedout " href="/login/">Log in</a>
481</MSL:Loginbutton>
481
482                </div>
483</div>
484                  <div class="admin-links mobile-admin-links">
485                    <ul class="nav-icons icons">
486                        <li>
487                            
488
489<div id="msl-basket-summary">
490    <a title="Review Basket" class="msl-basket-link" href="/shop/basket/">Basket</a>
491	<div class="msl-basket-summary-items">   
492        
493            <div class="msl-basket-itemcount-container">
494                
495                    <span class="msl-basket-noitems-text"></span>
496                
497    		        <div class="msl-basket-itemcount">0</div> 
498                
499            </div>
500        
501        
502
503        
504
505	</div> 
506</div></MSL:BasketLink>
507                            <div class="hidden-xl-down">
508                            </div>
509                        </li>
510                        <!-- CHANGED: was class="fa-solid fa-user"aria-hidden="true" - missing space
511                             meant the class and aria-hidden attributes ran together. Harmless in
512                             most browsers' lenient parsing, but invalid HTML; fixed the spacing. -->
513                        <li class="profile"><a href="https://keelesu.com/profile/"><i class="fa-solid fa-user" aria-hidden="true"></i><span class="hidden-xl-down">My Account</span></a></li>
514                        <li class="admin-container">
515                            <a href="https://keelesu.com/admin/" class="notext" id="admin-trigger"><i class="fas fa-cog" aria-hidden="true"></i><span class="hidden-xl-down">Admin Panel</span></a>
516
517                        </li>
518                        <li> <a class="searchbar" role="button" aria-label="Site Search" href="https://keelesu.com/search/"> <i class="fas fa-search fa-inverse" aria-hidden="true"></i><span class="hidden-xl-down">Site Search</span> </a> </li>
519                    </ul>
520                                                <div class="dropdown-menu">
521                                </MSL:ControlPanel>
522                                </MSL:Admin>
523                            </div>
524                </div>
525                <div aria-label="Main Navigation" id="topnav" class="mslwidget dsk-nav">
526<ul class="msl_navbar">	<li><a href="/whatson/" class="msl-itemhassubnav"><span class="nav-text">Events and Gigs</span></a>
527<ul class="level_1 subnav_nav_whatson_">		<li><a href="https://keelesu.com/gigs/" class="nav_whatson_gigs_">Public Events &amp; Gigs - Open to Everyone</a></li>
528		<li><a href="/whatson/venueinfo/" class="nav_whatson_venueinfo_">Venue Info</a></li>
529</ul>
530</li>
531	<li><a href="/yourunion/" class="current msl-itemhassubnav"><span class="nav-text">Student Voice</span></a>
532<ul class="level_1 subnav_nav_yourunion_">		<li><a href="/yourunion/campaigns/" class="nav_yourunion_campaigns_">Campaigns</a></li>
533		<li><a href="/yourunion/elections/" class="nav_yourunion_elections_">Elections</a></li>
534		<li><a href="/yourunion/ideas/" class="nav_yourunion_ideas_">Have Your Say - Your Ideas</a></li>
535		<li><a href="/yourunion/networks/" class="nav_yourunion_networks_">Student Networks</a></li>
536		<li><a href="/yourunion/uniondelegates/" class="nav_yourunion_uniondelegates_">Union Delegates</a></li>
537		<li><a href="/yourunion/voicereps/" class="nav_yourunion_voicereps_">Voice Reps</a></li>
538		<li><a href="/yourunion/electedofficers/" class="nav_yourunion_electedofficers_ current">Your Current Elected Officers</a></li>
539</ul>
540</li>
541	<li><a href="/advice/" class="msl-itemhassubnav"><span class="nav-text">Advice and Support</span></a>
542<ul class="level_1 subnav_nav_advice_">		<li><a href="/advice/aboutask/" class="nav_advice_aboutask_">About ASK</a></li>
543		<li><a href="/advice/academic/" class="nav_advice_academic_">Academic</a></li>
544		<li><a href="/advice/complaints/" class="nav_advice_complaints_">Complaints</a></li>
545		<li><a href="/advice/discipline/" class="nav_advice_discipline_">Discipline</a></li>
546		<li><a href="/advice/employment/" class="nav_advice_employment_">Employment</a></li>
547		<li><a href="/advice/family/" class="nav_advice_family_">Family</a></li>
548		<li><a href="/advice/graduating/" class="nav_advice_graduating_">Graduate Guide</a></li>
549		<li><a href="/advice/accommodation/" class="nav_advice_accommodation_">Housing</a></li>
550		<li><a href="/advice/international/" class="nav_advice_international_">International Students</a></li>
551		<li><a href="/advice/legal/" class="nav_advice_legal_">Legal</a></li>
552		<li><a href="/advice/finance/" class="nav_advice_finance_">Money</a></li>
553		<li><a href="/advice/wellbeing/" class="nav_advice_wellbeing_">Wellbeing</a></li>
554</ul>
555</li>
556	<li><a href="/activities/" class="msl-itemhassubnav"><span class="nav-text">Get Involved</span></a>
557<ul class="level_1 subnav_nav_activities_">		<li><a href="/activities/clubs-societies/" class="nav_activities_clubs-societies_">Societies</a></li>
558		<li><a href="/activities/au/" class="nav_activities_au_">Sport Clubs</a></li>
559		<li><a href="/activities/volunteering/" class="nav_activities_volunteering_">Volunteering</a></li>
560</ul>
561</li>
562	<li><a href="/shopsandservices/" class="msl-itemhassubnav"><span class="nav-text">Shops and Services</span></a>
563<ul class="level_1 subnav_nav_shopsandservices_">		<li><a href="/shopsandservices/bookinghub/" class="nav_shopsandservices_bookinghub_">Booking Hub</a></li>
564		<li><a href="/shopsandservices/printshop/" class="nav_shopsandservices_printshop_">Keele Print House</a></li>
565		<li><a href="/shopsandservices/vehiclehire/" class="nav_shopsandservices_vehiclehire_">Minibus Bookings</a></li>
566		<li><a href="/shopsandservices/shop/" class="nav_shopsandservices_shop_">Online Shop</a></li>
567		<li><a href="/shopsandservices/student-discounts/" class="nav_shopsandservices_student-discounts_">Student Discounts</a></li>
568		<li><a href="/shopsandservices/venues/" class="nav_shopsandservices_venues_">Venues &amp; Outlets</a></li>
569</ul>
570</li>
571	<li><a href="/yoursu/" class="msl-itemhassubnav"><span class="nav-text">Your Union</span></a>
572<ul class="level_1 subnav_nav_yoursu_">		<li><a href="/yoursu/aboutus/" class="nav_yoursu_aboutus_">About your SU</a></li>
573		<li><a href="/yoursu/contact/" class="nav_yoursu_contact_">Contact Us</a></li>
574		<li><a href="/yoursu/feedback/" class="nav_yoursu_feedback_">Feedback &amp; Complaints</a></li>
575		<li><a href="/yoursu/sustainability/" class="nav_yoursu_sustainability_">Sustainability &amp; Environmental Responsibility</a></li>
576		<li><a href="https://jobs.keelesu.com" class="nav_yoursu_workwithus_">Work with Us</a></li>
577		<li><a href="/yoursu/advertise/" class="nav_yoursu_advertise_">Advertise with us!</a></li>
578</ul>
579</li>
580	<li><a href="/freshers/" class="fresherstab"><span class="nav-text">
580Freshers 2026 &#127881;</span></a></li>
581</ul>
582
583</div></MSL:Navigation>
584              </div>
585            <!--end 12-->
586        </div>
587        <!--end row-->
588    </div>
589</header>
590<div class="adminmenu">
591    <div class="dropdown-menu">
592        </MSL:ControlPanel>
593        </MSL:Admin>
594        <!-- Mobile copy of admin links so MSL links appear inside the nav pop-up -->
595        <div class="admin-links mobile-admin-links">
596            <ul class="nav-icons icons">
597                <li>
598                    
599
600<div id="msl-basket-summary">
601    <a title="Review Basket" class="msl-basket-link" href="/shop/basket/">Basket</a>
602	<div class="msl-basket-summary-items">   
603        
604            <div class="msl-basket-itemcount-container">
605                
606                    <span class="msl-basket-noitems-text"></span>
607                
608    		        <div class="msl-basket-itemcount">0</div> 
609                
610            </div>
611        
612        
613
614        
615
616	</div> 
617</div></MSL:BasketLink>
618                </li>
619                <li class="profile"><a href="https://keelesu.com/profile/"><i class="fa-solid fa-user" aria-hidden="true"></i><span>My Account</span></a></li>
620                <li class="admin-container"><a href="https://keelesu.com/admin/" class="notext" id="admin-trigger-mobile"><i class="fas fa-cog" aria-hidden="true"></i><span>Admin Panel</span></a></li>
621                <li><a class="searchbar" role="button" aria-label="Site Search" href="https://keelesu.com/search/"><i class="fas fa-search fa-inverse" aria-hidden="true"></i><span>Site Search</span></a></li>
622            </ul>
623        </div>
624    </div>
625</div>
626<!-- feedback form and button  -->
627<!--
628<iframe id="feedbackForm" width="640px" height="480px" src="https://forms.office.com/Pages/ResponsePage.aspx?id=7vO7K2i2-U2wY1mJRcPUZnsNe7WejyZOv7GKwMl3GbdUMVVKMDNHNVpPSVJIQVVFT0Q5NjZHRjRLSS4u&embed=true" frameborder="0" marginwidth="0" marginheight="0" style="border: none; max-width:100%; max-height:100vh" allowfullscreen=""> </iframe>
629<div id="FBBS" class="row">
630<div id="fbButton" onclick="formToggle()">How did we do?<br />Give your Feedback here!</div>
631<div id="closeFB" onclick="hideButton()">&#x2716;</div>
632</div>-->
633<script defer>
634  document.addEventListener("DOMContentLoaded", function () {
635    let searchVisible = false;
636    const searchForm = document.getElementById("search-form");
637    const searchBars = document.querySelectorAll("a.searchbar");
638    const navMenu = document.getElementById("navMenu");
639
640    function toggleSearch() {
641      if (!searchForm) return;
642      if (!searchVisible) {
643        searchForm.classList.remove("d-none");
644        searchForm.scrollIntoView({ behavior: "smooth" });
645        searchVisible = true;
646      } else {
647        searchForm.classList.add("d-none");
648        searchVisible = false;
649      }
650    }
651
652    function hideSearch() {
653      if (searchVisible && searchForm) {
654        searchForm.classList.add("d-none");
655        searchVisible = false;
656      }
657    }
658
659    // Keep the mobile search links as real navigation to the search page.
660    // Desktop still opens the inline search form.
661    if (searchBars && searchBars.length) {
662      searchBars.forEach(function (searchBar) {
663        searchBar.addEventListener("click", function (e) {
664          if (window.innerWidth <= 767) return;
665          e.preventDefault();
666          toggleSearch();
667        });
668      });
669    }
670
671    if (navMenu) {
672      const navMenuIcon = navMenu.querySelector(".nav-menu-icon");
673      const navMenuLabel = navMenu.querySelector(".nav-menu-label");
674      const mainNav = document.querySelector(".mainnav");
675
676      function setNavMenuState(isOpen) {
677        navMenu.classList.toggle("is-open", isOpen);
678        navMenu.setAttribute("aria-expanded", String(isOpen));
679        navMenu.setAttribute("aria-label", isOpen ? "Close menu" : "Open menu");
680
681        if (navMenuIcon) {
682          navMenuIcon.classList.remove("fa-bars", "fa-xmark");
683          navMenuIcon.classList.add(isOpen ? "fa-xmark" : "fa-bars");
684        }
685
686        if (navMenuLabel) {
687          navMenuLabel.textContent = isOpen ? "Close" : "Menu";
688        }
689
690        if (mainNav) {
691          mainNav.classList.toggle("open", isOpen);
692          mainNav.style.display = isOpen ? "block" : "none";
693        }
694      }
695
696      setNavMenuState(false);
697
698      navMenu.addEventListener("click", function (e) {
699        e.preventDefault();
700        const isOpen = navMenu.classList.toggle("is-open");
701        setNavMenuState(isOpen);
702        hideSearch();
703        // also close admin menus when opening nav
704        closeAllAdmin();
705      });
706    }
707
708    // Admin menu handling (desktop and mobile)
709    function toggleAdminMenu(trigger) {
710      const container = trigger.closest(".admin-links") || document.querySelector('.adminmenu');
711      if (!container) return;
712      const dropdown = container.querySelector(".dropdown-menu");
713      if (!dropdown) return;
714      const isOpen = dropdown.classList.contains("show");
715      closeAllAdmin();
716      if (!isOpen) {
717        dropdown.classList.add("show");
718      }
719    }
720
721    function closeAllAdmin() {
722      document.querySelectorAll(".dropdown-menu").forEach(function (d) {
723        d.classList.remove("show");
724      });
725    }
726
727    // Attach handlers to admin triggers (covers #admin-trigger, #admin-trigger-mobile and any .admin-container anchors)
728    const adminTriggers = Array.from(document.querySelectorAll("a#admin-trigger, a#admin-trigger-mobile, .admin-container > a"));
729    adminTriggers.forEach(function (t) {
730      t.addEventListener("click", function (e) {
731        e.preventDefault();
732        hideSearch();
733        toggleAdminMenu(t);
734      });
735    });
736
737    // Close menus/search when clicking outside
738    document.addEventListener("click", function (e) {
739      const clickedInsideAdmin = e.target.closest(".admin-links, .adminmenu, a#admin-trigger, a#admin-trigger-mobile");
740      const clickedSearch = e.target.closest("#search-form, a.searchbar");
741      if (!clickedInsideAdmin) {
742        closeAllAdmin();
743      }
744      if (!clickedSearch) {
745        hideSearch();
746      }
747    });
748
749    // Close on Escape key
750    document.addEventListener("keydown", function (e) {
751      if (e.key === "Escape") {
752        hideSearch();
753        closeAllAdmin();
754      }
755    });
756  });
757</script>
757
758
759<script>
760document.addEventListener("DOMContentLoaded", function () {
761    const triggers = document.querySelectorAll(
762        "#admin-trigger, #admin-trigger-mobile"
763    );
764
765    const adminMenu = document.querySelector(".adminmenu");
766    const dropdown = adminMenu?.querySelector(".dropdown-menu");
767
768    if (!adminMenu || !dropdown) return;
769
770    triggers.forEach(trigger => {
771        trigger.addEventListener("click", function (e) {
772            if (window.innerWidth > 767) return;
773
774            e.preventDefault();
775
776            const isHidden =
777                adminMenu.style.display === "none" ||
778                adminMenu.style.display === "";
779
780            if (isHidden) {
781                adminMenu.style.display = "block";
782                dropdown.style.display = "contents";
783            } else {
784                adminMenu.style.display = "none";
785                dropdown.style.display = "none";
786            }
787        });
788    });
789});
790</script>
790
791<!-- end of novus-header-redesign snippet -->
792
793<div class="container-fluid" role="main">
794  <div class="row">
795    <div class="col-xl-12 no-padding">
796	        <section class="main">
797		        <div class="container no-padding">
798            		<div class="wht-container">
799      					  <div class="row">
800                               		<div class="col-xl-12">
801        					<div id="title-section">
802          						<div class="mslwidget">
803Officer Blogs
804</div>
805        					</div>
806        					<div class="row breadcrumbs"><div class="span12">
807<nav id="breadcrumb" class="msl-breadcrumb" aria-label="Breadcrumb">
808
809    <ul class="breadcrumb"><li><a href="/yourunion/">Student Voice</a><span class="msl-breadcrumb-separator" aria-hidden="true">&gt;</span></li><li><a href="/yourunion/electedofficers/">Your Current Elected Officers</a><span class="msl-breadcrumb-separator" aria-hidden="true">&gt;</span></li><li class="current-page" aria-current="page"><span>Development &amp;amp; Democracy Officer Blog</span></li></ul>
810
811</nav></div></div>
812				                <div class="row">
813                               		<div class="col-xl-12">
814      						            
815        <p><a href="https://keelesu.com/edit/page/widget/?page_name=/yourunion/electedofficers/blogs/&amp;control_name=blog" title="Edit widget settings"><div class="mslwidget">
816
817<div class="msl_blog msl_blog_posts">
818	
819
820	<h1><a href="/yourunion/electedofficers/blogs/DDOfficer/">Development &amp; Democracy Officer Blog</a></h1>
821	
822	<div class="msl_blog_tools">
823		
824		<ul>
825			
826			
827			<li id="ctl00_blog_liRss"><a id="ctl00_blog_lnkRSS" class="msl-icon msl_rss" href="/blogs/rss/DDOfficer/">RSS</a></li>
828		</ul>
829	
830	</div>
831
832	<div class="msl_blog_image">
833		
834		<img src="/asset/Blog/1/Benjamin-Buckley-Wain-Keele-SU-Officer(1)%20(1).jpg?thumbnail_width=200&amp;thumbnail_height=200" alt="" />		
835	
836	</div>
837
838    <div class="msl_blog_description">
839        <p>Hello!! I am Benjamin, and I&nbsp;am your elected Development and Democracy Officer.&nbsp;</p>
840
841<p>I started my Studies here at Keele in 2024. I am a second-year Law student with&nbsp;my&nbsp;full degree title hopefully being; Law with Professional Legal Practice with a Placement Year with an&nbsp;Understanding of British Sign Language... A mouthful I know. I&nbsp;have&nbsp;been a student ambassador for my academic area and a&nbsp;Voice Rep for my Course.&nbsp;I also volunteered in Keele University&#39;s Legal Clinic as a student legal advisor.&nbsp;&nbsp;</p>
842
843<p>Outside of my academics, I used to be a Dancer. I danced in a&nbsp;variety&nbsp;of styles, with a focus&nbsp;in&nbsp;competing across the country. In college I had stopped dancing due to work, but&nbsp;i&nbsp;was still interested in performing arts, here I volunteered in theatres and partook in my college&rsquo;s reproduction of legally blonde the musical as a Technical Director and Lighting Designer. Quite possibly the best experience I have&nbsp;had in theatre. My interests are all over the place, every week I fixate on a niche subject and find myself learning everything about it.&nbsp;&nbsp;</p>
844
845<p>My favourite part about campus is Keele woods.&nbsp;&nbsp;There is no place in&nbsp;Keele woods that I do not know.&nbsp;And my favourite fact is that co-op memberships cost &pound;1 which goes directly back to the student union and gets you member prices on products!!!&nbsp;</p>
846
847<p>You can talk to me about anything,&nbsp;however my role&rsquo;s&nbsp;main focus&nbsp;are:&nbsp;&nbsp;</p>
848
849<ul role="list">
850	<li aria-setsize="-1" data-aria-level="1" data-aria-posinset="1" data-font="Symbol" data-leveltext="?" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;?&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-listid="1" role="listitem">
851	<p>Campus Issues&nbsp;and getting to campus&nbsp;</p>
852	</li>
853</ul>
854
855<ul role="list">
856	<li aria-setsize="-1" data-aria-level="1" data-aria-posinset="2" data-font="Symbol" data-leveltext="?" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;?&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-listid="1" role="listitem">
857	<p>Campaign Networks&nbsp;</p>
858	</li>
859</ul>
860
861<ul role="list">
862	<li aria-setsize="-1" data-aria-level="1" data-aria-posinset="3" data-font="Symbol" data-leveltext="?" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;?&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-listid="1" role="listitem">
863	<p>Any suggestion/development&nbsp;regarding&nbsp;the SU and/or the University&nbsp;</p>
864	</li>
865</ul>
866
867<ul role="list">
868	<li aria-setsize="-1" data-aria-level="1" data-aria-posinset="4" data-font="Symbol" data-leveltext="?" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;?&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-listid="1" role="listitem">
869	<p>Democracy, Voting, Elections and why we do what we do&nbsp;</p>
870	</li>
871</ul>
872
873<ul role="list">
874	<li aria-setsize="-1" data-aria-level="1" data-aria-posinset="5" data-font="Symbol" data-leveltext="?" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;?&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" data-listid="1" role="listitem">
875	<p>Sustainability&nbsp;</p>
876	</li>
877</ul>
878
879<p>I love helping people, cliche I know, but everything I do is in the&nbsp;interest in&nbsp;all students.&nbsp;&nbsp;</p>
880
881<p>You can contact me&nbsp;at&nbsp;<a href="mailto:[email protected]" rel="noreferrer noopener" target="_blank">[email protected]</a>&nbsp;or you can find me in the&nbsp;chatterbox!&nbsp;</p>
882
883<p>I look forward to working with you. Have a lovely day!!!&nbsp;</p>
884    </div>
885
886	
887			<div class="blog_day">Mon 02 Dec 2024</div>
888			<div class="mslwidget msl_blog_post">
889
890	<h2 class="msl_blog_post_title"><a id="ctl00_blog_rptPosts_ctl00_BlogPost1_lnkSubject" href="/yourunion/electedofficers/blogs/DDOfficer/2024/12/02/December-AGM-2024/">December AGM 2024</a></h2>
891	<div class="msl_blog_post_date">Posted on Mon 02 Dec 2024 at 15:31 </div>
892	
893	<div class="msl_blog_post_body"></div>
894    <div id="ctl00_blog_rptPosts_ctl00_BlogPost1_divCommentCount" class="msl_blog_post_comments">
895	    
896	</div>
897
898    
899	
900</div>			
901		
902	
903	
904    
905
906
907</div>
908
909</div></a></p>
910
911        
912        
913        
914        
915					                </div>
916				                </div>
917			        </div>
918		        </div>
919        	</section>
920    </div>
921  </div>
922</div>
923
924
925<!-- start of novus-footer snippet -->
926<footer>
927  <div class="container">
928    <!-- Advertisement Section -->
929    <!-- NOTE: this MSL:Advert control is the "Perks" banner I found on the live homepage
930         (asset/Advert/34/1.png) - it's the one image on the whole page NOT going through
931         MSL's resize pipeline (?thumbnail_width=...&resize_type=CropToFit) that every news/
932         event/officer image uses. That's set by whatever image is uploaded in Adverts Admin
933         for this advert slot, not by this template - re-uploading it there through the same
934         resize pipeline is the actual fix, this file has no control over it. -->
935    <div class="row" style="padding-top: 15px;">
936      <div class="col-12" style="text-align: center;">
937        <div class="mslwidget">
938<a href="/advertclick/34/" target="_blank"><img src="/asset/Advert/34/1.png" alt="International Student Identity Card. Student ID &a" /></a>
939</div>
940      </div> 
941    </div>
942
943    <!-- Footer Links -->
944    <div class="row f-links">
945      <!-- Useful Links -->
946      <div class="col-sm-4 col-xs-12 f-links-col">
947        <div class="f-links-cont">
948          <div class="f-head">Useful Links</div>
949          <div class="mslwidget footer-nav">
950<ul class="msl_navbar">	<li><a href="/yoursu/workwithus/" target="_blank"><span class="nav-text">Jobs at Keele SU</span></a></li>
951	<li><a href="/yoursu/advertise/"><span class="nav-text">Advertise</span></a></li>
952	<li><a href="/yoursu/feedback/"><span class="nav-text">Make a Complaint</span></a></li>
953	<li><a href="/tac/"><span class="nav-text">Terms &amp; Conditions</span></a></li>
954	<li><a href="/yoursu/aboutus/governance/"><span class="nav-text">Our Policies</span></a></li>
955	<li><a href="/accessibility/"><span class="nav-text">Accessibility</span></a></li>
956	<li><a href="/cookies/"><span class="nav-text">Cookies Policy</span></a></li>
957	<li><a href="/it/"><span class="nav-text">IT Support Links</span></a></li>
958	<li><a href="/accessable/" target="_blank"><span class="nav-text">Accessibility at Keele SU</span></a></li>
959	<li><a href="/system-status/"><span class="nav-text">System Status</span></a></li>
960	<li><a href="/activities/clubs-societies/committeeresources/"><span class="nav-text">Committee Resources</span></a></li>
961	<li><a href="/lostproperty/"><span class="nav-text">Lost Property</span></a></li>
962</ul>
963
964</div>
965        </div>
966      </div>
967
968      <!-- Vision, Mission, and Values -->
969      <div class="col-sm-5 col-xs-12 f-links-col">
970        <div class="f-links-cont">
971          <div class="f-head">Our Vision</div>
972          <p>Empower every student to be who they want to be and make a difference to the world.</p>
973          
974          <div class="f-head">Our Mission</div>
975          <p>Through the delivery of our quality support, activity, representation, entertainment, and value-for-money services, we will ensure that our students feel part of a community which is inclusive, where they can grow in confidence and simply be students.</p>
976          
977          <div class="f-head">Our Values</div>
978          <p>We are Global Citizens, We Challenge & Collaborate, We Unlock Potential.</p>
979        </div>
980      </div>
981
982      <!-- Contact Information and Social Media -->
983      <div class="col-sm-3 col-xs-12 f-links-col">
984        <div class="f-links-cont">
985          <div class="f-head">Contact Us</div>
986          <p>
987            Keele University Students' Union<br>
988            Keele University<br>
989            Newcastle-Under-Lyme<br>
990            Staffordshire<br>
991            ST5 5BJ<br>
992            United Kingdom
993          </p>
994          <p><i class="fas fa-phone"></i> 01782 733700</p>
995          <p><i class="fas fa-envelope"></i> <a href="mailto:[email protected]">[email protected]</a></p>
996          <p><i class="fas fa-map-marker-alt"></i> <a href="https://maps.app.goo.gl/U8Mw4fiQVAKoC1iNA/">Maps & Directions</a></p>
997        </div>
998
999        <!-- Social Media Links -->
1000        <br>
1001        <div class="f-head">Follow Us!</div>
1002        <div id="socialsFooter" class="clearfix">
1003          <ul>
1004            <!-- Facebook -->
1005            <li>
1006              <a target="_blank" href="https://www.facebook.com/keelestudentsunion/" aria-label="Facebook" tabindex="0" role="button" aria-pressed="false">
1007                <i class="fa-brands fa-facebook"></i>
1008                <span class="social-description">Facebook</span>
1009              </a>
1010            </li>
1011            <!-- Instagram -->
1012            <li>
1013              <a target="_blank" href="https://www.instagram.com/keelesu/" aria-label="Instagram" tabindex="0" role="button" aria-pressed="false">
1014                <i class="fa-brands fa-instagram"></i>
1015                <span class="social-description">Instagram</span>
1016              </a>
1017            </li>
1018            <!-- YouTube -->
1019            <li>
1020              <a target="_blank" href="https://www.youtube.com/user/keelesu/" aria-label="YouTube" tabindex="0" role="button" aria-pressed="false">
1021                <i class="fa-brands fa-youtube"></i>
1022                <span class="social-description">YouTube</span>
1023              </a>
1024            </li>
1025            <!-- LinkedIn -->
1026            <li>
1027              <a target="_blank" href="https://www.linkedin.com/company/keelesu/" aria-label="LinkedIn" tabindex="0" role="button" aria-pressed="false">
1028                <i class="fa-brands fa-linkedin"></i>
1029                <span class="social-description">LinkedIn</span>
1030              </a>
1031            </li>
1032            <!-- TikTok -->
1033            <li>
1034              <a target="_blank" href="https://www.tiktok.com/@keele_su/" aria-label="TikTok" tabindex="0" role="button" aria-pressed="false">
1035                <i class="fa-brands fa-tiktok"></i>
1036                <span class="social-description">TikTok</span>
1037              </a>
1038            </li>
1039            <!-- LinkTree -->
1040            <li>
1041              <a target="_blank" href="https://linktr.ee/keelesu/" aria-label="LinkTree" tabindex="0" role="button" aria-pressed="false">
1042                <!-- CHANGED: added loading="lazy" - this was the one footer image without it -->
1043                <img width="32" height="32" src="https://keelesu.com/stylesheet/Brand/linktree-icon.png" alt="LinkTree" loading="lazy"/>
1044                <span class="social-description">LinkTree</span>
1045              </a>
1046            </li>
1047          </ul>
1048        </div>
1049      </div>
1050    </div>
1051
1052    <!-- Download App Section -->
1053    <div class="row">
1054      <div class="col-12">
1055        <div class="f-head text-center">Download Our App</div>
1056        <p class="text-center">
1057          <a href="https://apps.apple.com/gb/app/studentlink/id1579307063/" rel="noopener noreferrer" target="_blank" aria-label="Keele SU App on the Appstore">
1058            <i class="fa-brands fa-apple fa-2xl"></i>
1059            <span class="social-description">Keele SU iOS App</span>
1060          </a>&nbsp;&nbsp;
1061          <a href="https://play.google.com/store/apps/details?id=com.ukmsl.studentlinkplus.keele" rel="noopener noreferrer" target="_blank" aria-label="Keele SU App on the Playstore">
1062            <i class="fa-brands fa-android fa-2xl"></i>
1063            <span class="social-description">Keele SU Android App</span>
1064          </a>
1065        </p>
1066      </div>
1067    </div>
1068
1069    <!-- Footer Credits -->
1070    <div class="row">
1071      <div class="col-12">
1072        <p class="msl-footer">Keele SU is a Charitable Incorporated Organisation No.1173328</p>
1073        <p class="msl-footer">
1074          <a href="https://www.ukmsl.com/" id="poweredmsl">Powered by MSL</a>
1075        </p>
1076        <p class="msl-footer">
1077          Last Updated: Thu, 03 Jul 2025 13:34:53 GMT
1078        </p>
1079      </div>
1080    </div>
1081  </div>
1082</footer>
1083
1084<!-- Popup for Voting -->
1085<!--class="hide"-->
1086<div id="popup">
1087<MSL:VoterPopup
1088  ContainerTag=""
1089  ContainerID=""
1090  ContainerCssClass=""
1091  SuppressContainer=""
1092  ElectionId="1293"
1093  VotingPeriodNotStartedText=""
1094  VotingNotStartedText="<img src='https://keelesu.com/stylesheet/novus/electionsheaderfs.jpg' alt='Elections Banner' width='100%'>
1095      <br>You haven't voted in the current Elections &#128557
1096      <br><a href='https://keelesu.com/elections/vote/1293/'>Vote Now!</a>
1097      <br>"
1098  VotingInProgressText=""
1099  VotingCompleteText=""
1100  VotingClosedText=""
1101  HideButtonText="Close"
1102/>
1103
1104  <div id="fbmllike">
1105    <div style="clear:both"></div>
1106  </div>
1107</div>
1108
1109<!-- Microsoft Clarity Analytics -->
1110<script>
1111  (function(c, l, a, r, i, t, y) {
1112    c[a] = c[a] || function() { 
1113      (c[a].q = c[a].q || []).push(arguments);
1114    };
1115    t = l.createElement(r);
1116    t.async = true;
1117    t.src = "https://www.clarity.ms/tag/" + i;
1118    y = l.getElementsByTagName(r)[0];
1119    y.parentNode.insertBefore(t, y);
1120  })(window, document, "clarity", "script", "lqptr9hbv4");
1121</script>
1121
1122
1123<!-- Chatbot Styles -->
1124<!-- NOTE: no change needed here. Earlier I flagged this chatbot as a likely big contributor
1125     to page weight, going only off the fact that it existed. Having now seen the actual
1126     implementation: the iframe ships with loading="lazy" AND starts display:none, and the
1127     script below only flips it to display:block after a 60s timer or a manual click. A
1128     hidden, lazy iframe like this is very unlikely to be fetched during a single automated
1129     page-load measurement (the kind carbon calculators run), so this was probably already a
1130     non-issue - correcting my earlier read rather than "fixing" something that isn't broken. -->
1131<style>
1132  :root {
1133    --chat-width: 320px;
1134    --chat-height: 600px;
1135    --chat-margin: 20px;
1136    --chat-button-size: 60px;
1137  }
1138
1139  #chat-popup {
1140    position: fixed;
1141    bottom: var(--chat-margin);
1142    right: calc(var(--chat-margin) * 2);
1143    width: var(--chat-width);
1144    height: var(--chat-height);
1145    display: none;
1146    border: none;
1147    z-index: 1000;
1148  }
1149
1150  #chat-button {
1151    position: fixed;
1152    bottom: var(--chat-margin);
1153    right: var(--chat-margin);
1154    width: var(--chat-button-size);
1155    height: var(--chat-button-size);
1156    border: none;
1157    border-radius: 50%;
1158    background-color: var(--secondary-color, #65b22e);
1159    color: #fff;
1160    cursor: pointer;
1161    z-index: 1001;
1162    font-size: 1rem;
1163  }
1164
1165  .popup-container {
1166    display: none;
1167    position: fixed;
1168    top: 50%;
1169    left: 50%;
1170    transform: translate(-50%, -50%);
1171    background-color: #fff3cd;
1172    color: #856404;
1173    border: 1px solid #ffeeba;
1174    padding: 30px;
1175    border-radius: 10px;
1176    box-shadow: 0 6px 12px rgba(0,0,0,0.15);
1177    max-width: 500px;
1178    width: 90%;
1179    font-family: Arial, sans-serif;
1180    z-index: 1000;
1181    text-align: center;
1182  }
1183
1184  .popup-container h2 {
1185    margin-top: 0;
1186  }
1187
1188  .app-links a {
1189    color: #856404;
1190    text-decoration: underline;
1191    font-weight: bold;
1192  }
1193
1194  .popup-close {
1195    background-color: #856404;
1196    color: white;
1197    border: none;
1198    padding: 10px 16px;
1199    border-radius: 5px;
1200    cursor: pointer;
1201    margin-top: 15px;
1202    font-size: 1em;
1203  }
1204
1205  .popup-close:hover {
1206    background-color: #6c4f03;
1207  }
1208</style>
1209
1210<!-- Chatbot Iframe -->
1211<iframe
1212  id="chat-popup"
1213  src="https://www.chatbase.co/chatbot-iframe/KUL--w-zDPlx88ZgZl8Xh"
1214  title="Live Chat"
1215  loading="lazy"
1216></iframe>
1217
1218<!-- Chat Toggle Button -->
1219<button id="chat-button" type="button" aria-label="Open Chat">Chat</button>
1220
1221<!-- Chat Toggle Script (Vanilla JS) -->
1222<script>
1223  (function() {
1224    'use strict';
1225    
1226    function initChatToggle() {
1227      const chatButton = document.getElementById('chat-button');
1228      const chatPopup = document.getElementById('chat-popup');
1229      
1230      if (!chatButton || !chatPopup) return;
1231
1232      chatButton.addEventListener('click', function(e) {
1233        e.preventDefault();
1234        const isVisible = chatPopup.style.display === 'block';
1235        chatPopup.style.display = isVisible ? 'none' : 'block';
1236      });
1237    }
1238
1239    // Initialize when DOM is ready
1240    if (document.readyState === 'loading') {
1241      document.addEventListener('DOMContentLoaded', initChatToggle);
1242    } else {
1243      initChatToggle();
1244    }
1245  })();
1246</script>
1246
1247
1248<script>
1249window.addEventListener("load", () => {
1250  const path = window.location.pathname;
1251  const isBackend = path.includes("/admin/") || path.includes("/edit/");
1252
1253  const STORAGE_KEY = "chatPopupLastShown";
1254  const COOLDOWN_DAYS = 3;
1255
1256  // Check if popup should show
1257  function canShowPopup() {
1258    const lastShown = localStorage.getItem(STORAGE_KEY);
1259    if (!lastShown) return true;
1260
1261    const now = Date.now();
1262    const diff = now - parseInt(lastShown, 10);
1263    const cooldown = COOLDOWN_DAYS * 24 * 60 * 60 * 1000;
1264
1265    return diff > cooldown;
1266  }
1267
1268  // Save timestamp
1269  function markShown() {
1270    localStorage.setItem(STORAGE_KEY, Date.now().toString());
1271  }
1272
1273  // If admin/edit page → stop
1274  if (isBackend) {
1275    const iframe = document.getElementById("chat-popup");
1276    if (iframe) iframe.style.display = "none";
1277    return;
1278  }
1279
1280  // 🔴 If within 3 days → don't show
1281  if (!canShowPopup()) return;
1282
1283  // ✅ Show popup after 60s
1284  setTimeout(() => {
1285    const interval = setInterval(() => {
1286      const iframe = document.getElementById("chat-popup");
1287      if (iframe) {
1288        iframe.style.display = "block";
1289        iframe.click();
1290
1291        // Save that it has been shown
1292        markShown();
1293
1294        clearInterval(interval);
1295      }
1296    }, 300);
1297  }, 60000);
1298});
1299</script>
1299
1300
1301<!-- Changes Colour/Text on Chatbot Button -->
1302
1303<script>
1304document.addEventListener("DOMContentLoaded", function () {
1305  const chatPopup = document.getElementById("chat-popup");
1306  const chatButton = document.getElementById("chat-button");
1307
1308  if (!chatPopup || !chatButton) return;
1309
1310  // Store original button styles/text so we can restore them
1311  const originalText = chatButton.textContent;
1312  const originalBg = getComputedStyle(chatButton).backgroundColor;
1313  const originalColor = getComputedStyle(chatButton).color;
1314
1315  function updateChatButton() {
1316    const isVisible = getComputedStyle(chatPopup).display === "block";
1317
1318    if (isVisible) {
1319      chatButton.textContent = "Close";
1320      chatButton.style.backgroundColor = "red";
1321      chatButton.style.color = "black";
1322      chatButton.setAttribute("aria-label", "Close Chat");
1323    } else {
1324      chatButton.textContent = originalText || "Chat";
1325      chatButton.style.backgroundColor = originalBg;
1326      chatButton.style.color = originalColor;
1327      chatButton.setAttribute("aria-label", "Open Chat");
1328    }
1329  }
1330
1331  // Watch for changes to the iframe's style attribute
1332  const observer = new MutationObserver(updateChatButton);
1333  observer.observe(chatPopup, {
1334    attributes: true,
1335    attributeFilter: ["style", "class"]
1336  });
1337
1338  // Run once on load
1339  updateChatButton();
1340});
1341
1342</script>
1342
1343
1344<script>
1345// Removes empty location box from events
1346document.querySelectorAll('.location').forEach(location => {
1347    const text = location.textContent.trim();
1348
1349    if (!text) {
1350        location.style.display = 'none';
1351    }
1352});
1353</script>
1353
1354
1355<!-- Cookie Popup -->
1356<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.css" integrity="sha512-LQ97camar/lOliT/MqjcQs5kWgy6Qz/cCRzzRzUCfv0fotsCTC9ZHXaPQmJV8Xu/PVALfJZ7BDezl5lW3/qBxg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
1357<script defer src="https://cdnjs.cloudflare.com/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.js" integrity="sha512-yXXqOFjdjHNH1GND+1EO0jbvvebABpzGKD66djnUfiKlYME5HGMUJHoCaeE4D5PTG2YsSJf6dwqyUUvQvS0vaA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
vendor: 2 bytes, line 1357
1357
1358<script>
1359  (function() {
1360    'use strict';
1361    
1362    function initCookieConsent() {
1363      if (typeof window.cookieconsent === 'undefined') return;
1364      
1365      window.cookieconsent.initialise({
1366        palette: {
1367          popup: {
1368            background: "#575952"
1369          },
1370          button: {
1371            background: "#22004d"
1372          }
1373        },
1374        theme: "edgeless",
1375        content: {
1376          message: "This site uses cookies",
1377          dismiss: "Dismiss",
1378          link: "More info",
1379          href: "https://keelesu.com/cookies/"
1380        },
1381        position: "bottom-left"
1382      });
1383    }
1384
1385    window.addEventListener("load", initCookieConsent);
1386  })();
1387</script>
1387
1388
1389<!-- Accessibility Widget -->
1390<script>
1391  window.interdeal = {
1392    sitekey: "6771fa1a11958d581b731f95e0c44d43",
1393    Position: "right",
1394    domains: {
1395      js: "https://cdn.equalweb.com/",
1396      acc: "https://access.equalweb.com/"
1397    },
1398    showTooltip: true,
1399    btnStyle: {
1400      vPosition: ["92%", "20%"],
1401      scale: ["0.5", "0.5"],
1402      color: {
1403        main: "#2b0e48",
1404        second: "#ffffff"
1405      },
1406      icon: {
1407        type: 11,
1408        shape: "rounded"
1409      }
1410    }
1411  };
1412
1413  (function(doc, head, body) {
1414    'use strict';
1415    
1416    const coreCall = doc.createElement('script');
1417    coreCall.src = window.interdeal.domains.js + 'core/4.6.14/accessibility.js';
1418    coreCall.defer = true;
1419    coreCall.integrity = 'sha512-DeZBWLOEHK1CkmU3vQTNSXeENfZmhTHFmn7zzhvZCPERahpp/DTouMc1ZHOu+RAo1FTKnuKEf1NQyB76z8mU1Q==';
1420    coreCall.crossOrigin = 'anonymous';
1421    coreCall.setAttribute('data-cfasync', true);
1422    
1423    (body || head).appendChild(coreCall);
1424  })(document, document.head, document.body);
1425</script>
1425
1426
1427<!-- System Issue Popup (Vanilla JS) -->
1428<script>
1429  (function() {
1430    'use strict';
1431    
1432    function initPopup() {
1433      const popup = document.getElementById('system-issue-popup');
1434      const closeBtn = document.querySelector('.popup-close');
1435      
1436      if (!popup) return;
1437
1438      // Check if popup was already dismissed in this session
1439      const dismissed = sessionStorage.getItem('popupDismissed');
1440      
1441      if (!dismissed) {
1442        setTimeout(function() {
1443          popup.style.display = 'block';
1444        }, 1000);
1445      }
1446
1447      // Close button handler
1448      if (closeBtn) {
1449        closeBtn.addEventListener('click', function() {
1450          popup.style.display = 'none';
1451          sessionStorage.setItem('popupDismissed', 'true');
1452        });
1453      }
1454    }
1455
1456    // Initialize when DOM is ready
1457    if (document.readyState === 'loading') {
1458      document.addEventListener('DOMContentLoaded', initPopup);
1459    } else {
1460      initPopup();
1461    }
1462  })();
1463</script>
1463
1464<!-- end of novus-footer snippet -->
1465
1466<script type="text/javascript">
1467  $(document).ready(function () {
1468    
1469<!-- start of novus-scripts snippet -->
1470// Enhanced Site Script - Optimized Vanilla JavaScript
1471// Performance optimized with caching and efficient DOM operations
1472//
1473// Fixes applied in this version:
1474// 1. Moved the "accessibility cleanup / admin controls / basket buttons /
1475//    event location / referendum" block OUT of the newsItems.forEach loop.
1476//    It previously only ran once per news-scroller item (and not at all
1477//    when there were no news items) instead of once per page load.
1478// 2. Removed no-op `return false` inside a native addEventListener handler
1479//    (that only works with jQuery); replaced with explicit preventDefault.
1480// 3. Added aria-expanded updates to the nav toggle and admin trigger buttons
1481//    so assistive tech can announce expanded/collapsed state.
1482// 4. Added aria-hidden="true" to the accordion chevron icon, and aria-controls
1483//    linking the accordion title to its content panel, for consistency with
1484//    the slider's icons and proper ARIA relationships.
1485// 5. Guarded the popup auto-focus so it only steals focus when the popup is
1486//    actually visible, instead of unconditionally on every page load.
1487// 6. Removed dead/commented-out code (legacy UA sniffing comment left as-is
1488//    where still functionally relevant, but the disabled bxSlider/doubleTap
1489//    leftovers were removed).
1490
1491(function() {
1492  'use strict';
1493
1494  const $ = (selector, context = document) => context.querySelector(selector);
1495
1496  const $$ = (selector, context = document) => {
1497    return Array.from(context.querySelectorAll(selector));
1498  };
1499
1500  // Batch DOM operations
1501  const domBatch = {
1502    operations: [],
1503    add(fn) {
1504      this.operations.push(fn);
1505    },
1506    execute() {
1507      requestAnimationFrame(() => {
1508        this.operations.forEach(fn => fn());
1509        this.operations = [];
1510      });
1511    }
1512  };
1513
1514  // Double Tap To Go (optimized with event delegation where possible)
1515  function doubleTapToGo(selector) {
1516    if (!('ontouchstart' in window) &&
1517        !navigator.msMaxTouchPoints &&
1518        !navigator.userAgent.toLowerCase().match(/windows phone os 7/i)) {
1519      return;
1520    }
1521
1522    let lastTapped = null;
1523    const container = document.getElementById('topnav');
1524    if (!container) return;
1525
1526    container.addEventListener('click', function(e) {
1527      const element = e.target.closest(selector);
1528      if (element && element !== lastTapped) {
1529        e.preventDefault();
1530        lastTapped = element;
1531      }
1532    });
1533
1534    document.addEventListener('click', function(e) {
1535      if (lastTapped && !lastTapped.contains(e.target)) {
1536        lastTapped = null;
1537      }
1538    });
1539
1540    document.addEventListener('touchstart', function(e) {
1541      if (lastTapped && !lastTapped.contains(e.target)) {
1542        lastTapped = null;
1543      }
1544    }, { passive: true });
1545  }
1546
1547  // Relative time formatting (cached results)
1548  const timeCache = new Map();
1549  function relTime(dateString) {
1550    if (timeCache.has(dateString)) {
1551      return timeCache.get(dateString);
1552    }
1553
1554    const date = new Date(dateString);
1555    const now = new Date();
1556    const diff = now - date;
1557    const seconds = Math.floor(diff / 1000);
1558    const minutes = Math.floor(seconds / 60);
1559    const hours = Math.floor(minutes / 60);
1560    const days = Math.floor(hours / 24);
1561
1562    let result;
1563    if (days > 7) result = date.toLocaleDateString();
1564    else if (days > 0) result = `${days} day${days > 1 ? 's' : ''} ago`;
1565    else if (hours > 0) result = `${hours} hour${hours > 1 ? 's' : ''} ago`;
1566    else if (minutes > 0) result = `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
1567    else result = 'Just now';
1568
1569    timeCache.set(dateString, result);
1570    return result;
1571  }
1572
1573  // Main initialization (optimized with fewer DOM queries)
1574  function init() {
1575    const body = document.body;
1576    const mainNav = document.querySelector('.mainnav');
1577
1578    // Remove admin elements for logged out users (single pass)
1579    if (document.querySelector('.msl-loggedout')) {
1580      const adminSelectors = '.admin-links ul li.admin-container, #admin-trigger, .admin-links ul li.profile';
1581      $$(adminSelectors).forEach(el => el.remove());
1582    }
1583
1584    // Event delegation for navigation toggle
1585    body.addEventListener('click', function(e) {
1586      const toggle = e.target.closest('a[class*="toggle-left"]');
1587      if (toggle) {
1588        if (!mainNav.classList.contains('show-nav')) {
1589          body.classList.remove('show-admin');
1590        }
1591        mainNav.classList.toggle('show-nav');
1592        toggle.setAttribute('aria-expanded', mainNav.classList.contains('show-nav'));
1593        return;
1594      }
1595
1596      // Admin trigger
1597      const adminTrigger = e.target.closest('#admin-trigger');
1598      if (adminTrigger) {
1599        e.preventDefault();
1600        if (!body.classList.contains('show-admin')) {
1601          mainNav.classList.remove('show-nav');
1602        }
1603        body.classList.toggle('show-admin');
1604        adminTrigger.setAttribute('aria-expanded', body.classList.contains('show-admin'));
1605        return;
1606      }
1607
1608      // Shop tile clicks
1609      const shopTile = e.target.closest('.shop-cat li');
1610      if (shopTile) {
1611        const link = shopTile.querySelector('a');
1612        if (link) {
1613          e.preventDefault();
1614          window.location = link.href;
1615          return;
1616        }
1617      }
1618
1619      // Accordion clicks
1620      const accordionTitle = e.target.closest('.accordion-title');
1621      if (accordionTitle) {
1622        handleAccordion(accordionTitle);
1623      }
1624
1625      // Submenu clicks
1626      const submenuLink = e.target.closest('#topnav ul.msl_navbar li:has(ul) a');
1627      if (submenuLink) {
1628        const parent = submenuLink.parentElement;
1629        const siblings = Array.from(parent.parentElement.children).filter(el => el !== parent);
1630
1631        siblings.forEach(sib => {
1632          const openUl = sib.querySelector('ul.open');
1633          if (openUl) openUl.classList.remove('open');
1634        });
1635
1636        const firstUl = parent.querySelector('ul');
1637        if (firstUl) firstUl.classList.toggle('open');
1638      }
1639    });
1640
1641    // Enable double-tap navigation
1642    doubleTapToGo('#topnav ul.msl_navbar > li:has(ul) > a');
1643
1644    // Batch DOM manipulations
1645    const exploreTiles = $$('.explore-tiles ul li');
1646    const shopTiles = $$('.shop-cat li');
1647    const tables = $$('#main table:not([class])');
1648    const newsItems = $$('#scroller .news_item');
1649    const mslNewsItems = $$('.msl-news .msl-item');
1650    const bannerItems = $$('#banner .msl-news .msl-item');
1651
1652    // Process explore tiles
1653    exploreTiles.forEach(tile => {
1654      const link = tile.querySelector('a');
1655      if (!link) return;
1656
1657      if (!link.querySelector('.msl-imagenav-image')) {
1658        const img = document.createElement('img');
1659        img.src = 'https://keelesu.com/stylesheet/Brand/image_nav_default.png';
1660        img.alt = 'KeeleSU Branded Image Placeholder';
1661        img.width = 570;
1662        img.height = 285;
1663        img.className = 'msl-imagenav-image';
1664        link.appendChild(img);
1665      }
1666
1667      const desc = tile.querySelectorAll('.msl-imagenav-description, .msl-imagenav-title');
1668      if (desc.length > 0) {
1669        const wrapper = document.createElement('div');
1670        wrapper.className = 'explore_description';
1671        desc[0].parentNode.insertBefore(wrapper, desc[0]);
1672        desc.forEach(el => wrapper.appendChild(el));
1673
1674        const title = wrapper.querySelector('.msl-imagenav-title');
1675        const description = wrapper.querySelector('.msl-imagenav-description');
1676        if (title && description) {
1677          description.parentNode.insertBefore(title, description.nextSibling);
1678        }
1679
1680        const image = tile.querySelector('.msl-imagenav-image');
1681        if (image && wrapper) {
1682          image.parentNode.insertBefore(wrapper, image.nextSibling);
1683        }
1684      }
1685    });
1686
1687    // Process shop tiles
1688    shopTiles.forEach(tile => {
1689      const name = tile.querySelector('.msl-product-name');
1690      const price = tile.querySelector('.msl-product-price');
1691
1692      if (name && price && !name.parentElement.classList.contains('details')) {
1693        const wrapper = document.createElement('div');
1694        wrapper.className = 'details';
1695        name.parentNode.insertBefore(wrapper, name);
1696        wrapper.appendChild(name);
1697        wrapper.appendChild(price);
1698      }
1699    });
1700
1701    // Wrap tables
1702    tables.forEach(table => {
1703      table.className = 'table table-light table-bordered table-striped';
1704      const wrapper = document.createElement('div');
1705      wrapper.className = 'table-responsive';
1706      table.parentNode.insertBefore(wrapper, table);
1707      wrapper.appendChild(table);
1708    });
1709
1710    // Basket handling
1711    $$('.product_box > .btn').forEach(btn => btn.value = 'Add to Basket');
1712
1713    const basket = document.getElementById('basket');
1714    if (basket) {
1715      const basketItems = basket.querySelectorAll('dt');
1716      const itemCount = basketItems.length;
1717      const basketContainer = document.querySelector('.basket-container');
1718
1719      if (itemCount > 0 && basketContainer) {
1720        const basketCount = document.createElement('span');
1721        basketCount.className = 'basket-count';
1722        basketCount.textContent = itemCount;
1723        basketCount.setAttribute('aria-label', `${itemCount} item${itemCount > 1 ? 's' : ''} in basket`);
1724        basketContainer.style.display = '';
1725        basketContainer.classList.add('bagged');
1726        const link = basketContainer.querySelector('a');
1727        if (link) link.appendChild(basketCount);
1728      } else if (basketContainer) {
1729        basketContainer.style.display = 'none';
1730      }
1731
1732      let totalQty = 0;
1733      basket.querySelectorAll('.qty').forEach(qty => {
1734        const match = qty.textContent.match(/\d+/);
1735        if (match) {
1736          const num = parseInt(match[0], 10);
1737          if (!isNaN(num)) totalQty += num;
1738        }
1739      });
1740
1741      if (totalQty > 0) {
1742        const basketIcon = document.querySelector('.basket-icon');
1743        if (basketIcon) {
1744          const quantitySpan = document.createElement('span');
1745          quantitySpan.className = 'basket-quantity';
1746          quantitySpan.setAttribute('aria-label', `${totalQty} item${totalQty > 1 ? 's' : ''} in basket`);
1747          quantitySpan.innerHTML = `<div class="quantity-inner" aria-hidden="true">${totalQty}</div>`;
1748          basketIcon.appendChild(quantitySpan);
1749        }
1750      }
1751
1752      basketItems.forEach(dt => {
1753        const dd = dt.nextElementSibling?.nextElementSibling;
1754        if (dd) {
1755          const wrapper = document.createElement('div');
1756          wrapper.className = 'basket-item';
1757          dt.parentNode.insertBefore(wrapper, dt);
1758          wrapper.appendChild(dt);
1759          wrapper.appendChild(dd);
1760        }
1761      });
1762    }
1763
1764    // Add rel="noopener" to target="_blank" links
1765    $$('a[target="_blank"]').forEach(link => {
1766      const rel = link.getAttribute('rel') || '';
1767      if (!rel.includes('noopener')) {
1768        link.setAttribute('rel', (rel + ' noopener').trim());
1769      }
1770    });
1771
1772    // News scroller formatting
1773    newsItems.forEach(item => {
1774      const title = item.querySelector('h5');
1775      if (title) {
1776        const newTitle = document.createElement('h2');
1777        newTitle.innerHTML = title.innerHTML;
1778        title.replaceWith(newTitle);
1779
1780        const leader = item.querySelector('p.leader');
1781        const newsDetail = document.createElement('div');
1782        newsDetail.className = 'news-detail';
1783        newsDetail.innerHTML = `<div class="news-detail-cell">${newTitle.outerHTML}</div>`;
1784        item.appendChild(newsDetail);
1785
1786        if (leader) {
1787          newsDetail.querySelector('.news-detail-cell').appendChild(leader);
1788        }
1789      }
1790    });
1791
1792    // --- The block below previously lived (incorrectly) inside the
1793    // newsItems.forEach loop above, so it only ran once per news item
1794    // and not at all when #scroller had no news items. It now runs
1795    // exactly once per page load, as intended. ---
1796
1797    // Accessibility cleanup
1798    const popup = document.querySelector('.popup.vp_form');
1799    if (popup) {
1800      popup.setAttribute('tabindex', '0');
1801      popup.setAttribute('title', 'Modal form popup');
1802      // Only steal focus if the popup is actually visible/open, so we don't
1803      // yank focus away from the page on every load when it's hidden.
1804      const isVisible = popup.offsetParent !== null &&
1805        window.getComputedStyle(popup).display !== 'none';
1806      if (isVisible) popup.focus();
1807    }
1808
1809    if (typeof mslUserInfo === 'undefined') {
1810      $$('#skip-to-user, #skip-to-admin, #skip-to-basket').forEach(el => el.remove());
1811    } else {
1812      const skipLogin = document.getElementById('skip-to-login');
1813      if (skipLogin) skipLogin.remove();
1814    }
1815
1816    $$('[aria-label="Site navigation"] > ul > li > a > span').forEach(span => {
1817      const h2 = document.createElement('h2');
1818      span.parentNode.insertBefore(h2, span);
1819      h2.appendChild(span);
1820    });
1821
1822    const adminControls = document.querySelector('.controls-container');
1823    if (adminControls) {
1824      if (adminControls.querySelectorAll('li').length > 0) {
1825        adminControls.style.display = 'block';
1826      } else {
1827        const skipAdmin = document.getElementById('skip-to-admin');
1828        if (skipAdmin) skipAdmin.remove();
1829      }
1830    }
1831
1832    const eventLocation = document.querySelector('.event-location');
1833    if (eventLocation && eventLocation.textContent.length === 1) {
1834      eventLocation.style.display = 'none';
1835    }
1836
1837    $$('.qty > .remove').forEach(btn => btn.textContent = '');
1838
1839    const reviewBtn = document.getElementById('ctl00_basket_lnkReviewBasket');
1840    if (reviewBtn) {
1841      reviewBtn.classList.add('btn', 'btn-primary');
1842    }
1843
1844    const checkoutBtn = document.getElementById('ctl00_basket_lnkCheckout');
1845    if (checkoutBtn) {
1846      checkoutBtn.classList.add('btn', 'btn-secondary');
1847    }
1848
1849    // Format publication metadata for news items
1850    mslNewsItems.forEach(item => {
1851      const title = item.querySelector('.msl-title');
1852      const org = item.querySelector('.msl-organisation');
1853      const byline = item.querySelector('.msl-byline');
1854      const pubDateEl = item.querySelector('.msl-pubdate');
1855
1856      if (pubDateEl) {
1857        const pubDate = pubDateEl.textContent;
1858        const isBanner = item.closest('.mslwidget')?.classList.contains('banner');
1859        pubDateEl.textContent = isBanner ? 'Posted ' + relTime(pubDate) : relTime(pubDate);
1860      }
1861
1862      if (org && byline && title) {
1863        org.textContent += ' | ' + byline.textContent;
1864        title.parentNode.insertBefore(org, title);
1865        byline.remove();
1866      } else if (org && title) {
1867        title.parentNode.insertBefore(org, title);
1868      } else if (byline && title) {
1869        byline.classList.add('msl-organisation');
1870        title.parentNode.insertBefore(byline, title);
1871      }
1872    });
1873
1874    // Banner formatting
1875    bannerItems.forEach(item => {
1876      const h = item.querySelector('h3');
1877      const d = item.querySelector('.msl-pubdate');
1878      const o = item.querySelector('.msl-organisation');
1879
1880      if (h) {
1881        h.classList.remove('msl-title');
1882        const wrapper = document.createElement('div');
1883        wrapper.className = 'msl-title';
1884        h.parentNode.insertBefore(wrapper, h);
1885        wrapper.appendChild(h);
1886
1887        if (d) h.parentNode.insertBefore(d, h.nextSibling);
1888        if (o) h.parentNode.insertBefore(o, h);
1889      }
1890    });
1891
1892    // Hide "More" buttons if no content
1893    const latestEventP = document.querySelector('.banner-latest .latest-event .msl_eventlist > p');
1894    if (latestEventP && latestEventP.textContent.length > 0) {
1895      const btnGroup = document.querySelector('.banner-latest .latest-event .btn-group');
1896      if (btnGroup) btnGroup.style.display = 'none';
1897    }
1898
1899    const noNewsMsg = document.querySelector('.banner-latest .latest-news .msl-no-news-message');
1900    if (noNewsMsg && noNewsMsg.textContent.length > 0) {
1901      const btnGroup = document.querySelector('.banner-latest .latest-news .btn-group');
1902      if (btnGroup) btnGroup.style.display = 'none';
1903    }
1904
1905    // Referendum styling
1906    if (document.querySelector('.referendum')) {
1907      $$('.referendum .vote').forEach(el => el.classList.toggle('btn-group'));
1908      $$('.referendum .votenow').forEach(el => {
1909        el.classList.add('btn', 'btn-primary');
1910      });
1911    }
1912  }
1913
1914  function handleAccordion(title) {
1915    const tabId = title.dataset.tab;
1916    const content = document.getElementById(tabId);
1917    if (!content) return;
1918
1919    // Ensure the ARIA relationship between title and content is present.
1920    if (!title.hasAttribute('aria-controls')) {
1921      title.setAttribute('aria-controls', tabId);
1922    }
1923
1924    const parent = content.parentElement;
1925    const siblings = Array.from(parent.parentElement.children).filter(el => el !== parent);
1926
1927    const isVisible = window.getComputedStyle(content).display !== 'none';
1928    content.style.display = isVisible ? 'none' : 'block';
1929
1930    siblings.forEach(sib => {
1931      const sibContent = sib.querySelector('.accordion-content');
1932      if (sibContent) sibContent.style.display = 'none';
1933    });
1934
1935    title.classList.toggle('active-title');
1936    siblings.forEach(sib => {
1937      const sibTitle = sib.querySelector('.accordion-title');
1938      if (sibTitle) sibTitle.classList.remove('active-title');
1939    });
1940
1941    title.setAttribute('aria-expanded', title.classList.contains('active-title'));
1942
1943    const icon = title.querySelector('i.fa-chevron-down');
1944    if (icon) {
1945      icon.classList.toggle('chevron-top');
1946      icon.setAttribute('aria-hidden', 'true');
1947    }
1948
1949    siblings.forEach(sib => {
1950      const sibIcon = sib.querySelector('.accordion-title i.fa-chevron-down');
1951      if (sibIcon) {
1952        sibIcon.classList.remove('chevron-top');
1953        sibIcon.setAttribute('aria-hidden', 'true');
1954      }
1955    });
1956  }
1957
1958  // Initialize when DOM is ready
1959  if (document.readyState === 'loading') {
1960    document.addEventListener('DOMContentLoaded', init);
1961  } else {
1962    init();
1963  }
1964})();
1965
1966
1967(function() {
1968  function ready(fn) {
1969    if (document.readyState !== 'loading') fn();
1970    else document.addEventListener('DOMContentLoaded', fn);
1971  }
1972
1973  ready(function initAllSliders() {
1974    // Support multiple instances: ID (hero/mini hook) and class (mini)
1975    var containers = Array.prototype.slice.call(
1976      document.querySelectorAll('#sliderControl, .sliderControls-mini')
1977    );
1978
1979    // Remove duplicates if the same element is returned twice
1980    containers = containers.filter(function(el, i, arr){
1981      return arr.indexOf(el) === i;
1982    });
1983
1984    containers.forEach(function(container){
1985      initSliderContainer(container);
1986    });
1987  });
1988
1989  function initSliderContainer(container) {
1990    // Prevent double init
1991    if (container.dataset.sliderInit === '1') return;
1992
1993    // --- STEP 1: Collect slides (news first; else adapt events) ---
1994    var slides = Array.prototype.slice.call(container.querySelectorAll('.news_item'));
1995
1996    if (!slides.length) {
1997      // Try events markup and adapt to news structure
1998      var eventSlides = Array.prototype.slice.call(container.querySelectorAll('.event_item'));
1999      if (eventSlides.length) {
2000        slides = adaptEventsToNews(container, eventSlides);
2001      }
2002    }
2003
2004    if (!slides.length) return; // nothing to do
2005
2006    // --- STEP 2: Track setup ---
2007    var track = container.querySelector('.slider-track');
2008    var createdTrack = false;
2009
2010    if (!track) {
2011      track = document.createElement('div');
2012      track.className = 'slider-track';
2013      createdTrack = true;
2014    }
2015
2016    // Ensure each slide has the expected inner structure
2017    slides.forEach(function(slide, i) {
2018      // If not already structured, build .slide-grid with .slide-image & .slide-text
2019      var hasGrid = slide.querySelector('.slide-grid');
2020      if (!hasGrid) {
2021        var titleBlock = slide.querySelector('h2, h3, h4, h5');
2022        var leader     = slide.querySelector('.leader');
2023        var imageWrap  = slide.querySelector('.news_image');
2024
2025        var grid    = document.createElement('div');
2026        grid.className = 'slide-grid';
2027
2028        var textCol = document.createElement('div');
2029        textCol.className = 'slide-text';
2030
2031        var imageCol = document.createElement('div');
2032        imageCol.className = 'slide-image';
2033
2034        if (imageWrap) {
2035          var img = imageWrap.querySelector('img');
2036          if (img) {
2037            img.removeAttribute('width');
2038            img.removeAttribute('height');
2039            img.loading = 'lazy';
2040          }
2041          imageCol.appendChild(imageWrap);
2042        }
2043
2044        if (titleBlock) textCol.appendChild(titleBlock);
2045        if (leader)     textCol.appendChild(leader);
2046
2047        while (slide.firstChild) slide.removeChild(slide.firstChild);
2048        slide.appendChild(grid);
2049        grid.appendChild(imageCol);
2050        grid.appendChild(textCol);
2051      }
2052
2053      // A11y
2054      slide.setAttribute('role', 'group');
2055      slide.setAttribute('aria-roledescription', 'slide');
2056      slide.setAttribute('aria-label', (i + 1) + ' of ' + slides.length);
2057
2058      // Move into track if we just created it
2059      if (createdTrack) track.appendChild(slide);
2060    });
2061
2062    // Insert track if we created it
2063    if (createdTrack) {
2064      container.insertBefore(track, container.firstChild);
2065    }
2066
2067    // --- STEP 3: Controls & dots (create only if not present) ---
2068    var prevBtn = container.querySelector('.slider-edge.left');
2069    var nextBtn = container.querySelector('.slider-edge.right');
2070
2071    if (!prevBtn) {
2072      prevBtn = document.createElement('button');
2073      prevBtn.type = 'button';
2074      prevBtn.className = 'slider-edge left';
2075      prevBtn.setAttribute('aria-label', 'Previous slide');
2076      prevBtn.innerHTML = '<i class="fa-solid fa-chevron-left" aria-hidden="true"></i>';
2077      container.appendChild(prevBtn);
2078    }
2079
2080    if (!nextBtn) {
2081      nextBtn = document.createElement('button');
2082      nextBtn.type = 'button';
2083      nextBtn.className = 'slider-edge right';
2084      nextBtn.setAttribute('aria-label', 'Next slide');
2085      nextBtn.innerHTML = '<i class="fa-solid fa-chevron-right" aria-hidden="true"></i>';
2086      container.appendChild(nextBtn);
2087    }
2088
2089    var dotsWrap = container.querySelector('.slider-dots');
2090    if (!dotsWrap) {
2091      dotsWrap = document.createElement('div');
2092      dotsWrap.className = 'slider-dots';
2093      dotsWrap.setAttribute('role', 'tablist');
2094      dotsWrap.setAttribute('aria-label', 'Slide navigation');
2095      container.appendChild(dotsWrap);
2096    }
2097
2098    // Pause/Play control so autoplay can be stopped by keyboard/AT users,
2099    // not just via mouseenter.
2100    var pauseBtn = container.querySelector('.slider-pause');
2101    if (!pauseBtn) {
2102      pauseBtn = document.createElement('button');
2103      pauseBtn.type = 'button';
2104      pauseBtn.className = 'slider-pause';
2105      container.appendChild(pauseBtn);
2106    }
2107
2108    container.classList.add('slider-initialized');
2109    container.dataset.sliderInit = '1';
2110
2111    // --- STEP 4: State & behavior ---
2112    var index = 0;
2113    var autoTimer = null;
2114    var AUTO_MS = 6000;
2115    var PAUSE_ON_HOVER = true;
2116    var prefersReducedMotion = window.matchMedia &&
2117      window.matchMedia('(prefers-reduced-motion: reduce)').matches;
2118    var userPaused = prefersReducedMotion; // start paused if user prefers reduced motion
2119
2120    // Dots
2121    var dots = [];
2122    function buildDots() {
2123      while (dotsWrap.firstChild) dotsWrap.removeChild(dotsWrap.firstChild);
2124      dots = slides.map(function(_, i) {
2125        var b = document.createElement('button');
2126        b.type = 'button';
2127        b.setAttribute('role', 'tab');
2128        b.setAttribute('aria-label', 'Go to slide ' + (i + 1));
2129        b.addEventListener('click', function() { goTo(i); });
2130        dotsWrap.appendChild(b);
2131        return b;
2132      });
2133    }
2134
2135    function updatePauseButton() {
2136      var isPaused = !autoTimer;
2137      pauseBtn.setAttribute('aria-label', isPaused ? 'Play slideshow' : 'Pause slideshow');
2138      pauseBtn.setAttribute('aria-pressed', String(isPaused));
2139      pauseBtn.innerHTML = isPaused
2140        ? '<i class="fa-solid fa-play" aria-hidden="true"></i>'
2141        : '<i class="fa-solid fa-pause" aria-hidden="true"></i>';
2142    }
2143
2144    function updateUI() {
2145      var slideWidth = slides[0].getBoundingClientRect().width || container.getBoundingClientRect().width;
2146      if (!slideWidth) return; // container hidden? wait for next tick
2147
2148      var offset = index * slideWidth * -1;
2149      track.style.transform = 'translateX(' + offset + 'px)';
2150
2151      dots.forEach(function(d, i) {
2152        d.setAttribute('aria-current', i === index ? 'true' : 'false');
2153      });
2154    }
2155
2156    function goTo(i) {
2157      index = (i + slides.length) % slides.length;
2158      updateUI();
2159      resetAuto();
2160    }
2161    function next() { goTo(index + 1); }
2162    function prev() { goTo(index - 1); }
2163
2164    // Autoplay
2165    function startAuto() {
2166      stopAuto();
2167      if (userPaused) { updatePauseButton(); return; }
2168      autoTimer = setInterval(next, AUTO_MS);
2169      updatePauseButton();
2170    }
2171    function stopAuto()  {
2172      if (autoTimer) { clearInterval(autoTimer); autoTimer = null; }
2173      updatePauseButton();
2174    }
2175    function resetAuto() { if (!userPaused) startAuto(); }
2176
2177    pauseBtn.addEventListener('click', function() {
2178      userPaused = !userPaused;
2179      if (userPaused) stopAuto(); else startAuto();
2180    });
2181
2182    // Keyboard
2183    container.setAttribute('tabindex', '0');
2184    container.addEventListener('keydown', function(e) {
2185      var k = e.key;
2186      if (k === 'ArrowRight' || k === 'PageDown') { e.preventDefault(); next(); }
2187      else if (k === 'ArrowLeft' || k === 'PageUp') { e.preventDefault(); prev(); }
2188      else if (k === 'Home') { e.preventDefault(); goTo(0); }
2189      else if (k === 'End')  { e.preventDefault(); goTo(slides.length - 1); }
2190    });
2191
2192    // Buttons
2193    prevBtn.addEventListener('click', prev);
2194    nextBtn.addEventListener('click', next);
2195
2196    // Pause on hover (does not permanently set userPaused, just suspends the timer)
2197    if (PAUSE_ON_HOVER) {
2198      container.addEventListener('mouseenter', function() {
2199        if (autoTimer) { clearInterval(autoTimer); autoTimer = null; }
2200      });
2201      container.addEventListener('mouseleave', function() {
2202        if (!userPaused) startAuto();
2203      });
2204    }
2205
2206    // Touch swipe
2207    var startX = null, startY = null, dragging = false;
2208    var SWIPE_THRESHOLD = 40; // px
2209    container.addEventListener('touchstart', function(e) {
2210      var t = e.touches ? e.touches[0] : e;
2211      startX = t.clientX; startY = t.clientY; dragging = true;
2212      if (autoTimer) { clearInterval(autoTimer); autoTimer = null; }
2213    }, { passive: true });
2214    container.addEventListener('touchmove', function(e) {
2215      if (!dragging) return;
2216      var t = e.touches ? e.touches[0] : e;
2217      var dx = t.clientX - startX, dy = t.clientY - startY;
2218      if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > SWIPE_THRESHOLD) {
2219        dragging = false; (dx < 0 ? next() : prev());
2220      }
2221    }, { passive: true });
2222    container.addEventListener('touchend', function() {
2223      dragging = false;
2224      if (!userPaused) startAuto();
2225    });
2226
2227    // Resize & late image load sync
2228    var resizeTimer = null;
2229    window.addEventListener('resize', function() {
2230      if (resizeTimer) clearTimeout(resizeTimer);
2231      resizeTimer = setTimeout(updateUI, 150);
2232    });
2233    window.addEventListener('load', updateUI);
2234
2235    // On hidden container at init (e.g., tabs), re-check.
2236    // Also re-check via ResizeObserver where available, so sliders revealed
2237    // later (e.g. inside a tab panel opened after page load) still sync.
2238    setTimeout(updateUI, 200);
2239    setTimeout(updateUI, 500);
2240
2241    if (typeof ResizeObserver !== 'undefined') {
2242      var ro = new ResizeObserver(function() { updateUI(); });
2243      ro.observe(container);
2244    }
2245
2246    // Init
2247    buildDots();
2248    goTo(0);
2249    if (!userPaused) startAuto();
2250    updatePauseButton();
2251  }
2252
2253  /**
2254   * Adapt events markup (.event_item) to the news structure the slider expects.
2255   * Returns the new slides NodeList (now with .news_item).
2256   */
2257  function adaptEventsToNews(container, eventSlides) {
2258    eventSlides.forEach(function(slide) {
2259      // 1) Mark as news_item so existing logic sees it
2260      slide.classList.add('news_item');
2261
2262      // 2) Extract typical events markup
2263      var dl       = slide.querySelector('dl');
2264      var dt       = dl ? dl.querySelector('dt') : null;
2265      var nameLink = dt ? dt.querySelector('.msl_event_name') : null;
2266      var imgWrap  = dt ? dt.querySelector('.msl_event_image') : null;
2267      var desc     = slide.querySelector('.msl_event_description');
2268
2269      // 3) Build grid columns
2270      var grid    = document.createElement('div');
2271      grid.className = 'slide-grid';
2272
2273      var imgCol  = document.createElement('div');
2274      imgCol.className = 'slide-image';
2275
2276      var textCol = document.createElement('div');
2277      textCol.className = 'slide-text';
2278
2279      // Image column: convert to .news_image for CSS compatibility
2280      if (imgWrap) {
2281        imgWrap.classList.add('news_image');
2282        var img = imgWrap.querySelector('img');
2283        if (img) {
2284          img.removeAttribute('width');
2285          img.removeAttribute('height');
2286          img.loading = 'lazy';
2287        }
2288        imgCol.appendChild(imgWrap);
2289      }
2290
2291      // Text column: wrap name in h5, convert description to .leader
2292      if (nameLink) {
2293        var h2 = document.createElement('h2');
2294        h2.appendChild(nameLink);
2295        textCol.appendChild(h2);
2296      }
2297      if (desc) {
2298        desc.classList.add('leader');
2299        textCol.appendChild(desc);
2300      }
2301
2302      // Replace slide content
2303      while (slide.firstChild) slide.removeChild(slide.firstChild);
2304      slide.appendChild(grid);
2305      grid.appendChild(imgCol);
2306      grid.appendChild(textCol);
2307    });
2308
2309    // Return as slides for the rest of the flow
2310    return Array.prototype.slice.call(container.querySelectorAll('.news_item'));
2311  }
2312})();
2313<!-- end of novus-scripts snippet -->
2314
2315  });
2316</script>
2316
2317        </div>
2318        
2319        
2320        
2321        
2322        
2323
2324        
2325
2326    </form>
2327
2328</body>
2329</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.