
/* ---------- fonts ---------------------------------------------------------
   Self-hosted so no visitor data reaches a third-party font CDN. Files are
   fetched into public/fonts by scripts/fetch-assets.mjs; if they are absent the
   stack falls back to system faces and the layout still holds. */
@font-face {
  font-family: 'Plus Jakarta Sans';
  src: url('/fonts/plus-jakarta-sans-latin.woff2') format('woff2');
  font-weight: 400 800;
  font-display: swap;
  font-style: normal;
}
@font-face {
  font-family: 'DM Sans';
  src: url('/fonts/dm-sans-latin.woff2') format('woff2');
  font-weight: 400 700;
  font-display: swap;
  font-style: normal;
}

:root {
  --bg: #F0F4F9;
  --text: #1C2C45;
  --text-strong: #1C2D45;
  --muted: #5A7396;
  --nav: #2E4D7A;
  --primary: #4E6FA3;
  --primary-hover: #3E5C89;
  --pill: #7B9EC7;
  --border: #C5D5E8;
  --card: #FFFFFF;
  --footer-text: #B8CEE2;
  /* The one warm colour in the palette. Featured is the only state that earns
     it — it is the paid promotion, and it has to win against blue and green. */
  --featured: #BA7517;

  --radius: 10px;
  --radius-card: 12px;
  --radius-pill: 9999px;

  --shadow-sm: 0 1px 2px 0 rgba(0,0,0,.03), 0 1px 3px 0 rgba(0,0,0,.06);
  --shadow-md: 0 4px 6px -1px rgba(0,0,0,.05), 0 2px 4px -2px rgba(0,0,0,.05);
  --shadow-lg: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -4px rgba(0,0,0,.1);

  --s-xs: 4px; --s-sm: 8px; --s-md: 16px; --s-lg: 24px;
  --s-xl: 32px; --s-2xl: 48px; --s-3xl: 64px;

  --container: 1200px;

  --font-display: 'Plus Jakarta Sans', ui-sans-serif, system-ui, sans-serif;
  --font-body: 'DM Sans', ui-sans-serif, system-ui, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 24px;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { font-family: var(--font-display); margin: 0; }

h1 {
  font-size: 36px; line-height: 1.1; font-weight: 700;
  letter-spacing: -1px; color: #fff; margin-bottom: var(--s-md);
}
h2 {
  font-size: 28px; line-height: 1.15; font-weight: 700;
  letter-spacing: -0.7px; color: var(--nav); margin-bottom: var(--s-sm);
}
h3 {
  font-size: 18px; line-height: 28px; font-weight: 600;
  letter-spacing: -0.45px; color: var(--text-strong); margin-bottom: var(--s-sm);
}
h4 { font-size: 16px; font-weight: 600; color: #fff; margin-bottom: var(--s-sm); }

p { margin: 0 0 var(--s-md); }
a { color: var(--primary); }

:focus-visible {
  outline: 3px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

.container {
  margin-inline: auto;
  max-width: var(--container);
  padding-inline: var(--s-lg);
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: #fff; color: var(--nav); padding: var(--s-sm) var(--s-md);
}
.skip-link:focus { left: var(--s-md); top: var(--s-sm); }

/* ---------- nav ---------------------------------------------------------- */
.nav {
  position: sticky; top: 0; z-index: 50; width: 100%;
  background: var(--nav);
}
.nav__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-md);
  margin-inline: auto; max-width: var(--container);
  padding: 12px var(--s-lg);
}
.nav__brand {
  display: inline-flex; align-items: center; gap: var(--s-sm);
  color: #fff; font-family: var(--font-display); font-size: 20px;
  letter-spacing: -0.5px; font-weight: 600; text-decoration: none;
}
.nav__links { display: flex; align-items: center; gap: var(--s-lg); }
.nav__link {
  color: rgba(255,255,255,.9); text-decoration: none;
  font-size: 14px; font-weight: 500;
}
.nav__link:hover { color: #fff; text-decoration: underline; }

.btn {
  display: inline-flex; align-items: center; gap: var(--s-sm);
  background: var(--primary); color: #fff; border: 0;
  border-radius: var(--radius); text-decoration: none; cursor: pointer;
  font-family: var(--font-body); font-size: 14px; font-weight: 500;
  padding: var(--s-sm) 20px;
  transition: background-color .15s ease;
}
.btn:hover { background: var(--primary-hover); }
.btn--lg {
  font-size: 16px; font-weight: 600; padding: 12px var(--s-xl);
  box-shadow: var(--shadow-lg);
}
.btn--ghost {
  background: transparent; color: var(--primary);
  border: 1px solid var(--border);
}
.btn--ghost:hover { background: #fff; }
.btn--danger { background: #B3261E; }
.btn--danger:hover { background: #8C1D18; }

/* ---------- hero --------------------------------------------------------- */
.hero {
  position: relative; display: flex; align-items: center; justify-content: center;
  overflow: hidden; min-height: 380px; padding-block: var(--s-3xl);
}
.hero__image {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  /* WebP is ~25% smaller than the JPEG. Browsers that do not understand
     image-set() ignore the whole declaration, so the plain url() below stays
     as the fallback and must come first. */
  background-image: url('/img/hero.jpg');
  background-image: image-set(url('/img/hero.webp') type('image/webp'),
                              url('/img/hero.jpg') type('image/jpeg'));
}
.hero__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to right,
    rgba(28,45,69,.85) 0%, rgba(46,77,122,.7) 50%, rgba(78,111,163,.5) 100%);
}
.hero__content {
  position: relative; z-index: 10; text-align: center;
  margin-inline: auto; max-width: var(--container); padding-inline: var(--s-lg);
}
.hero__sub {
  color: rgba(255,255,255,.92); font-size: 18px; line-height: 28px;
  max-width: 620px; margin: 0 auto var(--s-lg);
}

/* ---------- sections ----------------------------------------------------- */
.section { padding-block: var(--s-3xl); }
.section--tight { padding-block: var(--s-2xl); }
.section__lede { color: var(--muted); max-width: 680px; }

.pills { display: flex; flex-wrap: wrap; gap: var(--s-sm); margin: var(--s-lg) 0; }
.pill {
  display: inline-block; border-radius: var(--radius-pill);
  padding: 6px var(--s-md); font-size: 14px; font-weight: 500;
  text-decoration: none; background: var(--pill); color: var(--text-strong);
  transition: background-color .15s ease, color .15s ease;
}
.pill:hover { background: var(--primary); color: #fff; }
.pill[aria-current="page"] { background: var(--primary); color: #fff; }

.count { color: var(--muted); font-size: 14px; margin-bottom: var(--s-md); }

.grid {
  display: grid; gap: var(--s-lg);
  grid-template-columns: 1fr;
}
@media (min-width: 640px) { .grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .grid { grid-template-columns: repeat(3, 1fr); } }

.card {
  position: relative; display: block; background: var(--card);
  border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: var(--s-lg); box-shadow: var(--shadow-sm);
  text-decoration: none; color: inherit;
  transition: box-shadow .2s ease, transform .2s ease;
}
.card:hover { box-shadow: var(--shadow-md); }
.card:hover h3 { color: var(--primary); }
.card--featured { border-color: var(--primary); box-shadow: var(--shadow-md); }

.card__meta {
  display: flex; align-items: center; gap: 6px;
  color: var(--muted); font-size: 14px; margin-bottom: var(--s-xs);
}
.card__desc { color: var(--muted); font-size: 14px; line-height: 22px; margin: var(--s-sm) 0 0; }
.card__tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--s-sm); }
.tag {
  display: inline-block; border-radius: var(--radius-pill);
  padding: 2px 10px; font-size: 12px; font-weight: 500;
  background: var(--pill); color: var(--text-strong); text-decoration: none;
}

.badge {
  display: inline-block; border-radius: var(--radius-pill);
  padding: 2px 10px; font-size: 12px; font-weight: 600;
  background: var(--primary); color: #fff; margin-bottom: var(--s-sm);
}

/* ---------- detail page -------------------------------------------------- */
.crumbs { font-size: 14px; color: var(--muted); margin-bottom: var(--s-md); }
.crumbs a { color: var(--muted); }
.crumbs span { margin-inline: 6px; }

.panel {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-card); padding: var(--s-xl);
  box-shadow: var(--shadow-sm);
}
.detail__title { color: var(--nav); }
.detail__facts { list-style: none; margin: var(--s-lg) 0 0; padding: 0; }
.detail__facts li {
  display: flex; gap: var(--s-md); padding: 10px 0;
  border-top: 1px solid var(--border); font-size: 15px;
}
.detail__facts dt, .detail__facts .k {
  color: var(--muted); min-width: 120px; font-size: 14px;
}
.prose { max-width: 68ch; }
.prose h2 { margin-top: var(--s-xl); }

/* ---------- forms -------------------------------------------------------- */
/* Bounded sections inside the two-column form — Status, Categories, Delete.
   On a fieldset the border must be set explicitly: the UA default is a 2px
   groove that reads as a dark box and matches nothing else on the page. The
   legend is pulled back to the padding edge so it sits like a heading rather
   than straddling the border. */
.boxed {
  border: 1px solid var(--border); border-radius: var(--radius-card);
  background: var(--card); padding: var(--s-md);
  margin: 0 0 var(--s-md);
}
.boxed > legend { padding: 0; margin-bottom: var(--s-sm); }
.boxed > h3 { font-size: 15px; margin-bottom: var(--s-sm); }
.boxed > :last-child { margin-bottom: 0; }
.boxed__option { display: block; font-size: 14px; margin-bottom: 6px; }

.field { display: block; margin-bottom: var(--s-md); }
.field__label {
  display: block; font-size: 14px; font-weight: 500;
  color: var(--text); margin-bottom: 6px;
}
.field__hint { display: block; font-size: 13px; color: var(--muted); margin-top: 4px; }
.input, .select, .textarea {
  width: 100%; background: #fff; color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 10px 12px; font-family: var(--font-body); font-size: 15px;
}
.textarea { min-height: 110px; resize: vertical; }
.input:focus, .select:focus, .textarea:focus { border-color: var(--primary); }

.notice {
  border-radius: var(--radius); padding: 12px var(--s-md);
  font-size: 14px; margin-bottom: var(--s-lg);
  border: 1px solid var(--border); background: #fff;
}
.notice--ok { border-color: #2E7D51; color: #1B5E3A; background: #EEF7F1; }
.notice--warn { border-color: #A8741A; color: #7A5312; background: #FDF6E8; }
.notice--err { border-color: #B3261E; color: #8C1D18; background: #FDECEA; }

.price {
  font-family: var(--font-display); font-size: 44px; font-weight: 700;
  letter-spacing: -1px; color: var(--nav); line-height: 1;
}
.price small { display: block; font-family: var(--font-body); font-size: 14px;
  font-weight: 400; color: var(--muted); letter-spacing: 0; margin-top: 6px; }

.benefits { list-style: none; margin: var(--s-lg) 0; padding: 0; }
.benefits li {
  position: relative; padding-left: 26px; margin-bottom: 10px;
  font-size: 15px; color: var(--text);
}
.benefits li::before {
  content: ''; position: absolute; left: 0; top: 7px;
  width: 14px; height: 8px; border-left: 2px solid var(--primary);
  border-bottom: 2px solid var(--primary); transform: rotate(-45deg);
}

.split { display: grid; gap: var(--s-xl); }
@media (min-width: 900px) { .split { grid-template-columns: 1fr 1fr; align-items: start; } }

/* ---------- faq ---------------------------------------------------------- */
.faq { border-top: 1px solid var(--border); }
.faq details { border-bottom: 1px solid var(--border); padding: var(--s-md) 0; }
.faq summary {
  cursor: pointer; font-family: var(--font-display); font-weight: 600;
  font-size: 17px; color: var(--text-strong); letter-spacing: -0.3px;
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: ' +'; color: var(--primary); font-weight: 700; }
.faq details[open] summary::after { content: ' –'; }
.faq p { margin: var(--s-sm) 0 0; color: var(--muted); max-width: 68ch; }

/* ---------- footer ------------------------------------------------------- */
.footer { background: var(--nav); color: var(--footer-text); margin-top: var(--s-3xl); }
.footer__inner {
  margin-inline: auto; max-width: var(--container);
  padding: var(--s-2xl) var(--s-lg);
}
.footer__grid { display: grid; gap: var(--s-xl); }
@media (min-width: 768px) { .footer__grid { grid-template-columns: 1fr 1fr; } }
.footer__blurb { font-size: 14px; line-height: 22px; max-width: 480px; margin: 12px 0 0; }
.footer__right { }
@media (min-width: 768px) { .footer__right { text-align: right; } }
.footer__meta { font-size: 14px; margin-bottom: 4px; }
.footer a { color: var(--footer-text); }
.footer a:hover { color: #fff; }
.footer__nav { display: flex; flex-wrap: wrap; gap: var(--s-md); margin-top: var(--s-md); font-size: 14px; }
@media (min-width: 768px) { .footer__nav { justify-content: flex-end; } }
.footer__legal {
  margin-top: 40px; padding-top: var(--s-lg);
  border-top: 1px solid rgba(255,255,255,.15); font-size: 13px;
}

/* ---------- admin -------------------------------------------------------- */
.adm { background: #fff; min-height: 100vh; }
.adm__bar { background: var(--nav); color: #fff; }
.adm__bar .nav__inner { padding-block: 10px; }
.adm__tabs { display: flex; gap: var(--s-md); flex-wrap: wrap; }
.adm__tab { color: rgba(255,255,255,.85); font-size: 14px; text-decoration: none; }
.adm__tab[aria-current="page"] { color: #fff; font-weight: 600; text-decoration: underline; }
.adm__who { font-size: 13px; color: rgba(255,255,255,.75); }

.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th, .table td {
  text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.table th { color: var(--muted); font-weight: 500; font-size: 13px; }
.table tr:hover td { background: var(--bg); }
/* Dates and their headers must not break mid-value. The width is what the
   content needs and no more — the Categories column absorbs the difference,
   since chips wrap gracefully and an ISO date does not. */
.table .nowrap { white-space: nowrap; width: 1%; }
/* Row title as link: inherits the cell's colour so the table does not turn into
   a wall of blue, and declares itself on hover and keyboard focus. */
.table a.rowlink { color: inherit; text-decoration: none; }
.table a.rowlink:hover { color: var(--primary); text-decoration: underline; }
.row-actions { display: flex; gap: var(--s-sm); flex-wrap: wrap; }

.chip {
  display: inline-block; font-size: 12px; padding: 2px 8px;
  border-radius: var(--radius-pill); background: var(--bg);
  border: 1px solid var(--border); color: var(--muted);
}
.chip--on { background: var(--primary); border-color: var(--primary); color: #fff; }

.stack > * + * { margin-top: var(--s-md); }
.muted { color: var(--muted); }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; }
.right { text-align: right; }
.inline-form { display: inline; }

@media (min-width: 768px) {
  h1 { font-size: 48px; letter-spacing: -1.2px; }
  h2 { font-size: 36px; letter-spacing: -0.9px; line-height: 40px; }
}
@media (min-width: 1024px) {
  h1 { font-size: 60px; line-height: 60px; letter-spacing: -1.5px; }
}

/* ---------- status toggles (admin) ----------------------------------------
   Checkbox-backed so the control is a real form field: keyboard reachable,
   announced as a checkbox, and submitted without JavaScript. Green reads as
   on, red as off, matching the existing notice and danger colours.        */

.toggles { display: grid; gap: var(--s-lg); margin-top: var(--s-sm); }
.toggle-row { display: grid; gap: var(--s-sm); }

.toggle { display: inline-flex; align-items: center; gap: var(--s-md); cursor: pointer; }
.toggle__input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle__track {
  position: relative; flex: 0 0 auto;
  width: 52px; height: 30px; border-radius: var(--radius-pill);
  background: #B3261E; border: 1px solid rgba(0,0,0,.12);
  transition: background .15s ease;
}
.toggle__knob {
  position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: 50%;
  background: #fff; box-shadow: var(--shadow-sm);
  transition: transform .15s ease;
}
.toggle__input:checked + .toggle__track { background: #2E7D51; }
.toggle__input:checked + .toggle__track .toggle__knob { transform: translateX(22px); }
.toggle__input:focus-visible + .toggle__track {
  outline: 2px solid var(--primary); outline-offset: 2px;
}
.toggle__input:disabled + .toggle__track { opacity: .5; cursor: not-allowed; }
.toggle__text { font-weight: 600; color: var(--text-strong); }
.toggle__state { font-size: 13px; color: var(--muted); }

.toggle-expiry { display: grid; gap: 4px; max-width: 240px; padding-left: 68px; }
.toggle-expiry label { font-size: 13px; color: var(--muted); }
@media (max-width: 640px) { .toggle-expiry { padding-left: 0; } }

/* ---------- admin filter bar ---------------------------------------------- */
.filters {
  display: grid; gap: var(--s-md); align-items: end;
  grid-template-columns: 1fr;
}
@media (min-width: 720px)  { .filters { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1100px) { .filters { grid-template-columns: 2fr repeat(6, 1fr) auto; } }
.filters .field__label { margin-bottom: 4px; }
.filters .select, .filters .input { width: 100%; }


/* ---------- row action glyphs (admin) --------------------------------------
   Icon-only buttons. State is carried by BOTH shape and colour where the glyph
   allows it — star and bookmark switch outline to filled — because colour alone
   fails for anyone who cannot separate grey from amber. Every button also
   carries an aria-label naming the action and the current state, so 175 rows do
   not read as a wall of unnamed buttons.                                     */

.actions { display: flex; align-items: center; justify-content: flex-end; gap: 2px; }
.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0;
  background: none; border: 0; border-radius: var(--radius);
  color: var(--muted); cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
}
.iconbtn:hover { background: var(--bg); color: var(--text-strong); }
.iconbtn:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.iconbtn svg { width: 20px; height: 20px; display: block; }
.iconbtn--on-publish  { color: var(--primary); }
.iconbtn--on-list     { color: #2E7D51; }
.iconbtn--on-feature  { color: var(--featured); }
/* Edit and delete are always available — they have no off state, so they must
   not sit at the --muted grey that means "switched off" on the three toggles. */
.iconbtn--plain       { color: var(--text); }
.iconbtn--danger:hover { color: #B3261E; background: #FDECEA; }

/* ---------- confirm dialogs ------------------------------------------------
   Real <dialog>s rather than window.confirm(), so the prompt appears centred
   over the table instead of pinned to the top of the window as browser chrome.
   Escape closes them, focus is trapped, and the backdrop comes free. Deleting
   also needs a typed slug, which a window.confirm() could not have carried.  */

dialog.confirm {
  /* margin:auto centres in both axes against the modal's containing block;
     the top/bottom margins are what a UA sheet leaves at 0. */
  margin: auto;
  border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: var(--s-lg); max-width: 520px; width: calc(100% - 32px);
  color: var(--text); background: var(--card);
  box-shadow: var(--shadow-lg);
}
dialog.confirm::backdrop { background: rgba(28,44,69,.45); }
dialog.confirm h3 { margin-bottom: var(--s-sm); }
dialog.confirm p { margin: 0; }
dialog.confirm .row-actions { display: flex; gap: var(--s-sm); margin-top: var(--s-md); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}
