670 lines
20 KiB
Plaintext
670 lines
20 KiB
Plaintext
---
|
|
const configuredApiBase = import.meta.env.PUBLIC_PPR_API_BASE ?? 'https://ppr.swansea-airport.wales/api/v1';
|
|
const pprApiBase = configuredApiBase.replace(/\/$/, '');
|
|
---
|
|
|
|
<section class="ppr-shell surface" aria-labelledby="ppr-heading">
|
|
<div class="ppr-head">
|
|
<p class="eyebrow">Prior permission request</p>
|
|
<h2 id="ppr-heading" class="section-title">Submit a PPR request</h2>
|
|
<p class="section-copy">
|
|
Complete the details below for flights into Swansea Airport. Requests are accepted by default;
|
|
the airport will contact you if additional information is required.
|
|
</p>
|
|
<p class="ppr-note">
|
|
If you have any issues, email
|
|
<a href="mailto:james.pattinson@sasalliance.org">james.pattinson@sasalliance.org</a> - our resident IT nerd!
|
|
</p>
|
|
</div>
|
|
|
|
<form id="ppr-form" class="ppr-form">
|
|
<div class="ppr-grid">
|
|
<div class="ppr-field">
|
|
<label for="ac_reg">Aircraft Registration <span aria-hidden="true">*</span></label>
|
|
<input type="text" id="ac_reg" name="ac_reg" autocomplete="off" required />
|
|
<div id="aircraft-lookup-results" class="ppr-lookup" aria-live="polite"></div>
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="ac_type">Aircraft Type <span aria-hidden="true">*</span></label>
|
|
<input type="text" id="ac_type" name="ac_type" autocomplete="off" required />
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="ac_call">Callsign</label>
|
|
<input type="text" id="ac_call" name="ac_call" placeholder="If different from registration" />
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="captain">Captain/Pilot Name <span aria-hidden="true">*</span></label>
|
|
<input type="text" id="captain" name="captain" autocomplete="name" required />
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="in_from">Arriving From <span aria-hidden="true">*</span></label>
|
|
<input type="text" id="in_from" name="in_from" placeholder="ICAO code or airport name" autocomplete="off" required />
|
|
<div id="arrival-airport-lookup-results" class="ppr-lookup" aria-live="polite"></div>
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="eta-date">Estimated Time of Arrival (Local Time) <span aria-hidden="true">*</span></label>
|
|
<div class="ppr-date-time">
|
|
<input type="date" id="eta-date" name="eta-date" required />
|
|
<select id="eta-time" name="eta-time" required>
|
|
<option value="">Select Time</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="pob_in">Persons on Board (Arrival) <span aria-hidden="true">*</span></label>
|
|
<input type="number" id="pob_in" name="pob_in" min="1" inputmode="numeric" required />
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="fuel">Fuel Required</label>
|
|
<select id="fuel" name="fuel">
|
|
<option value="">None</option>
|
|
<option value="100LL">100LL</option>
|
|
<option value="JET A1">JET A1</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="out_to">Departing To</label>
|
|
<input type="text" id="out_to" name="out_to" placeholder="ICAO code or airport name" autocomplete="off" />
|
|
<div id="departure-airport-lookup-results" class="ppr-lookup" aria-live="polite"></div>
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="etd-date">Estimated Time of Departure (Local Time)</label>
|
|
<div class="ppr-date-time">
|
|
<input type="date" id="etd-date" name="etd-date" />
|
|
<select id="etd-time" name="etd-time">
|
|
<option value="">Select Time</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="pob_out">Persons on Board (Departure)</label>
|
|
<input type="number" id="pob_out" name="pob_out" min="1" inputmode="numeric" />
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="email">Email Address</label>
|
|
<input type="email" id="email" name="email" autocomplete="email" />
|
|
</div>
|
|
|
|
<div class="ppr-field">
|
|
<label for="phone">Phone Number</label>
|
|
<input type="tel" id="phone" name="phone" autocomplete="tel" />
|
|
</div>
|
|
|
|
<div class="ppr-field ppr-full">
|
|
<label for="notes">Additional Notes</label>
|
|
<textarea id="notes" name="notes" rows="4" placeholder="Any special requirements, handling instructions, or additional information..."></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ppr-actions">
|
|
<button type="submit" class="button primary" id="submit-btn">Submit PPR Request</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="ppr-loading" id="loading" role="status" aria-live="polite">
|
|
<span class="ppr-spinner" aria-hidden="true"></span>
|
|
Submitting your PPR request...
|
|
</div>
|
|
|
|
<div class="ppr-success notice" id="success-message" role="status" aria-live="polite">
|
|
<h3>PPR Request Submitted.</h3>
|
|
<p>Your PPR request has been submitted. You will receive confirmation via email if provided.</p>
|
|
<p><strong>Please note:</strong> PPR requests are accepted by default. We will contact you if additional information is required. Remember to check NOTAMs before your flight.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<div id="notification" class="ppr-notification" role="status" aria-live="polite"></div>
|
|
|
|
<script define:vars={{ pprApiBase }}>
|
|
(() => {
|
|
const API_BASE = pprApiBase;
|
|
let etdManuallyEdited = false;
|
|
let aircraftLookupTimeout;
|
|
let arrivalAirportLookupTimeout;
|
|
let departureAirportLookupTimeout;
|
|
|
|
const get = (id) => document.getElementById(id);
|
|
|
|
function setLookupStatus(results, message, className) {
|
|
results.replaceChildren();
|
|
if (!message) return;
|
|
const status = document.createElement('span');
|
|
status.className = className;
|
|
status.textContent = message;
|
|
results.append(status);
|
|
}
|
|
|
|
function createOptionList(items, renderItem) {
|
|
const list = document.createElement('div');
|
|
list.className = 'ppr-option-list';
|
|
items.forEach((item) => list.append(renderItem(item)));
|
|
return list;
|
|
}
|
|
|
|
function createAircraftOption(aircraft, fallbackRegistration) {
|
|
const registration = aircraft.registration || fallbackRegistration.toUpperCase();
|
|
const typeCode = aircraft.type_code || '';
|
|
const option = document.createElement('button');
|
|
option.type = 'button';
|
|
option.className = 'ppr-option';
|
|
option.addEventListener('mousedown', (event) => event.preventDefault());
|
|
option.addEventListener('click', () => selectAircraft(registration, typeCode));
|
|
|
|
const code = document.createElement('span');
|
|
code.className = 'ppr-option-code';
|
|
code.textContent = registration;
|
|
|
|
const details = document.createElement('span');
|
|
details.className = 'ppr-option-detail';
|
|
details.textContent = `${typeCode || 'Unknown'}${aircraft.model ? ` (${aircraft.model})` : ''}`;
|
|
|
|
option.append(code, details);
|
|
return option;
|
|
}
|
|
|
|
function createAirportOption(fieldId, airport) {
|
|
const option = document.createElement('button');
|
|
option.type = 'button';
|
|
option.className = 'ppr-option';
|
|
option.addEventListener('mousedown', (event) => event.preventDefault());
|
|
option.addEventListener('click', () => selectAirport(fieldId, airport.icao));
|
|
|
|
const code = document.createElement('span');
|
|
code.className = 'ppr-option-code';
|
|
code.textContent = `${airport.icao}/${airport.iata || ''}`;
|
|
|
|
const details = document.createElement('span');
|
|
details.className = 'ppr-option-detail';
|
|
details.textContent = `${airport.name}, ${airport.country}`;
|
|
|
|
option.append(code, details);
|
|
return option;
|
|
}
|
|
|
|
function selectAircraft(registration, typeCode) {
|
|
get('ac_reg').value = registration;
|
|
get('ac_type').value = typeCode;
|
|
get('aircraft-lookup-results').replaceChildren();
|
|
get('ac_reg').blur();
|
|
}
|
|
|
|
function selectAirport(fieldId, icaoCode) {
|
|
get(fieldId).value = icaoCode;
|
|
const resultsId = fieldId === 'in_from' ? 'arrival-airport-lookup-results' : 'departure-airport-lookup-results';
|
|
get(resultsId).replaceChildren();
|
|
get(fieldId).blur();
|
|
}
|
|
|
|
function initializeTimeDropdowns() {
|
|
['eta-time', 'etd-time'].forEach((selectId) => {
|
|
const select = get(selectId);
|
|
select.replaceChildren(new Option('Select Time', ''));
|
|
|
|
for (let hour = 0; hour < 24; hour += 1) {
|
|
for (let minute = 0; minute < 60; minute += 15) {
|
|
const timeString = `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
|
|
select.append(new Option(timeString, timeString));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function formatDate(date) {
|
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
|
}
|
|
|
|
function formatTime(date) {
|
|
return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
|
}
|
|
|
|
function updateETDFromETA() {
|
|
if (etdManuallyEdited) return;
|
|
|
|
const etaDate = get('eta-date').value;
|
|
const etaTime = get('eta-time').value;
|
|
if (!etaDate || !etaTime) return;
|
|
|
|
const etd = new Date(new Date(`${etaDate}T${etaTime}`).getTime() + 2 * 60 * 60 * 1000);
|
|
get('etd-date').value = formatDate(etd);
|
|
get('etd-time').value = formatTime(etd);
|
|
}
|
|
|
|
function setDefaultDateTime() {
|
|
const nextHour = new Date();
|
|
nextHour.setHours(nextHour.getHours() + 1, 0, 0, 0);
|
|
|
|
const etd = new Date(nextHour);
|
|
etd.setHours(nextHour.getHours() + 2);
|
|
|
|
get('eta-date').value = formatDate(nextHour);
|
|
get('eta-time').value = formatTime(nextHour);
|
|
get('etd-date').value = formatDate(etd);
|
|
get('etd-time').value = formatTime(etd);
|
|
}
|
|
|
|
function showNotification(message, isError = false) {
|
|
const notification = get('notification');
|
|
notification.textContent = message;
|
|
notification.className = `ppr-notification${isError ? ' error' : ''}`;
|
|
|
|
requestAnimationFrame(() => notification.classList.add('show'));
|
|
window.setTimeout(() => notification.classList.remove('show'), 5000);
|
|
}
|
|
|
|
async function handleAircraftLookup(registration) {
|
|
clearTimeout(aircraftLookupTimeout);
|
|
const results = get('aircraft-lookup-results');
|
|
|
|
if (!registration || registration.length < 4) {
|
|
results.replaceChildren();
|
|
return;
|
|
}
|
|
|
|
setLookupStatus(results, 'Searching...', 'ppr-lookup-searching');
|
|
aircraftLookupTimeout = window.setTimeout(async () => {
|
|
try {
|
|
const response = await fetch(`${API_BASE}/aircraft/public/lookup/${registration.toUpperCase()}`);
|
|
if (!response.ok) {
|
|
results.replaceChildren();
|
|
return;
|
|
}
|
|
|
|
const data = await response.json();
|
|
if (!data || data.length === 0) {
|
|
setLookupStatus(results, 'No aircraft found with this registration', 'ppr-lookup-muted');
|
|
return;
|
|
}
|
|
|
|
if (data.length === 1) {
|
|
const aircraft = data[0];
|
|
get('ac_reg').value = aircraft.registration || registration.toUpperCase();
|
|
if (!get('ac_type').value) get('ac_type').value = aircraft.type_code || '';
|
|
}
|
|
|
|
if (data.length <= 10) {
|
|
results.replaceChildren(createOptionList(data, (item) => createAircraftOption(item, registration)));
|
|
return;
|
|
}
|
|
|
|
setLookupStatus(results, 'Too many matches, please be more specific', 'ppr-lookup-muted');
|
|
} catch (error) {
|
|
console.error('Aircraft lookup error:', error);
|
|
results.replaceChildren();
|
|
}
|
|
}, 500);
|
|
}
|
|
|
|
async function handleAirportLookup(query, fieldId, resultsId, timeoutSetter) {
|
|
const results = get(resultsId);
|
|
if (!query || query.length < 2) {
|
|
results.replaceChildren();
|
|
return;
|
|
}
|
|
|
|
setLookupStatus(results, 'Searching...', 'ppr-lookup-searching');
|
|
timeoutSetter(window.setTimeout(async () => {
|
|
try {
|
|
const response = await fetch(`${API_BASE}/airport/public/lookup/${query.toUpperCase()}`);
|
|
if (!response.ok) {
|
|
results.replaceChildren();
|
|
return;
|
|
}
|
|
|
|
const data = await response.json();
|
|
if (!data || data.length === 0) {
|
|
setLookupStatus(results, 'No airport found', 'ppr-lookup-muted');
|
|
return;
|
|
}
|
|
|
|
if (data.length <= 10) {
|
|
results.replaceChildren(createOptionList(data, (airport) => createAirportOption(fieldId, airport)));
|
|
return;
|
|
}
|
|
|
|
setLookupStatus(results, 'Too many matches, please be more specific', 'ppr-lookup-muted');
|
|
} catch (error) {
|
|
console.error('Airport lookup error:', error);
|
|
results.replaceChildren();
|
|
}
|
|
}, 500));
|
|
}
|
|
|
|
function buildPprData(form) {
|
|
const formData = new FormData(form);
|
|
const pprData = {};
|
|
|
|
formData.forEach((value, key) => {
|
|
const fieldValue = String(value).trim();
|
|
if (!fieldValue) return;
|
|
|
|
if (key === 'pob_in' || key === 'pob_out') {
|
|
pprData[key] = Number.parseInt(fieldValue, 10);
|
|
} else if (key === 'eta-date' && formData.get('eta-time')) {
|
|
pprData.eta = new Date(`${fieldValue}T${formData.get('eta-time')}`).toISOString();
|
|
} else if (key === 'etd-date' && formData.get('etd-time')) {
|
|
pprData.etd = new Date(`${fieldValue}T${formData.get('etd-time')}`).toISOString();
|
|
} else if (key !== 'eta-time' && key !== 'etd-time') {
|
|
pprData[key] = fieldValue;
|
|
}
|
|
});
|
|
|
|
return pprData;
|
|
}
|
|
|
|
async function handleSubmit(event) {
|
|
event.preventDefault();
|
|
|
|
const form = event.currentTarget;
|
|
const submitButton = get('submit-btn');
|
|
get('loading').style.display = 'flex';
|
|
submitButton.disabled = true;
|
|
submitButton.textContent = 'Submitting...';
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/pprs/public`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(buildPprData(form)),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
throw new Error(errorData.detail || `Submission failed: ${response.status}`);
|
|
}
|
|
|
|
form.style.display = 'none';
|
|
get('success-message').style.display = 'block';
|
|
showNotification('PPR request submitted successfully!');
|
|
} catch (error) {
|
|
console.error('Error submitting PPR:', error);
|
|
showNotification(`Error submitting PPR: ${error.message}`, true);
|
|
} finally {
|
|
get('loading').style.display = 'none';
|
|
submitButton.disabled = false;
|
|
submitButton.textContent = 'Submit PPR Request';
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
initializeTimeDropdowns();
|
|
setDefaultDateTime();
|
|
|
|
get('ac_reg').addEventListener('input', (event) => handleAircraftLookup(event.target.value));
|
|
get('ac_reg').addEventListener('blur', () => window.setTimeout(() => get('aircraft-lookup-results').replaceChildren(), 150));
|
|
|
|
get('in_from').addEventListener('input', (event) => {
|
|
clearTimeout(arrivalAirportLookupTimeout);
|
|
handleAirportLookup(event.target.value, 'in_from', 'arrival-airport-lookup-results', (timeout) => {
|
|
arrivalAirportLookupTimeout = timeout;
|
|
});
|
|
});
|
|
get('in_from').addEventListener('blur', () => window.setTimeout(() => get('arrival-airport-lookup-results').replaceChildren(), 150));
|
|
|
|
get('out_to').addEventListener('input', (event) => {
|
|
clearTimeout(departureAirportLookupTimeout);
|
|
handleAirportLookup(event.target.value, 'out_to', 'departure-airport-lookup-results', (timeout) => {
|
|
departureAirportLookupTimeout = timeout;
|
|
});
|
|
});
|
|
get('out_to').addEventListener('blur', () => window.setTimeout(() => get('departure-airport-lookup-results').replaceChildren(), 150));
|
|
|
|
get('eta-date').addEventListener('change', updateETDFromETA);
|
|
get('eta-time').addEventListener('change', updateETDFromETA);
|
|
get('etd-date').addEventListener('change', () => {
|
|
etdManuallyEdited = true;
|
|
});
|
|
get('etd-time').addEventListener('change', () => {
|
|
etdManuallyEdited = true;
|
|
});
|
|
get('ppr-form').addEventListener('submit', handleSubmit);
|
|
});
|
|
})();
|
|
</script>
|
|
|
|
<style>
|
|
.ppr-shell {
|
|
display: grid;
|
|
gap: 1.25rem;
|
|
margin-block: 1.5rem 0;
|
|
}
|
|
|
|
.ppr-head {
|
|
display: grid;
|
|
gap: 0.55rem;
|
|
}
|
|
|
|
.ppr-note {
|
|
margin: 0;
|
|
color: var(--muted);
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.ppr-form {
|
|
display: grid;
|
|
gap: 1.2rem;
|
|
}
|
|
|
|
.ppr-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
|
|
.ppr-field {
|
|
display: grid;
|
|
gap: 0.4rem;
|
|
align-content: start;
|
|
}
|
|
|
|
.ppr-full {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.ppr-field label {
|
|
color: var(--text);
|
|
font-size: 0.92rem;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.ppr-field label span {
|
|
color: var(--critical);
|
|
}
|
|
|
|
.ppr-field input,
|
|
.ppr-field select,
|
|
.ppr-field textarea {
|
|
width: 100%;
|
|
min-height: 2.85rem;
|
|
border: 1px solid rgba(16, 34, 51, 0.16);
|
|
border-radius: 0.7rem;
|
|
background: rgba(255, 255, 255, 0.88);
|
|
color: var(--text);
|
|
font: inherit;
|
|
font-size: 1rem;
|
|
padding: 0.7rem 0.82rem;
|
|
}
|
|
|
|
.ppr-field textarea {
|
|
min-height: 7.5rem;
|
|
resize: vertical;
|
|
}
|
|
|
|
.ppr-field input:focus,
|
|
.ppr-field select:focus,
|
|
.ppr-field textarea:focus {
|
|
outline: none;
|
|
border-color: var(--brand-2);
|
|
box-shadow: 0 0 0 0.2rem rgba(29, 118, 184, 0.16);
|
|
}
|
|
|
|
.ppr-date-time {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) minmax(8rem, 0.72fr);
|
|
gap: 0.6rem;
|
|
}
|
|
|
|
.ppr-lookup {
|
|
color: var(--muted);
|
|
font-size: 0.88rem;
|
|
}
|
|
|
|
.ppr-lookup-searching {
|
|
color: var(--brand-2);
|
|
font-weight: 700;
|
|
}
|
|
|
|
.ppr-lookup-muted {
|
|
color: var(--muted);
|
|
font-style: italic;
|
|
}
|
|
|
|
.ppr-option-list {
|
|
display: grid;
|
|
max-height: 14rem;
|
|
overflow-y: auto;
|
|
border: 1px solid var(--line);
|
|
border-radius: 0.7rem;
|
|
background: var(--panel-strong);
|
|
box-shadow: 0 0.7rem 1.8rem rgba(16, 34, 51, 0.08);
|
|
}
|
|
|
|
.ppr-option {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 0.75rem;
|
|
width: 100%;
|
|
padding: 0.7rem 0.8rem;
|
|
border: 0;
|
|
border-bottom: 1px solid rgba(16, 34, 51, 0.08);
|
|
background: transparent;
|
|
color: var(--text);
|
|
cursor: pointer;
|
|
font: inherit;
|
|
text-align: left;
|
|
}
|
|
|
|
.ppr-option:hover,
|
|
.ppr-option:focus {
|
|
outline: none;
|
|
background: var(--brand-soft);
|
|
}
|
|
|
|
.ppr-option:last-child {
|
|
border-bottom: 0;
|
|
}
|
|
|
|
.ppr-option-code {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.ppr-option-detail {
|
|
color: var(--muted);
|
|
font-size: 0.86rem;
|
|
text-align: right;
|
|
}
|
|
|
|
.ppr-actions {
|
|
display: flex;
|
|
justify-content: flex-start;
|
|
padding-top: 0.4rem;
|
|
}
|
|
|
|
.ppr-actions .button {
|
|
border: 0;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.ppr-actions .button:disabled {
|
|
cursor: wait;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.ppr-loading {
|
|
display: none;
|
|
align-items: center;
|
|
gap: 0.7rem;
|
|
color: var(--brand);
|
|
font-weight: 800;
|
|
}
|
|
|
|
.ppr-spinner {
|
|
width: 1.45rem;
|
|
height: 1.45rem;
|
|
border: 3px solid rgba(29, 118, 184, 0.18);
|
|
border-top-color: var(--brand-2);
|
|
border-radius: 50%;
|
|
animation: ppr-spin 0.8s linear infinite;
|
|
}
|
|
|
|
.ppr-success {
|
|
display: none;
|
|
border-left-color: #257b4c;
|
|
}
|
|
|
|
.ppr-notification {
|
|
position: fixed;
|
|
top: 1rem;
|
|
right: 1rem;
|
|
z-index: 60;
|
|
max-width: min(24rem, calc(100vw - 2rem));
|
|
padding: 0.85rem 1rem;
|
|
border-radius: 0.8rem;
|
|
background: #257b4c;
|
|
color: white;
|
|
box-shadow: var(--shadow);
|
|
font-weight: 800;
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
transform: translateY(-0.65rem);
|
|
transition: opacity 0.18s ease, transform 0.18s ease;
|
|
}
|
|
|
|
.ppr-notification.show {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.ppr-notification.error {
|
|
background: var(--critical);
|
|
}
|
|
|
|
@keyframes ppr-spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
@media (max-width: 720px) {
|
|
.ppr-grid,
|
|
.ppr-date-time {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.ppr-actions,
|
|
.ppr-actions .button {
|
|
width: 100%;
|
|
}
|
|
|
|
.ppr-option {
|
|
display: grid;
|
|
gap: 0.2rem;
|
|
}
|
|
|
|
.ppr-option-detail {
|
|
text-align: left;
|
|
}
|
|
}
|
|
</style>
|