ctucx.git: trainsearch

web based trip-planner, fork of https://cyberchaos.dev/yuka/trainsearch

commit 7e07d4d7f2171dee6b6f84adbb51fc85f0ed02f8
parent 4bb5de0d09251f81e3ce9bd20e8b61fc644967e8
Author: Katja (ctucx) <git@ctu.cx>
Date: Thu, 23 Jan 2025 11:26:00 +0100

big stylesheet and template refactoring
10 files changed, 250 insertions(+), 339 deletions(-)
M
src/departuresView.js
|
7
+++----
M
src/journeyView.js
|
8
++++----
M
src/journeysView.js
|
18
+++++++++---------
M
src/overlays.js
|
32
+++++++++++++-------------------
M
src/searchView.js
|
11
++++++-----
M
src/settingsView.js
|
2
+-
M
src/templates.js
|
2
+-
M
src/tripView.js
|
22
+++++++++++-----------
M
static/index.html
|
3
+--
M
static/style.css
|
484
+++++++++++++++++++++++++++++++++----------------------------------------------
diff --git a/src/departuresView.js b/src/departuresView.js
@@ -11,15 +11,14 @@ const departuresTemplate = (data, profile) => {
 	let changes = 0;
 	let lastArrival;
 
-	//<a class="reload icon-reload" title="${t("reload")}" @click=${() => refreshJourneyView(data.refreshToken, profile)}>${t("reload")}</a>
 	return html`
-		<div class="departures">
+		<div class="departuresView column">
 			<header>
 				<a id="back" class="icon-back hidden" title="${t('back')}" @click=${() => history.back()}>${t('back')}</a>
 				<div class="content">
 					<h3>Departures from ${data.name}</h3>
 				</div>
-				<a class="icon-reload hidden">${t("reload")}</a>
+				<a id="reload" class="icon-reload invisible" title="${t("reload")}">${t("reload")}</a>
 			</header>
 
 			<div class="card">

@@ -39,7 +38,7 @@ const departuresTemplate = (data, profile) => {
 							${departure.cancelled ? html`
 								<td><span class="cancelled-text">${t('cancelled-ride')}</span></td>
 							` : html`
-								<td><span>${platformTemplate(departure)}</span></td>
+								<td>${platformTemplate(departure)}</td>
 							`}
 						</tr>
 					`)}
diff --git a/src/journeyView.js b/src/journeyView.js
@@ -28,14 +28,14 @@ const legTemplate = (leg, profile) => {
 				<thead>
 					<tr>
 						<td colspan="4">
-							<span><a href="#/t/${profile}/${leg.tripId}">${lineDisplayName(leg.line)}${leg.direction ? html` → ${leg.direction}` : ''}</a>
+							<div class="center"><a href="#/t/${profile}/${leg.tripId}">${lineDisplayName(leg.line)}${leg.direction ? html` → ${leg.direction}` : ''}</a>
 							${leg.cancelled ? html`<b class="cancelled-text">${t('cancelled-ride')}</b>` : ''}
-							${Object.entries(remarks).map(remarksTemplate)}</span>
+							${Object.entries(remarks).map(remarksTemplate)}</div>
 						</td>
 					</tr>
 					<tr>
 						<td colspan="4">
-							<div class="train-details">
+							<div class="train-details center">
 								${lineAdditionalName(leg.line) ? html`
 									<div>
 										Trip: ${lineAdditionalName(leg.line)}

@@ -119,7 +119,7 @@ const journeyTemplate = (data, profile) => {
 	}
 
 	return html`
-		<div class="journey">
+		<div class="journeyView column">
 			<header>
 				${data.slug ? html`
 					<a class="icon-back" href="#/${data.slug}/${settings.journeysViewMode}" title="${t('back')}">${t('back')}</a>
diff --git a/src/journeysView.js b/src/journeysView.js
@@ -8,7 +8,7 @@ import { html, render } from 'lit-html';
 import { showAlertModal, showLoader, hideOverlay } from './overlays.js';
 
 const journeysTemplate = (data) => html`
-	<div class="journeys">
+	<div class="journeysView column">
 		<header id="header">
 			<a class="icon-back" href="#/" title="${t('back')}">${t('back')}</a>
 			<div class="content">

@@ -35,7 +35,7 @@ const journeysTemplate = (data) => html`
 		` : ''}
 		${settings.journeysViewMode === 'table' ? html`
 			${data.earlierRef ? html`
-				<a class="loadMore icon-arrow2 flipped" title="${t('label_earlier')}" @click=${() => moreJourneys(data.slug, 'earlier')}></a>
+				<a class="arrowButton flipped icon-arrow2" title="${t('label_earlier')}" @click=${() => moreJourneys(data.slug, 'earlier')}></a>
 			` : ''}
 
 			<div class="card">

@@ -58,7 +58,7 @@ const journeysTemplate = (data) => html`
 			</div>
 
 			${data.laterRef ? html`
-				<a class="loadMore icon-arrow2" title="${t('label_later')}" @click=${() => moreJourneys(data.slug, 'later')}></a>
+				<a class="arrowButton icon-arrow2" title="${t('label_later')}" @click=${() => moreJourneys(data.slug, 'later')}></a>
 			` : ''}
 		` : ''}
 	</div>

@@ -99,16 +99,16 @@ const journeyOverviewTemplate = (profile, entry, slug, key) => {
 
 	return html`
 	<tr @click=${() => go(`/j/${profile}/${entry.refreshToken}`)}>
-		<td class="${cancelled ? 'cancelled' : ''}"><span>${timeTemplate(firstLeg, 'departure')}</span></td>
+		<td class="${cancelled ? 'cancelled' : ''}">${timeTemplate(firstLeg, 'departure')}</td>
 		${cancelled ? html`
 			<td><span class="cancelled-text">${t('cancelled-ride')}</span></td>
 		` : html`
-			<td><span>${timeTemplate(lastLeg, 'arrival')}</span></td>
+			<td>${timeTemplate(lastLeg, 'arrival')}</td>
 		`}
-		<td class="${cancelled ? 'cancelled' : ''}" title="${changesDuration > 0 ? 'including '+formatDuration(changesDuration)+' transfer durations' : ''}"><span>${formatDuration(duration)}</span></td>
-		<td><span>${changes-1}</span></td>
-		<td><span>${productsString}</span></td>
-		${settings.showPrices ? html`<td><span>${formatPrice(entry.price)}</span></td>` : ''}
+		<td class="${cancelled ? 'cancelled' : ''}" title="${changesDuration > 0 ? 'including '+formatDuration(changesDuration)+' transfer durations' : ''}">${formatDuration(duration)}</td>
+		<td>${changes-1}</td>
+		<td>${productsString}</td>
+		${settings.showPrices ? html`<td>${formatPrice(entry.price)}</td>` : ''}
 		<td><a class="icon-arrow1"></a></td>
 	</tr>`;
 };
diff --git a/src/overlays.js b/src/overlays.js
@@ -5,11 +5,9 @@ export const showAlertModal = (text) => {
 	showDiv('overlay');
 	return new Promise(resolve => {
 		render(html`
-			<div class="modal">
-				<div class="box alert">
-					${text}
-					<br><button class="color" @click=${() => { hideOverlay(); resolve(); }}>OK</button>
-				</div>
+			<div class="modal alert">
+				${text}
+				<br><button class="color" @click=${() => { hideOverlay(); resolve(); }}>OK</button>
 			</div>
 		`, ElementById('overlay'));
 	});

@@ -19,13 +17,11 @@ export const showSelectModal = (items) => {
 	showDiv('overlay');
 	return new Promise(resolve => {
 		render(html`
-			<div class="modal">
-				<div class="box select">
-					${items.map(
-						(item) => html`<a class="button color" @click=${item.action}>${item.label}</a>`
-					)}
-					<a class="button color" @click=${() => { hideOverlay(); resolve(); }}>Close</a>
-				</div>
+			<div class="modal select column">
+				${items.map(
+					(item) => html`<a class="button color" @click=${item.action}>${item.label}</a>`
+				)}
+				<a class="button color" @click=${() => { hideOverlay(); resolve(); }}>Close</a>
 			</div>
 		`, ElementById('overlay'));
 	});

@@ -35,14 +31,12 @@ export const showModal = (title, content) => {
 	showDiv('overlay');
 	return new Promise(resolve => {
 		render(html`
-			<div class="modal">
-				<div class="box dialog">
-					<div class="header">
-						<h4>${title}</h4>
-						<div class="close" title="Close" @click=${() => { hideOverlay(); resolve(); }}></div>
-					</div>
-					<div class="body">${content}</div>
+			<div class="modal dialog">
+				<div class="header row">
+					<h4>${title}</h4>
+					<div class="icon-close" title="Close" @click=${() => { hideOverlay(); resolve(); }}></div>
 				</div>
+				<div class="body">${content}</div>
 			</div>
 		`, ElementById('overlay'));
 	});
diff --git a/src/searchView.js b/src/searchView.js
@@ -60,12 +60,12 @@ const iconFor = id => {
 };
 
 const searchTemplate = (journeysHistory) => html`
-	<div id="searchView">
-		<div class="title">
+	<div class="searchView">
+		<div class="title center">
 			<div class="icon-logo"></div>
 			<h1>TrainSearch</h1>
 		</div>
-		<form onsubmit="return false;">
+		<form class="column" onsubmit="return false;">
 			<div class="row nowrap">
 				<label for="from">${t('from')}:</label>
 				<input type="text" name="from" id="from" placeholder="${t('from')}" value="${fromValue}" autocomplete="off" @focus=${startTyping} @blur=${stopTyping} @keyup=${onKeyup} @keydown=${onKeydown} required>

@@ -73,9 +73,10 @@ const searchTemplate = (journeysHistory) => html`
 			</div>
 			<div class="suggestions" id="fromSuggestions"></div>
 
-			<div class="row hidden" id="viaRow">
+			<div class="row nowrap hidden" id="viaRow">
 				<label for="via">${t('via')}:</label>
 				<input type="text" name="via" id="via" placeholder="${t('via')}" value="${viaValue}" autocomplete="off" @focus=${startTyping} @blur=${stopTyping} @keyup=${onKeyup} @keydown=${onKeydown} required>
+				<div class="button icon-arrow2 invisible"></div>
 			</div>
 			<div class="suggestions" id="viaSuggestions"></div>
 

@@ -133,7 +134,7 @@ const searchTemplate = (journeysHistory) => html`
 			</div>
 
 			${journeysHistory.length ? html`
-				<div id="historyButton" class="loadMore icon-arrow2" title="History" @click=${toggleHistory}></div>
+				<div id="historyButton" class="arrowButton icon-arrow2" title="History" @click=${toggleHistory}></div>
 			` : ''}
 		</form>
 
diff --git a/src/settingsView.js b/src/settingsView.js
@@ -12,7 +12,7 @@ export const showSettings = async () => {
 };
 
 const settingsTemplate = () => html`
-	<div id="settingsView">
+	<div class="settingsView">
 		<div class="row">
 			<label for="language">${t('language')}:</label>
 			<select id="language">
diff --git a/src/templates.js b/src/templates.js
@@ -26,7 +26,7 @@ export const remarksTemplate = ([type, remarks]) => !!remarks.length ? html`
 ` : '';
 
 export const stopTemplate = (profile, stop) => {
-	return html`<a href="#/d/${profile}/${stop.id}">${stop.name} ${ds100Names(stop.id)}</a>`;
+	return html`<a class="center" href="#/d/${profile}/${stop.id}">${stop.name} ${ds100Names(stop.id)}</a>`;
 }
 
 export const platformTemplate = (data) => {
diff --git a/src/tripView.js b/src/tripView.js
@@ -27,13 +27,13 @@ const tripTemplate = (data, profile) => {
 	}
 
 	return html`
-		<div class="journey">
+		<div class="journeyView column">
 			<header>
 				<a id="back" class="icon-back hidden" title="${t('back')}" @click=${() => history.back()}>${t('back')}</a>
 				<div class="content">
 					<h3>Trip of ${lineDisplayName(data.line)} to ${data.direction}</h3>
 				</div>
-				<a class="icon-reload hidden">${t("reload")}</a>
+				<a class="icon-reload invisible">${t("reload")}</a>
 			</header>
 
 			<div class="card">

@@ -41,18 +41,18 @@ const tripTemplate = (data, profile) => {
 				<thead>
 					<tr>
 						<td colspan="4">
-							<span>${bahnExpertUrl ? html`
+							<div class="center">${bahnExpertUrl ? html`
 								<a href="${bahnExpertUrl}">${lineDisplayName(data.line)}${data.direction ? html` → ${data.direction}` : ''}</a>
 							` : html `
 								${lineDisplayName(data.line)}${data.direction ? html` → ${data.direction}` : ''}
 							`}
 							${data.cancelled ? html`<b class="cancelled-text">${t('cancelled-ride')}</b>` : ''}
-							${Object.entries(remarks).map(remarksTemplate)}</span>
+							${Object.entries(remarks).map(remarksTemplate)}</div>
 						</td>
 					</tr>
 					<tr>
 						<td colspan="4">
-							<div class="train-details">
+							<div class="train-details center">
 								${lineAdditionalName(data.line) ? html`
 									<div>
 										Trip: ${lineAdditionalName(data.line)}

@@ -77,17 +77,17 @@ const tripTemplate = (data, profile) => {
 					<tr>
 						<th>${t('arrival')}</th>
 						<th>${t('departure')}</th>
-						<th class="station-">${t('station')}</th>
+						<th class="station">${t('station')}</th>
 						<th>${t('platform')}</th>
 					</tr>
 				</thead>
 				<tbody>
 					${(data.stopovers || []).map(stop => html`
-						<tr class="stop ${stop.cancelled ? 'cancelled' : ''}">
-							<td><span>${timeTemplate(stop, 'arrival')}</span></td>
-							<td><span>${timeTemplate(stop, 'departure')}</span></td>
-							<td><span>${stopTemplate(profile, stop.stop)}</span></td>
-							<td><span>${platformTemplate(stop)}</span></td>
+						<tr class="${stop.cancelled ? 'cancelled' : ''}">
+							<td>${timeTemplate(stop, 'arrival')}</td>
+							<td>${timeTemplate(stop, 'departure')}</td>
+							<td>${stopTemplate(profile, stop.stop)}</td>
+							<td>${platformTemplate(stop)}</td>
 						</tr>
 					`)}
 				</tbody>
diff --git a/static/index.html b/static/index.html
@@ -29,7 +29,6 @@ body {
 	height: 100vh;
 	width: 100vw;
 	background-color: rgba(0, 0, 0, .7);
-	overflow: hidden;
 	display: flex;
 }
 

@@ -53,7 +52,7 @@ body {
 		</style>
 	</head>
 	<body>
-		<div id="content"></div>
+		<div id="content" class="column"></div>
 		<div id="overlay">
 			<noscript>JavaScript is required to use TrainSearch</noscript>
 			<div id="logo">
diff --git a/static/style.css b/static/style.css
@@ -15,13 +15,22 @@ html, body {
 	overflow-x: hidden;
 	overflow-y: visible;
 }
+
+#content {
+	min-height: 100vh;
+}
+
+#overlay {
+	z-index: 1;
+	backdrop-filter: blur(10px);
+}
  
 a {
 	color: inherit;
 }
 
-.pointer {
-	cursor: pointer;
+.invisible {
+	visibility: hidden !important;
 }
 
 .hidden {

@@ -38,13 +47,15 @@ a {
 	flex-direction: row;
 }
 
-.cancelled {
-	text-decoration-line: line-through;
+.column {
+	display: flex;
+	flex-direction: column;
 }
 
-.cancelled-text {
-	font-weight: bold;
-	color: red !important;
+.center {
+	display: flex;
+	justify-content: center;
+	align-items: center;
 }
 
 .spinner {

@@ -66,41 +77,13 @@ a {
 	100% { transform: rotate(360deg); }
 }
 
-.loadMore {
-	cursor: pointer;
-	height: 72px;
-	width: 72px;
-	margin: 0 auto;
-	transition: transform 150ms;
-	user-select: none;
-	filter: invert();
-}
-
-.remarks {
-	/*background: #000000d0;*/
-	padding: 0;
-	width: 100%;
-	margin: 0;
-
-	td {
-		margin: 0 10px;
-		text-align: left;
-		display: block;
-	}
-
-	span {
-		vertical-align: middle;
-	}
-}
-
 header {
-	position: relative;
 	display: flex;
 	flex-direction: row;
 	justify-content: center;
 	color: white;
 	background-color: #222;
-	bottom-border: 1px solid rgba(255, 255, 255, .3);
+	border-bottom: 1px solid rgba(255, 255, 255, .3);
 
 	h3 {
 		margin-right: 1.5em;

@@ -149,25 +132,80 @@ header {
 	
 }
 
-#content {
-	display: flex;
-	flex-direction: column;
-	min-height: 100vh;
-}
+.card {
+	overflow-x: auto;
 
-#overlay {
-	position: fixed;
-	z-index: 1;
-	left: 0;
-	top: 0;
-	width: 100%;
-	height: 100%;
-	overflow: auto;
-	background-color: rgba(0,0,0,0.4);
-	backdrop-filter: blur(10px);
+	table {
+		border-bottom: 1px solid rgba(0, 0, 0, 0.3);
+		width: 100%;
+		background-color: #fff;
+		min-width: 390px;
+		max-width: 1000px;
+	}
+
+	table a {
+		padding: 5px 3px;
+		text-decoration: none;
+	}
+	
+	thead {
+		.center {
+			padding: 5px 3px;
+		}
+
+		tr:not(:last-child) {
+			background-color: #eee;
+		}
+	}
+
+	tbody {
+		tr {
+			cursor: pointer;
+			border-top: 1px solid #ccc;
+		}
+
+		tr:hover {
+			background-color: #ddd;
+		}
+
+		tr:hover td {
+			background-color: transparent;
+		}
+	}
+
+	td, th {
+		text-align: center;
+		overflow: hidden;
+	}
+
+	th {
+		padding: 10px 5px;
+	}
+
+	th.station {
+		width: 60%;
+	}
+
+	.train-details {
+		flex-wrap: wrap;
+		padding: 0 !important;
+	
+		div {
+			margin: .4em 2em;
+		}
+	}
+
+	.cancelled {
+		text-decoration-line: line-through;
+	}
+	
+	.cancelled-text {
+		font-weight: bold;
+		color: red !important;
+	}
 }
 
-#settingsView {
+.settingsView {
 	.row {
 		align-items: center;
 		padding: 1em;

@@ -175,6 +213,7 @@ header {
 	}
 
 	.row:last-child {
+		padding: .5em;
 		border-bottom: unset;
 	    justify-content: right;
 	}

@@ -189,15 +228,11 @@ header {
 	}
 }
 
-#searchView {	
+.searchView {	
 	background-color: #222;
 	flex-grow: 1;
 
 	.title {
-		display: flex;
-		justify-content: center;
-		align-items: center;
-
 		.icon-logo {
 			background-color: #7171e5;
 			border-radius: 15%;

@@ -223,18 +258,11 @@ header {
 
 	form {
 		color: white;
-		display: flex;
-		flex-direction: column;
 
 		label[for=from], label[for=via], label[for=to], label[for=date], label[for=time] {
 			display: none;
 		}
 
-		table {
-			width: 100%;
-			color: black;
-		}
-
 		#time, #date {
 			flex-grow: 1;
 		}

@@ -243,10 +271,6 @@ header {
 			width: 100%;
 		}
 
-		#via {
-			margin-right: 53px;
-		}
-
 		.button.icon-arrow1,
 		.button.icon-arrow2,
 		.button.icon-swap {

@@ -286,28 +310,24 @@ header {
 		overflow: visible;
 		z-index: 999;
 		height: 0;
+		width: 100%;
 
-		.box {
-			border-radius: 3px;
-			width: 100%;
-
-			p {
-				font-size: 1.2em;
-				background-color: white;
-				color: black;
-				margin: 0;
-				border-top: 1px solid rgba(0, 0, 0, .2);
-				padding: .3em .6em;
-				cursor: pointer;
-			}
+		p {
+			font-size: 1.2em;
+			background-color: white;
+			color: black;
+			margin: 0;
+			border-top: 1px solid rgba(0, 0, 0, .2);
+			padding: .3em .6em;
+			cursor: pointer;
+		}
 
-			p:first-child {
-				border-top: 0px;
-			}
+		p:first-child {
+			border-top: 0px;
+		}
 
-			p:hover {
-				background-color: #d3d3d3;
-			}
+		p:hover {
+			background-color: #d3d3d3;
 		}
 
 		#selected {

@@ -327,16 +347,14 @@ header {
 		user-select: none;
 
 		.row {
-			font-size: 1.2em;
+			justify-content: space-between;
+			cursor: pointer;
+			padding: .3em .6em .3em .3em;
+			margin: 0;
 			background-color: white;
 			color: black;
-			margin: 0;
+			font-size: 1.2em;
 			border-top: 1px solid rgba(0, 0, 0, .2);
-			padding: .3em .6em .3em .3em;
-			cursor: pointer;
-
-			display: flex;
-			justify-content: space-between;
 		}
 
 		:first-child {

@@ -382,78 +400,19 @@ header {
 	}
 }
 
-.card {
-	overflow-x: auto;
-
-	.train-details {
-		display: flex;
-		justify-content: center;
-		flex-wrap: wrap;
-	
-		div {
-			margin: .4em 2em;
-		}
-	}
-
-	table {
-		border-bottom: 1px solid rgba(0, 0, 0, 0.3);
-		width: 100%;
-		background-color: #fff;
-		min-width: 390px;
-		max-width: 1000px;
-	}
-	
-	thead tr:not(:last-child) {
-		background-color: #eee;
-	}
-
-	tbody {
-		tr {
-			border-top: 1px solid #ccc;
-		}
-
-		tr:hover {
-			background-color: #ddd;
-		}
-
-		tr:hover td {
-			background-color: transparent;
-		}
-	}
-
-	tr {
-		background-color: #fff;
-		margin: 0 0 15px 0;
-	}
-
-	td, th {
-		text-align: center;
-		overflow: hidden;
-	}
-
-	th {
-		padding: 5px 3px;
-	}
-
-	th.station {
-		width: 60%;
-	}
-}
-
-.journeys {
+.journeyView,
+.journeysView,
+.departuresView {
 	min-height: 100vh;
+}
 
-	.loadMore.flipped {
+.journeysView {
+	.arrowButton.flipped {
 		margin-top: 45px;
 	}
-
-	.icon-arrow1 {
-		height: 30px;
-		padding: 0;
-	}
 }
 
-.journey {
+.journeyView {
 	tbody:not(:last-child) {
 		border-bottom: 1px solid rgba(0, 0, 0, .2);
 	}

@@ -498,120 +457,86 @@ header {
 		max-inline-size: 22px;
 		margin: 0 .3em;
 	}
-}
 
-.journey,
-.journeys,
-.departures {
-	display: flex;
-	flex-direction: column;
-	min-height: 100vh;
-
-	tbody td:nth-child(2) span {
-	        justify-content: start;
+	.remarks {
+		padding: 0;
+		width: 100%;
+		margin: 0;
+	
+		td {
+			margin: 0 10px;
+			text-align: left;
+			display: block;
+		}
+	
+		span {
+			vertical-align: middle;
+		}
 	}
 }
 
-.journeys tbody tr,
-.departures tbody tr {
-	cursor: pointer;
-}
+.departuresView {
+	tbody td:nth-child(2) {
+		text-align: unset;
+	}
 
-.journeys table a,
-.journey table span,
-.departures table span {
-	padding: 5px 3px;
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	width: 100%;
-	text-decoration: none;
-	color: black;
+	tbody td {
+		padding: 5px 3px;
+	}
 }
 
-.journey table a,
-.departures table a {
-	padding: 5px 3px;
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	text-decoration: none;
-	color: black;
-}
 
 .modal {
-	display: flex;
-	position: fixed;
-	top: 0;
-	right: 0;
-	bottom: 0;
-	left: 0;
 	z-index: 1050;
-	overflow: hidden;
+	margin: auto;
+	background-color: white;
+	width: max-content;
+	padding: 15px;
 	-webkit-overflow-scrolling: touch;
-	outline: 0;
+}
 
-	.box {
-		margin: auto;
-		background-color: white;
-		width: max-content;
-		padding: 15px;
-		border-radius: 4px;
-	}
+.modal.alert button {
+	float: right;
+}
 
-	.alert button {
-		float: right;
+.modal.select {
+	a {
+		width: 100%;
+		margin: 5px 0;
+		text-align: center;
 	}
 
-	.select {
-		display: flex;
-		flex-direction: column;
+	a:first-child {
+		margin-top: unset;
+	}
 
-		a {
-			width: 100%;
-			margin: 5px 0;
-			text-align: center;
-		}
+	a:last-child {
+		margin-bottom: unset;
+	}
+}
 
-		a:first-child {
-			margin-top: unset;
-		}
+.modal.dialog {
+	padding: unset;
 
-		a:last-child {
-			margin-bottom: unset;
-		}
-	}
+	.header {
+		justify-content: space-between;
+		background-color: #5a5a5a;
+		color: white;
+		padding: 15px;
 
-	.dialog {
-		padding: unset;
-		border: 1px solid rgba(0, 0, 0, .4);
+		h4 {
+			margin: 0;
+ 		}
 
-		.header {
-			display: flex;
-			flex-direction: row;
-			justify-content: space-between;
-			background-color: #5a5a5a;
-			color: white;
-			padding: 15px;
-			border-top-right-radius: 3px;
-			border-top-left-radius:  3px;
-
-			h4 {
-				margin: 0;
-	 		}
-
-			.close {
-				margin: -15px;
-				padding: 10px;
-				border-left: 1px solid rgba(0, 0, 0, .4);
-				cursor: pointer;
-				content: url("data:image/svg+xml,%3Csvg width='30' height='30' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M5.293 5.293a1 1 0 0 1 1.414 0L12 10.586l5.293-5.293a1 1 0 1 1 1.414 1.414L13.414 12l5.293 5.293a1 1 0 0 1-1.414 1.414L12 13.414l-5.293 5.293a1 1 0 0 1-1.414-1.414L10.586 12 5.293 6.707a1 1 0 0 1 0-1.414' fill='%23fff'/%3E%3C/svg%3E");
-			}
+		.icon-close {
+			margin: -15px;
+			padding: 10px;
+			border-left: 1px solid rgba(0, 0, 0, .4);
+			cursor: pointer;
+		}
 
-			.close:hover {
-				border-top-right-radius: 3px;
-				background: rgba(0, 0, 0, .4);
-			}
+		.icon-close:hover {
+			background: rgba(0, 0, 0, .4);
 		}
 	}
 }

@@ -653,7 +578,6 @@ button,
 	color: black;
 	cursor: pointer;
 	user-select: none;
-	display: inline-block;
 }
 
 button, .button {

@@ -676,12 +600,14 @@ button.color:hover, .button.color:hover {
 	background-color: rgba(70, 100, 255, .8);
 }
 
-button:not(:first-child) {
-	margin-left: .2em;
-}
-
-button:not(:last-child) {
-	margin-right: .2em;
+.arrowButton {
+	cursor: pointer;
+	user-select: none;
+	height: 72px;
+	width: 72px;
+	margin: 0 auto;
+	transition: transform 150ms;
+	filter: invert();
 }
 
 .selector {

@@ -765,12 +691,12 @@ button:not(:last-child) {
 
 	.button.go {
 		flex-basis: 100%;
-		margin-right: auto;
+		justify-content: center;
 	}
 }
 
 @media (max-width: 799px) {
-	.header {
+	header {
 		.content {
 			flex-grow: 1;
 		}

@@ -780,7 +706,7 @@ button:not(:last-child) {
 		}
 	}
 
-	#searchView {
+	.searchView {
 		padding: 10px;
 	}
 

@@ -792,14 +718,15 @@ button:not(:last-child) {
 		flex-wrap: unset;
 	}
 
-	#journeysView {
-		.loadMore.flipped {
-			margin-top: 15px;
+	.journeysView {
+		.arrowButton {
+			margin: 15px auto;
 		}
 	}
 
-	.loadMore {
+	.arrowButton {
 		width: 48px;
+		height: 48px;
 	}
 
 }

@@ -809,7 +736,7 @@ button:not(:last-child) {
 		justify-content: center;
 	}
 
-	#searchView {
+	.searchView {
 		display: flex;
 		justify-content: center;
 		align-items: center;

@@ -838,24 +765,11 @@ button:not(:last-child) {
 		width: 80vw;
 	}
 
-	td p {
-		display: inline;
-		margin-right: 5px;
-	}
-
-	th {
-		padding: 10px 5px;
-	}
-
-	.journeys table {
+	.journeysView table {
 		margin: 15px auto;
-		
-		a {
-			padding: 10px 5px;
-		}
 	}
 
-	.modal .dialog {
+	.modal.dialog {
 		width: 400px;
 	}
 }

@@ -868,6 +782,10 @@ button:not(:last-child) {
 	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path style="fill: white;" d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
 }
 
+.icon-close {
+	content: url("data:image/svg+xml,%3Csvg width='30' height='30' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M5.293 5.293a1 1 0 0 1 1.414 0L12 10.586l5.293-5.293a1 1 0 1 1 1.414 1.414L13.414 12l5.293 5.293a1 1 0 0 1-1.414 1.414L12 13.414l-5.293 5.293a1 1 0 0 1-1.414-1.414L10.586 12 5.293 6.707a1 1 0 0 1 0-1.414' fill='%23fff'/%3E%3C/svg%3E");
+}
+
 .icon-hint {
 	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>');
 }