514 lines
22 KiB
HTML
514 lines
22 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}My Shifts — Bid Checker{% endblock %}
|
||
{% block content %}
|
||
|
||
<!-- ── Page header ─────────────────────────────────────────── -->
|
||
<div class="page-header">
|
||
<div>
|
||
<h1>My Shift — Website Checklist</h1>
|
||
<div class="page-subtitle" id="today-date"></div>
|
||
</div>
|
||
<div class="flex gap-1 items-center flex-wrap">
|
||
{% for s in shifts %}
|
||
<span class="badge badge-accent">{{ s.name }}
|
||
{% if s.start_time and s.end_time %}
|
||
· {{ s.start_time|hhmm }}–{{ s.end_time|hhmm }}
|
||
{% endif %}
|
||
</span>
|
||
{% endfor %}
|
||
<button class="btn btn-secondary btn-sm" onclick="location.reload()">↻ Refresh</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Progress bar ─────────────────────────────────────────── -->
|
||
<div class="progress-strip">
|
||
<div class="progress-strip-bar">
|
||
<div class="progress-strip-fill {% if pct == 100 %}fill-success{% elif pct >= 50 %}fill-warning{% else %}fill-danger{% endif %}"
|
||
style="width:{{ pct }}%"></div>
|
||
</div>
|
||
<div class="progress-strip-label">
|
||
<strong>{{ checked }} / {{ total }}</strong> checked
|
||
<span class="text-muted"> · {{ pct }}%</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Action bar ───────────────────────────────────────────── -->
|
||
<div class="action-bar">
|
||
<!-- Search: magnifier on the RIGHT -->
|
||
<div class="search-wrap">
|
||
<input type="text" id="site-search" placeholder="Search sites…" autocomplete="off">
|
||
<span class="search-icon">🔍</span>
|
||
</div>
|
||
<button class="btn btn-secondary btn-sm" id="btn-select-all">☑ Select All Unchecked</button>
|
||
<button class="btn btn-success btn-sm" id="btn-bulk-check">✔ Mark Selected Checked</button>
|
||
</div>
|
||
|
||
<!-- ── Site list grouped by frequency ──────────────────────── -->
|
||
<div id="site-list">
|
||
|
||
{# Group sites by check_type #}
|
||
{% set daily_sites = sites | selectattr('check_type', 'equalto', 'daily') | list %}
|
||
{% set weekly_sites = sites | selectattr('check_type', 'equalto', 'weekly') | list %}
|
||
{% set other_sites = sites | rejectattr('check_type', 'in', ['daily','weekly']) | list %}
|
||
|
||
{% for group_name, group_sites in [('Daily', daily_sites), ('Weekly', weekly_sites), ('Other', other_sites)] %}
|
||
{% if group_sites %}
|
||
|
||
<!-- Group header (collapsible) -->
|
||
<div class="group-header" data-group="{{ group_name | lower }}" onclick="toggleGroup('{{ group_name | lower }}')">
|
||
<span class="group-toggle" id="toggle-{{ group_name | lower }}">▾</span>
|
||
<span class="group-label">{{ group_name }}</span>
|
||
<span class="group-count">
|
||
{{ group_sites | selectattr('check_id') | list | length }} / {{ group_sites | length }} checked
|
||
</span>
|
||
<div class="group-mini-bar">
|
||
{% set g_total = group_sites | length %}
|
||
{% set g_checked = group_sites | selectattr('check_id') | list | length %}
|
||
{% set g_pct = ((g_checked / g_total) * 100) | int if g_total > 0 else 0 %}
|
||
<div class="group-mini-fill
|
||
{% if g_pct == 100 %}fill-success{% elif g_pct >= 50 %}fill-warning{% else %}fill-danger{% endif %}"
|
||
style="width:{{ g_pct }}%"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sites in this group -->
|
||
<div class="site-group" id="group-{{ group_name | lower }}">
|
||
{% for site in group_sites %}
|
||
<div class="site-card {% if site.check_id %}is-checked{% endif %}"
|
||
data-id="{{ site.id }}"
|
||
data-group="{{ group_name | lower }}"
|
||
data-name="{{ site.name | lower }}"
|
||
data-url="{{ (site.url or '') | lower }}"
|
||
data-site-name="{{ site.name }}"
|
||
data-user-note="{{ site.user_note or '' }}">
|
||
|
||
<!-- Row 1: checkbox · status · info · actions · health -->
|
||
<div class="sc-row1">
|
||
|
||
<div class="sc-select">
|
||
<input type="checkbox" class="bulk-cb" data-id="{{ site.id }}"
|
||
aria-label="Select {{ site.name }} for bulk check"
|
||
{% if site.check_id %}disabled{% endif %}>
|
||
</div>
|
||
|
||
<div class="sc-status">
|
||
{% if site.check_id %}
|
||
<span class="status-dot dot-checked"
|
||
title="Checked at {{ site.checked_at.strftime('%H:%M') if site.checked_at else 'today' }}">✔</span>
|
||
{% else %}
|
||
<span class="status-dot dot-unchecked">○</span>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div class="sc-body">
|
||
<div class="sc-title-row">
|
||
<a class="sc-name" href="{{ site.url }}" target="_blank" rel="noopener">{{ site.name }}</a>
|
||
<span class="badge {% if site.check_type == 'weekly' %}badge-warning{% else %}badge-muted{% endif %}">
|
||
{{ site.check_type | capitalize }}
|
||
</span>
|
||
{% if site.check_id and site.checked_at %}
|
||
<span class="sc-checked-time text-success">✔ {{ site.checked_at.strftime('%H:%M') }}</span>
|
||
{% endif %}
|
||
</div>
|
||
<div class="sc-url">{{ site.url }}</div>
|
||
<div class="sc-meta">
|
||
{% if site.site_note %}
|
||
<span class="sc-meta-item">📌 {{ site.site_note }}</span>
|
||
{% endif %}
|
||
{% if site.shift_names %}
|
||
<span class="sc-meta-item text-accent">🕐 {{ site.shift_names }}</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sc-actions">
|
||
{% if site.check_id %}
|
||
<span class="btn btn-success btn-sm checked-indicator">✔ Checked</span>
|
||
<button class="btn btn-secondary btn-sm js-note"
|
||
data-id="{{ site.id }}"
|
||
data-note="{{ site.user_note or '' }}">📝 Note</button>
|
||
<button class="btn btn-secondary btn-sm js-creds"
|
||
data-id="{{ site.id }}">🔑 Creds</button>
|
||
<form method="post"
|
||
action="{{ url_for('user_dashboard.uncheck_site', website_id=site.id) }}"
|
||
style="display:inline">
|
||
<button class="btn btn-secondary btn-sm js-undo" type="button"
|
||
data-name="{{ site.name }}">↩ Undo</button>
|
||
</form>
|
||
{% else %}
|
||
<button class="btn btn-primary btn-sm js-check"
|
||
data-id="{{ site.id }}"
|
||
data-name="{{ site.name }}">✔ Mark Checked</button>
|
||
<button class="btn btn-secondary btn-sm js-note"
|
||
data-id="{{ site.id }}"
|
||
data-note="">📝 Note</button>
|
||
<button class="btn btn-secondary btn-sm js-creds"
|
||
data-id="{{ site.id }}">🔑 Creds</button>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div class="sc-health">
|
||
<span class="health-dot" id="health-{{ site.id }}" title="Checking…">●</span>
|
||
</div>
|
||
|
||
</div><!-- /sc-row1 -->
|
||
|
||
<!-- Row 2: user note (only shown when a note exists) -->
|
||
{% if site.user_note %}
|
||
<div class="sc-row2">
|
||
<span class="sc-note-row">📝 {{ site.user_note }}</span>
|
||
</div>
|
||
{% endif %}
|
||
|
||
</div><!-- /site-card -->
|
||
{% endfor %}
|
||
</div><!-- /site-group -->
|
||
|
||
{% endif %}
|
||
{% endfor %}
|
||
|
||
{% if not sites %}
|
||
<div class="empty-state">
|
||
<div class="empty-icon">✅</div>
|
||
<p>No sites to check today, or you're all done!</p>
|
||
</div>
|
||
{% endif %}
|
||
|
||
</div><!-- /site-list -->
|
||
|
||
<!-- ── Note Modal ──────────────────────────────────────────── -->
|
||
<div class="modal-overlay" id="modal-note">
|
||
<div class="modal">
|
||
<div class="modal-header">
|
||
<span class="modal-title">Update Note</span>
|
||
<button class="modal-close" onclick="closeModal('modal-note')">✕</button>
|
||
</div>
|
||
<form method="post" id="note-form">
|
||
<div class="modal-body">
|
||
<div class="form-group">
|
||
<label>Note</label>
|
||
<textarea name="user_note" id="note-text" rows="3"
|
||
placeholder="Any observations or notes…"></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" onclick="closeModal('modal-note')">Cancel</button>
|
||
<button type="submit" class="btn btn-primary">Save Note</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Credentials Modal ────────────────────────────────────── -->
|
||
<div class="modal-overlay" id="modal-creds">
|
||
<div class="modal">
|
||
<div class="modal-header">
|
||
<span class="modal-title">🔑 Credentials</span>
|
||
<button class="modal-close" onclick="closeModal('modal-creds')">✕</button>
|
||
</div>
|
||
<div class="modal-body" id="creds-body">
|
||
<div class="text-center text-muted">Loading…</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-secondary" onclick="closeModal('modal-creds'); document.getElementById('creds-body').innerHTML=''">Close</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
/* ── Date ──────────────────────────────────────────────────── */
|
||
document.getElementById('today-date').textContent =
|
||
new Date().toLocaleDateString('en-US', {weekday:'long',year:'numeric',month:'long',day:'numeric'});
|
||
|
||
/* ── Group collapse/expand ─────────────────────────────────── */
|
||
var _collapsed = {};
|
||
|
||
function toggleGroup(name) {
|
||
var group = document.getElementById('group-' + name);
|
||
var toggle = document.getElementById('toggle-' + name);
|
||
if (!group) return;
|
||
_collapsed[name] = !_collapsed[name];
|
||
group.style.display = _collapsed[name] ? 'none' : '';
|
||
toggle.textContent = _collapsed[name] ? '▸' : '▾';
|
||
}
|
||
|
||
/* ── Search — shows matching cards, auto-expands collapsed groups ── */
|
||
var _searchTimer = null;
|
||
document.getElementById('site-search').addEventListener('input', function() {
|
||
var val = this.value;
|
||
clearTimeout(_searchTimer);
|
||
_searchTimer = setTimeout(function() {
|
||
var q = val.trim().toLowerCase();
|
||
document.querySelectorAll('.site-card').forEach(function(card) {
|
||
var match = !q || card.dataset.name.includes(q) || card.dataset.url.includes(q);
|
||
card.style.display = match ? '' : 'none';
|
||
|
||
if (match && q) {
|
||
var group = card.closest('.site-group');
|
||
if (group) {
|
||
group.style.display = '';
|
||
var name = group.id.replace('group-', '');
|
||
var toggle = document.getElementById('toggle-' + name);
|
||
if (toggle) toggle.textContent = '▾';
|
||
_collapsed[name] = false;
|
||
}
|
||
}
|
||
});
|
||
}, 250);
|
||
});
|
||
|
||
/* ── Bulk select ───────────────────────────────────────────── */
|
||
document.getElementById('btn-select-all').addEventListener('click', function() {
|
||
document.querySelectorAll('.bulk-cb:not(:disabled)').forEach(function(cb) {
|
||
var card = cb.closest('.site-card');
|
||
if (!card.classList.contains('is-checked') && card.style.display !== 'none')
|
||
cb.checked = true;
|
||
});
|
||
});
|
||
|
||
/* ── Bulk check ────────────────────────────────────────────── */
|
||
document.getElementById('btn-bulk-check').addEventListener('click', function() {
|
||
var selected = Array.from(document.querySelectorAll('.bulk-cb:checked')).map(function(cb){ return cb.dataset.id; });
|
||
if (!selected.length) { alert('No sites selected. Tick the checkboxes first.'); return; }
|
||
if (!confirm('Mark ' + selected.length + ' site(s) as checked?')) return;
|
||
Promise.all(selected.map(function(id) {
|
||
return fetch('/dashboard/check/' + id, {
|
||
method: 'POST', credentials: 'same-origin',
|
||
headers: {'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRFToken': getCsrfToken()},
|
||
body: 'user_note='
|
||
});
|
||
})).then(function() { location.reload(); });
|
||
});
|
||
|
||
/* ── Delegated button handler ──────────────────────────────── */
|
||
document.getElementById('site-list').addEventListener('click', function(e) {
|
||
var btn = e.target.closest('button[class]');
|
||
if (!btn) return;
|
||
|
||
/* Mark Checked */
|
||
if (btn.classList.contains('js-check')) {
|
||
var siteName = btn.dataset.name;
|
||
btn.disabled = true;
|
||
fetch('/dashboard/check/' + btn.dataset.id, {
|
||
method: 'POST', credentials: 'same-origin',
|
||
headers: {'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRFToken': getCsrfToken()},
|
||
body: 'user_note='
|
||
}).then(function(r) {
|
||
if (!r.ok) throw new Error('Server error ' + r.status);
|
||
var toast = document.createElement('div');
|
||
toast.className = 'alert alert-success';
|
||
toast.style.cssText = 'position:fixed;top:1rem;right:1rem;z-index:9999;min-width:220px;box-shadow:var(--shadow)';
|
||
toast.textContent = '✔ ' + siteName + ' marked checked';
|
||
document.body.appendChild(toast);
|
||
setTimeout(function() { location.reload(); }, 700);
|
||
}).catch(function(err) {
|
||
btn.disabled = false;
|
||
var toast = document.createElement('div');
|
||
toast.className = 'alert alert-danger';
|
||
toast.style.cssText = 'position:fixed;top:1rem;right:1rem;z-index:9999;min-width:220px;box-shadow:var(--shadow)';
|
||
toast.textContent = '✖ Failed to mark checked. Please try again.';
|
||
document.body.appendChild(toast);
|
||
setTimeout(function() { toast.remove(); }, 4000);
|
||
});
|
||
return;
|
||
}
|
||
|
||
/* Note */
|
||
if (btn.classList.contains('js-note')) {
|
||
document.getElementById('note-form').action = '/dashboard/note/' + btn.dataset.id;
|
||
document.getElementById('note-text').value = btn.dataset.note || '';
|
||
openModal('modal-note');
|
||
return;
|
||
}
|
||
|
||
/* Credentials */
|
||
if (btn.classList.contains('js-creds')) {
|
||
var body = document.getElementById('creds-body');
|
||
body.innerHTML = '<div class="text-center text-muted">Loading…</div>';
|
||
openModal('modal-creds');
|
||
fetch('/dashboard/credentials/' + btn.dataset.id)
|
||
.then(function(r){ return r.json(); })
|
||
.then(function(creds) {
|
||
if (!creds.length) {
|
||
body.innerHTML = '<p class="text-muted text-center">No credentials stored.</p>';
|
||
return;
|
||
}
|
||
body.innerHTML = creds.map(function(c, i) {
|
||
var uid = 'pw-' + i + '-' + btn.dataset.id;
|
||
return '<div class="' + (i > 0 ? 'mt-2' : '') + '">'
|
||
+ (c.label ? '<div class="cred-label-heading">' + esc(c.label) + '</div>' : '')
|
||
+ '<div class="cred-row"><span class="cred-key">Username</span>'
|
||
+ '<span class="cred-val">' + esc(c.username || '—') + '</span>'
|
||
+ '<button class="btn btn-secondary btn-sm" data-copy="' + esc(c.username) + '">📋</button></div>'
|
||
+ '<div class="cred-row"><span class="cred-key">Password</span>'
|
||
+ '<span class="cred-val pw-mask" id="' + uid + '">' + esc(c.password) + '</span>'
|
||
+ '<button class="btn btn-secondary btn-sm" data-toggle-pw="' + uid + '">👁</button>'
|
||
+ '<button class="btn btn-secondary btn-sm" data-copy="' + esc(c.password) + '">📋</button></div>'
|
||
+ '</div>'
|
||
+ (i < creds.length - 1 ? '<hr class="divider">' : '');
|
||
}).join('');
|
||
})
|
||
.catch(function(){ body.innerHTML = '<p class="alert alert-danger">Failed to load.</p>'; });
|
||
return;
|
||
}
|
||
|
||
/* Undo */
|
||
if (btn.classList.contains('js-undo')) {
|
||
if (!confirm('Remove check for ' + btn.dataset.name + '?')) return;
|
||
var siteName = btn.dataset.name;
|
||
var formAction = btn.closest('form').action;
|
||
btn.disabled = true;
|
||
fetch(formAction, {
|
||
method: 'POST', credentials: 'same-origin',
|
||
headers: {'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRFToken': getCsrfToken()},
|
||
body: ''
|
||
}).then(function(r) {
|
||
if (!r.ok) throw new Error('Server error ' + r.status);
|
||
var toast = document.createElement('div');
|
||
toast.className = 'alert alert-info';
|
||
toast.style.cssText = 'position:fixed;top:1rem;right:1rem;z-index:9999;min-width:220px;box-shadow:var(--shadow)';
|
||
toast.textContent = '↩ Check removed for ' + siteName;
|
||
document.body.appendChild(toast);
|
||
setTimeout(function() { location.reload(); }, 700);
|
||
}).catch(function(err) {
|
||
btn.disabled = false;
|
||
var toast = document.createElement('div');
|
||
toast.className = 'alert alert-danger';
|
||
toast.style.cssText = 'position:fixed;top:1rem;right:1rem;z-index:9999;min-width:220px;box-shadow:var(--shadow)';
|
||
toast.textContent = '✖ Failed to remove check. Please try again.';
|
||
document.body.appendChild(toast);
|
||
setTimeout(function() { toast.remove(); }, 4000);
|
||
});
|
||
return;
|
||
}
|
||
});
|
||
|
||
/* ── Credential modal actions ──────────────────────────────── */
|
||
document.getElementById('modal-creds').addEventListener('click', function(e) {
|
||
/* Clear body when clicking the backdrop */
|
||
if (e.target === this) {
|
||
document.getElementById('creds-body').innerHTML = '';
|
||
return;
|
||
}
|
||
var copyBtn = e.target.closest('[data-copy]');
|
||
if (copyBtn) { copyToClipboard(copyBtn.dataset.copy, copyBtn); return; }
|
||
var toggleBtn = e.target.closest('[data-toggle-pw]');
|
||
if (toggleBtn) {
|
||
var el = document.getElementById(toggleBtn.dataset.togglePw);
|
||
if (el) {
|
||
var masked = el.classList.toggle('pw-mask');
|
||
toggleBtn.textContent = masked ? '👁' : '🙈';
|
||
}
|
||
}
|
||
});
|
||
|
||
/* ── Health dots — batched with max 4 concurrent requests ─── */
|
||
(function() {
|
||
var cards = Array.from(document.querySelectorAll('.site-card'));
|
||
var CONCURRENCY = 4, idx = 0;
|
||
|
||
function probe() {
|
||
if (idx >= cards.length) return;
|
||
var card = cards[idx++];
|
||
var id = card.dataset.id;
|
||
var dot = document.getElementById('health-' + id);
|
||
if (!dot) { probe(); return; }
|
||
fetch('/dashboard/health/' + id, {credentials: 'same-origin'})
|
||
.then(function(r) { return r.json(); })
|
||
.then(function(d) {
|
||
if (d.status === 'ok') {
|
||
dot.style.color = d.ms > 3000 ? '#d97706' : '#16a34a';
|
||
dot.title = 'Reachable (' + d.ms + 'ms)';
|
||
} else if (d.status === 'timeout') {
|
||
dot.style.color = '#d97706';
|
||
dot.title = 'Timeout (>6s)';
|
||
} else {
|
||
dot.style.color = '#dc2626';
|
||
dot.title = 'Unreachable';
|
||
}
|
||
})
|
||
.catch(function() {
|
||
dot.style.color = '#9ca3af';
|
||
dot.title = 'Health check failed';
|
||
})
|
||
.finally(probe);
|
||
}
|
||
|
||
for (var i = 0; i < Math.min(CONCURRENCY, cards.length); i++) probe();
|
||
})();
|
||
</script>
|
||
|
||
<style>
|
||
/* ── Group header ───────────────────────────────────────────── */
|
||
.group-header {
|
||
display:flex; align-items:center; gap:.65rem;
|
||
padding:.6rem 1rem; margin-bottom:2px; margin-top:.75rem;
|
||
background:var(--bg-subtle); border:1px solid var(--border);
|
||
border-radius:var(--r); cursor:pointer;
|
||
transition:background var(--t);
|
||
user-select:none;
|
||
}
|
||
.group-header:first-child { margin-top:0; }
|
||
.group-header:hover { background:var(--bg-hover); }
|
||
.group-toggle { font-size:.8rem; color:var(--text-muted); width:12px; flex-shrink:0; }
|
||
.group-label { font-size:.85rem; font-weight:700; color:var(--text);
|
||
text-transform:uppercase; letter-spacing:.05em; }
|
||
.group-count { font-size:.8rem; color:var(--text-muted); margin-left:.25rem; }
|
||
.group-mini-bar {
|
||
flex:1; height:5px; background:var(--border); border-radius:999px;
|
||
overflow:hidden; max-width:120px;
|
||
}
|
||
.group-mini-fill {
|
||
height:100%; border-radius:999px; background:var(--accent);
|
||
transition:width .4s ease;
|
||
}
|
||
.group-mini-fill.fill-success { background:var(--success); }
|
||
.group-mini-fill.fill-warning { background:var(--warning); }
|
||
.group-mini-fill.fill-danger { background:var(--danger); }
|
||
|
||
/* ── Site group wrapper ─────────────────────────────────────── */
|
||
.site-group { display:flex; flex-direction:column; gap:.45rem; margin-bottom:.5rem; }
|
||
|
||
/* ── Site card ──────────────────────────────────────────────── */
|
||
.site-card {
|
||
background:var(--bg-white); border:1px solid var(--border);
|
||
border-radius:var(--r-lg); box-shadow:var(--shadow-sm);
|
||
transition:box-shadow var(--t), border-color var(--t);
|
||
overflow:hidden;
|
||
}
|
||
.site-card:hover { box-shadow:var(--shadow); border-color:var(--border-strong); }
|
||
.site-card.is-checked { border-color:var(--success-border); background:#fafffe; }
|
||
.site-card.is-checked:hover { border-color:#86efac; }
|
||
|
||
/* ── Row 1: main content ────────────────────────────────────── */
|
||
.sc-row1 {
|
||
display:flex; align-items:center; gap:.85rem; padding:.95rem 1rem;
|
||
}
|
||
|
||
/* ── Row 2: note row ────────────────────────────────────────── */
|
||
.sc-row2 {
|
||
padding:.45rem 1rem .6rem calc(1rem + 15px + .85rem + 26px + .85rem);
|
||
/* indent to align with sc-body, past checkbox + status */
|
||
border-top:1px dashed var(--border);
|
||
}
|
||
.sc-note-row {
|
||
font-size:.875rem; color:var(--warning);
|
||
background:var(--warning-bg); border:1px solid var(--warning-border);
|
||
border-radius:var(--r-sm); padding:.25rem .65rem;
|
||
display:inline-block; line-height:1.5;
|
||
}
|
||
|
||
/* ── Font size bumps ─────────────────────────────────────────── */
|
||
.sc-name { font-size:1rem; }
|
||
.sc-url { font-size:.76rem; }
|
||
.sc-meta-item{ font-size:.82rem; }
|
||
.sc-checked-time { font-size:.78rem; color:var(--success); font-weight:600; }
|
||
|
||
@media(max-width:700px) {
|
||
.sc-row1 { flex-wrap:wrap; }
|
||
.sc-actions { margin-left:0; flex-direction:column; align-items:flex-start; }
|
||
.sc-url { display:none; }
|
||
.sc-row2 { padding-left:1rem; }
|
||
}
|
||
</style>
|
||
{% endblock %} |