@import url('https://fonts.googleapis.com/css2?family=Heebo:wght@400;500;600;700;800&display=swap');

:root {
  --navy: #1f3b57;
  --navy-dark: #142838;
  --gold: #b08d3f;
  --gold-light: #e8dcc0;
  --cta: #2f6b63;
  --cta-dark: #234f49;
  --paper: #faf8f4;
  --ink: #232323;
  --ink-soft: #62666b;
  --border: #e4e1d8;
  --success: #2f6f4f;
  --danger: #a13d3d;
  --radius: 0;
  --shadow: 0 1px 3px rgba(31, 59, 87, 0.07), 0 1px 2px rgba(31, 59, 87, 0.05);
  --max-width: 980px;
  --font-body: 'Heebo', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-head: 'Heebo', system-ui, -apple-system, 'Segoe UI', sans-serif;
}

* { box-sizing: border-box; }
html { font-size: 15px; height: 100%; }
html, body { margin: 0; padding: 0; }
/* Belt-and-suspenders: on top of the specific min-width/width fixes further
   down, this guarantees no free-typed post content can ever force a
   horizontal scrollbar on the page itself, regardless of which nested
   element's sizing quirk is behind it - X-axis only, so it never clips a
   vertically-extending dropdown/suggestion list/tooltip. */
html, body { overflow-x: hidden; }
body {
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  min-height: 100%;
}
body[dir='rtl'] { direction: rtl; }

#layout { display: flex; flex-direction: column; min-height: 100vh; }
/* min-width:0 plus an explicit 100% width - see the long comment on
   .home-main below for why both are here: min-width:0 alone is the
   textbook fix for a flex item's cross-axis automatic minimum size, but
   live diagnostics on a real device showed it insufficient by itself, so
   this forces the width outright rather than just removing the lower bound. */
#layout main#app { flex: 1 0 auto; min-width: 0; width: 100%; max-width: 100%; overflow-x: hidden; }
#layout .site-footer { flex-shrink: 0; }

/* ---------- Banners (admin-managed ad/promo slots) ---------- */
/* #topBannerSlot/#sidebarBannerSlot start hidden (inline style) and only
   ever get display:'' (shown) from JS once there's at least one banner to
   put in them - see public/js/banners.js - so an empty slot never reserves
   visible space or shows a placeholder. Once shown, each slot is a flex
   column: height isn't fixed anywhere, it's just the sum of however many
   banners actually render at their own natural (content-driven) height, so
   one short wide banner, one tall poster-style one, or several stacked
   banners all lay out cleanly with no extra/clipped space either way. */
#topBannerSlot, #sidebarBannerSlot { display: flex; flex-direction: column; gap: 10px; }
#topBannerSlot { margin: 14px 0 0; }
.site-banner { display: block; }
.site-banner img { display: block; width: 100%; height: auto; border: 1px solid var(--border); }

h1, h2, h3, h4 { font-family: var(--font-head); color: var(--navy); margin: 0 0 .4em; font-weight: 800; letter-spacing: -.01em; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1.02rem; }
a { color: var(--navy); text-decoration: none; transition: color .15s ease; }
a:hover { color: var(--gold); }
img { max-width: 100%; display: block; }
button { font-family: inherit; cursor: pointer; }
p { margin: 0 0 .7em; }

.container { max-width: var(--max-width); margin: 0 auto; padding: 0 18px; }

/* ---------- Header ---------- */
/* Redesign: white header, navy limited to accents (text/links/icons/borders)
   instead of a solid navy panel - the previous dark-fill header/footer/sidebar
   was the specific thing flagged as too heavy. */
.site-header {
  background: #fff;
  color: var(--navy);
  position: sticky;
  top: 0;
  z-index: 40;
  border-bottom: 1px solid var(--border);
}
/* Wider than the site's normal content container (--max-width: 980px) -
   the header row has more to fit (logo, 7 nav links, search, 2 buttons)
   than a content column ever needs, and capping it at the content width is
   exactly what was squeezing the last nav link (Bookmarks) permanently out
   of view, with no visible scrollbar to show it was clipped rather than
   just missing. */
.site-header .container { display: flex; align-items: center; gap: 14px; height: 68px; max-width: 1320px; }
/* Scoped to .site-header specifically - .brand alone would also match the
   unrelated "Admin Portal" sidebar brand div in the admin portal, which
   doesn't use this file's grid/height rules and broke badly when it did. */
.site-header .brand { display: flex; align-items: center; height: 100%; color: var(--navy); font-family: var(--font-head); font-size: 1.08rem; font-weight: 800; letter-spacing: -.01em; }
/* width:auto (already the default, made explicit) keeps the logo's aspect
   ratio intact - it only distorts if something else clamps the width down
   independently of height, which is what the mobile fix below guards against. */
.site-header .brand img { height: 48px; width: auto; }
.main-nav { display: flex; align-items: center; gap: 2px; flex: 1 1 auto; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.main-nav a { color: var(--ink-soft); padding: 6px 9px; border-radius: var(--radius); font-size: .86rem; font-weight: 500; white-space: nowrap; }
.main-nav a:hover, .main-nav a.active { background: rgba(31,59,87,.08); color: var(--navy); }
.nav-subscribe {
  display: inline-flex; align-items: center; gap: 5px;
  /* Same color as the +Post button (var(--cta)) for a consistent pair of
     CTAs in the header. !important on background/color: .main-nav a.active
     (toggled by the router whenever the current path matches a nav link -
     true for this link while actually on /subscribe) is more specific than
     the plain .nav-subscribe class and would otherwise repaint it back to
     the generic muted nav-link look instead of staying this button's own
     color before, during hover, and after being clicked. */
  background: var(--cta) !important; border: 1px solid var(--cta); color: #fff !important; font-weight: 700;
  border-radius: 999px; margin-inline-start: 6px; flex-shrink: 0;
  box-shadow: 0 0 0 0 rgba(47,107,99,.45);
  animation: nav-subscribe-pulse 2.6s ease-in-out infinite;
}
.nav-subscribe-icon { font-size: .92em; transform: translateY(-1px); }
.nav-subscribe:hover, .nav-subscribe.active {
  background: var(--cta-dark) !important; border-color: var(--cta-dark); color: #fff !important;
  animation-play-state: paused; box-shadow: none;
}
.nav-subscribe:hover { transform: translateY(-1px); }
@keyframes nav-subscribe-pulse {
  0%, 60%, 100% { box-shadow: 0 0 0 0 rgba(47,107,99,.45); }
  30% { box-shadow: 0 0 0 5px rgba(47,107,99,0); }
}
@media (prefers-reduced-motion: reduce) { .nav-subscribe { animation: none; } }
.site-search { flex-shrink: 2; min-width: 0; }
.site-search input {
  width: 100%; min-width: 90px; max-width: 220px; border: 1px solid var(--border); background: #fff;
  color: var(--ink); border-radius: 0; padding: 6px 10px; font-size: .82rem;
}
.site-search input::placeholder { color: var(--ink-soft); }
.site-search input:focus { outline: none; border-color: var(--navy); }
.header-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
@media (max-width: 600px) { .site-search input { max-width: 120px; } }
.btn-post {
  background: var(--cta); color: #fff; font-weight: 700; padding: 7px 15px;
  border-radius: 0; border: none; font-size: .84rem;
}
.btn-post:hover { background: var(--cta-dark); color: #fff; }
.lang-toggle, .bookmarks-link {
  background: transparent; border: 1px solid var(--border); color: var(--navy); border-radius: 0;
  padding: 5px 11px; font-size: .78rem;
}
.hamburger { display: none; background: none; border: none; width: 26px; height: 20px; padding: 0; flex-direction: column; justify-content: space-between; }
.hamburger span { display: block; height: 2px; width: 100%; background: var(--navy); }

@media (max-width: 1160px) {
  .main-nav {
    display: flex; position: absolute; top: 68px; inset-inline: 0; background: #fff; border-bottom: 1px solid var(--border); box-shadow: var(--shadow); flex-direction: column; padding: 0 6px;
    max-height: 0; overflow: hidden; opacity: 0; pointer-events: none;
    transition: max-height .25s ease, opacity .2s ease, padding .25s ease;
  }
  .main-nav.open { max-height: 360px; opacity: 1; pointer-events: auto; padding: 6px; }
  .nav-subscribe { margin-inline-start: 0; align-self: center; }
  .hamburger { display: flex; }
  .hamburger span { transition: transform .2s ease, opacity .15s ease; }
  .hamburger.open span:nth-child(1) { transform: translateY(9px) rotate(45deg); }
  .hamburger.open span:nth-child(2) { opacity: 0; }
  .hamburger.open span:nth-child(3) { transform: translateY(-9px) rotate(-45deg); }
}

/* Wider-feeling header on mobile: less side padding gives the logo, search
   and post button more room, and a smaller logo height keeps its
   auto-computed width comfortably inside that room. flex-shrink:0 on .brand
   is what actually guarantees no distortion - without it, a still-too-narrow
   row would shrink the logo's box (and, since height stays fixed, squash it)
   before it would ever shrink the search input, which is the one element
   that's actually meant to give up space here. */
@media (max-width: 600px) {
  .container { padding: 0 10px; }
  .site-header .container { height: 60px; gap: 8px; }
  .site-header .brand { flex-shrink: 0; }
  .site-header .brand img { height: 32px; }
  .site-search input { min-width: 60px; }
  .lang-toggle { padding: 5px 8px; }
  .main-nav { top: 60px; }
}
@media (max-width: 380px) {
  .lang-toggle { display: none; }
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-block; padding: 8px 16px; border-radius: var(--radius); border: 1px solid var(--navy); background: var(--navy); color: #fff; font-weight: 600; font-size: .86rem;
  transition: background .15s ease, border-color .15s ease, box-shadow .15s ease, transform .08s ease;
}
.btn:hover { background: var(--navy-dark); color: #fff; }
.btn:active:not(:disabled) { transform: scale(.96); }
.btn-outline { background: transparent; color: var(--navy); }
.btn-outline:hover { background: var(--navy); color: #fff; }
.btn-gold { background: var(--cta); border-color: var(--cta); color: #fff; }
.btn-gold:hover { background: var(--cta-dark); border-color: var(--cta-dark); }
.btn-danger { background: var(--danger); border-color: var(--danger); }
.btn-sm { padding: 5px 11px; font-size: .78rem; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-post, .hamburger, .lang-toggle, .bookmarks-link, .bookmark-btn, .report-link, .category-tile, .tier-tile, .category-pills a, .pagination a {
  transition: background .15s ease, border-color .15s ease, color .15s ease, transform .08s ease;
}
.btn-post:active, .category-tile:active, .tier-tile:active { transform: scale(.97); }

/* ---------- Home page layout: main column + sidebar (zmanim/daf yomi/weather) ---------- */
/* Desktop only: two columns via grid. On mobile this wrapper is demoted to
   plain block flow (see the media query below) rather than a single-column
   grid - the browse/search pages' card grids render correctly on every
   device precisely because they sit in ordinary block containers, and the
   home page was the only page wrapping its content in a grid ancestor, so
   on mobile it now uses the exact same structure as the pages that work. */
.home-grid { display: grid; grid-template-columns: 1fr 300px; gap: 24px; align-items: start; }
.home-main { min-width: 0; }
.home-sidebar { display: flex; flex-direction: column; gap: 14px; padding-top: 30px; }
@media (max-width: 860px) {
  .home-grid { display: block; }
  .home-main { width: auto; }
  .home-sidebar { padding-top: 0; margin-top: 22px; }
}

/* ---------- Combo widget (sidebar: date + daf yomi + zmanim, one compact card) ---------- */
.combo-widget { background: #fff; border: 1px solid var(--border); padding: 10px 14px; box-shadow: var(--shadow); font-size: .8rem; }
.combo-widget-top { display: flex; flex-direction: column; gap: 8px; padding-bottom: 8px; margin-bottom: 8px; border-bottom: 1px solid var(--border); }
.combo-label { display: block; font-weight: 700; color: var(--navy); font-size: .86rem; }
.combo-sub { display: block; color: var(--ink-soft); font-size: .72rem; }
.combo-zman-row { display: flex; flex-direction: column; gap: 5px; color: var(--ink-soft); font-size: .74rem; }
.combo-zman-row span { display: flex; justify-content: space-between; gap: 8px; }
.combo-zman-row b { color: var(--ink); font-weight: 600; }
.zman-disclaimer { margin: 8px 0 0; padding-top: 6px; border-top: 1px solid var(--border); font-size: .68rem; color: var(--ink-soft); text-align: center; direction: rtl; }

.weather-widget .weather-day { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding: 5px 0; border-bottom: 1px solid var(--border); font-size: .8rem; }
.weather-widget .weather-day:last-of-type { border-bottom: none; }
.weather-day-label { font-weight: 700; color: var(--navy); flex-shrink: 0; }
.weather-desc { color: var(--ink-soft); flex: 1; text-align: center; }
.weather-temps { flex-shrink: 0; white-space: nowrap; }
.weather-attribution { font-size: .64rem; color: var(--ink-soft); margin: 8px 0 0; text-align: end; }
.weather-attribution a { color: var(--ink-soft); text-decoration: underline; }

/* ---------- Carousels ---------- */
.section-heading { display: flex; align-items: baseline; justify-content: space-between; margin: 24px 0 10px; }
.section-heading a { font-size: .82rem; font-weight: 600; }
/* Wraps instead of horizontally scrolling - with only a handful of recent
   items, a fixed-width scroll row left a large empty gap next to the home
   sidebar instead of using the space. */
.carousel { display: flex; flex-wrap: wrap; gap: 10px; }
.carousel .card { flex: 1 1 210px; min-width: 0; }
/* At mobile widths this switches to CSS Grid with minmax(0, 1fr) columns
   instead of flex's percentage flex-basis (calc(50% - 4px)) - percentage
   flex-basis has real, confirmed-on-device ambiguity resolving against a
   flex container whose own available width comes from a still-being-
   resolved ancestor chain (grid > flex column > clipped box), where it can
   end up sized against the content's own max-content width instead of the
   actual available space. minmax(0, 1fr) has no such ambiguity - it's an
   explicit, unconditional "never exceed your fair share" instruction. This
   matches the technique .results-grid below already uses successfully. */
@media (max-width: 600px) {
  .carousel { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
  .carousel .card { min-width: 0; }
}

/* ---------- Cards ---------- */
/* Square corners by design - no image, the card is a compact text summary;
   full contact info only ever appears after clicking through to the post. */
.card {
  background: #fff; border: 1px solid var(--border); border-radius: 0; overflow: hidden;
  box-shadow: var(--shadow); display: flex; flex-direction: column;
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.card:hover { transform: translateY(-3px); border-color: var(--gold); box-shadow: 0 8px 20px rgba(31, 59, 87, .14); }
.card .body { padding: 12px 13px; flex: 1; display: flex; flex-direction: column; gap: 4px; }
.card .cat { font-size: .66rem; text-transform: uppercase; letter-spacing: .04em; color: var(--gold); font-weight: 700; }
.card .title { font-weight: 700; color: var(--navy); font-size: .94rem; line-height: 1.3; }
.card .card-desc {
  font-size: .8rem; color: var(--ink); margin: 0; line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.card .meta { font-size: .76rem; color: var(--ink-soft); }
.card .price { font-weight: 700; color: var(--success); font-size: .88rem; }
.card.featured { border-color: var(--gold); box-shadow: 0 0 0 2px var(--gold-light); }

/* Smaller text + tighter padding/gap on the 2-up mobile grid gives each card
   more usable width relative to its own chrome, instead of the type feeling
   squeezed into the same spacing built for wide desktop columns. */
@media (max-width: 600px) {
  .results-grid { gap: 7px; }
  .card .body { padding: 9px 10px; gap: 3px; }
  .card .cat { font-size: .6rem; }
  .card .title { font-size: .82rem; line-height: 1.25; }
  .card .card-desc { font-size: .72rem; -webkit-line-clamp: 2; }
  .card .meta, .card .price { font-size: .7rem; }
}
.badge-featured { color: var(--gold); font-size: .9rem; }

/* ---------- List/grid pages ---------- */
.page-header { padding: 20px 0 6px; }
.category-pills { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 16px; }
.category-pills a { padding: 5px 12px; border: 1px solid var(--border); border-radius: 0; font-size: .78rem; background: #fff; }
.category-pills a.active { background: var(--navy); color: #fff; border-color: var(--navy); }
.category-pills a .count { color: var(--ink-soft); margin-inline-start: 3px; }
.category-pills a.active .count { color: rgba(255,255,255,.7); }

.filters-bar { background: #fff; border: 1px solid var(--border); border-radius: var(--radius); padding: 11px 13px; margin-bottom: 16px; display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; }
.field { display: flex; flex-direction: column; gap: 3px; font-size: .76rem; color: var(--ink-soft); }
.field input, .field select, .field textarea {
  padding: 6px 9px; border: 1px solid var(--border); border-radius: 0; font-family: inherit; font-size: .85rem; background: #fff;
}
.field textarea { resize: vertical; }

.results-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
/* Below ~600px, minmax(200px,1fr) collapses to a single column - cards read
   fine at half that width (small fonts, no image), so force 2 up instead. */
@media (max-width: 600px) { .results-grid { grid-template-columns: repeat(2, 1fr); gap: 8px; } }
.empty-state { text-align: center; padding: 44px 16px; color: var(--ink-soft); font-size: .9rem; }

.pagination { display: flex; justify-content: center; gap: 5px; margin: 22px 0; flex-wrap: wrap; }
.pagination a, .pagination span { padding: 6px 11px; border: 1px solid var(--border); border-radius: 0; background: #fff; font-size: .82rem; }
.pagination a.active { background: var(--navy); color: #fff; border-color: var(--navy); }

/* ---------- Detail page ---------- */
.detail-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 22px; margin: 18px 0 44px; align-items: start; }
@media (max-width: 800px) { .detail-grid { grid-template-columns: 1fr; } }
.detail-anim { animation: detail-fade-in .35s ease; }
@keyframes detail-fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.detail-main { background: #fff; border: 1px solid var(--border); border-radius: var(--radius); padding: 18px; box-shadow: var(--shadow); }
.detail-topline { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.tag-lg { font-size: .74rem; padding: 4px 10px; }
.detail-posted { font-size: .78rem; color: var(--ink-soft); margin-inline-start: auto; }
.detail-title { font-size: 1.85rem; border-bottom: 3px solid var(--cta); display: inline-block; padding-bottom: 6px; margin-bottom: 16px; }
.detail-desc { font-size: 1rem; white-space: pre-wrap; line-height: 1.65; }
.detail-gallery { margin: 14px 0; }
.detail-gallery-main { border: 1px solid var(--border); background: #fff; }
.detail-gallery-main img { display: block; width: 100%; max-height: 460px; object-fit: cover; transition: opacity .15s ease; }
.detail-gallery-main img.fading { opacity: 0; }
.detail-gallery-thumbs { display: flex; gap: 6px; margin-top: 6px; overflow-x: auto; }
.detail-gallery-thumbs img {
  width: 72px; height: 72px; object-fit: cover; border: 2px solid transparent; opacity: .7; cursor: pointer; flex-shrink: 0;
  transition: opacity .15s ease, border-color .15s ease, transform .12s ease;
}
.detail-gallery-thumbs img.active, .detail-gallery-thumbs img:hover { opacity: 1; border-color: var(--cta); transform: scale(1.04); }
.share-row { display: flex; align-items: center; gap: 12px; margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); flex-wrap: wrap; }
.share-row a, .share-row button {
  font-size: .8rem; font-weight: 600; color: var(--cta); background: none; border: none; padding: 0; cursor: pointer; font-family: inherit;
}
.share-row a:hover, .share-row button:hover { text-decoration: underline; }
.contact-card { background: #fff; border: 1px solid var(--border); border-top: 3px solid var(--cta); border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow); position: sticky; top: 66px; }
.contact-card .btn { width: 100%; margin-bottom: 6px; text-align: center; }
.detail-meta-list { list-style: none; margin: 14px 0; padding: 0; font-size: .85rem; background: #fff; border: 1px solid var(--border); }
.detail-meta-list li { padding: 8px 12px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; }
.detail-meta-list li:last-child { border-bottom: none; }
.detail-meta-list li span:first-child { color: var(--ink-soft); font-weight: 600; }
.detail-meta-list li.stacked { flex-direction: column; align-items: flex-start; gap: 4px; }

/* ---------- Forms / wizard ---------- */
.wizard-steps { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.wizard-steps-row { display: flex; gap: 6px; flex-wrap: wrap; }
.wizard-steps span {
  padding: 5px 10px; border-radius: 0; background: #fff; border: 1px solid var(--border); font-size: .76rem; color: var(--ink-soft);
  transition: background .25s ease, color .25s ease, border-color .25s ease, transform .2s ease;
}
.wizard-steps span.active { background: var(--navy); color: #fff; border-color: var(--navy); transform: scale(1.05); }
.wizard-steps span.done { border-color: var(--cta); color: var(--cta); }
/* Fills smoothly as the poster advances through the wizard - width is set
   inline per-step (see postWizard.js) so the transition animates the change
   instead of jumping straight to the new value. */
.wizard-progress-track { height: 4px; background: var(--border); position: relative; overflow: hidden; }
.wizard-progress-fill { height: 100%; background: var(--cta); width: 0%; transition: width .35s cubic-bezier(.22,.61,.36,1); }
.form-card { background: #fff; border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; box-shadow: var(--shadow); max-width: 680px; animation: step-enter .3s cubic-bezier(.22,.61,.36,1) both; }
@keyframes step-enter { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.form-row { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.form-row label { font-weight: 600; font-size: .84rem; }
.form-row .hint { font-size: .74rem; color: var(--ink-soft); font-weight: 400; }
.char-counter { font-size: .72rem; color: var(--ink-soft); text-align: end; }
.form-row input, .form-row select, .form-row textarea {
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 0; font-family: inherit; font-size: .88rem;
}
.form-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 600px) { .form-cols { grid-template-columns: 1fr; } }
.places-suggestions {
  list-style: none; margin: 0; padding: 0; position: absolute; left: 0; right: 0; top: 100%; z-index: 20;
  background: #fff; border: 1px solid var(--border); border-top: none; max-height: 220px; overflow-y: auto;
  box-shadow: var(--shadow);
}
.places-suggestions li { padding: 8px 10px; font-size: .85rem; cursor: pointer; }
.places-suggestions li:hover { background: var(--paper); }

/* Stripe's Embedded Checkout mounts an auto-resizing iframe into this div -
   Stripe's own guidance is that the mount target must be a flex container
   or the iframe can fail to size itself correctly. */
#checkoutContainer, #boostCheckoutContainer { display: flex; flex-direction: column; opacity: 0; transition: opacity .35s ease; }
#checkoutContainer.show, #boostCheckoutContainer.show { opacity: 1; }
.category-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
@media (max-width: 700px) { .category-grid { grid-template-columns: repeat(2, 1fr); } }
.category-tile { border: 2px solid var(--border); border-radius: var(--radius); padding: 12px 8px; text-align: center; background: #fff; font-size: .82rem; font-weight: 600; }
.category-tile.selected { border-color: var(--gold); background: var(--gold-light); }
.tier-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 8px; }
.tier-tile { border: 2px solid var(--border); border-radius: var(--radius); padding: 11px; text-align: center; background: #fff; }
.tier-tile.selected { border-color: var(--navy); background: #eef3f7; }
.tier-tile .price { font-family: var(--font-head); font-size: 1.05rem; color: var(--navy); font-weight: 700; }
.addon-row { display: flex; align-items: center; gap: 8px; padding: 8px; border: 1px solid var(--border); border-radius: 0; margin-bottom: 6px; font-size: .86rem; }
.error-list { background: #fdecec; border: 1px solid var(--danger); color: var(--danger); padding: 8px 12px; border-radius: 0; margin-bottom: 12px; font-size: .84rem; }
.error-list ul { margin: 4px 0 0; padding-inline-start: 18px; }
.field-limit-warning { align-items: center; justify-content: space-between; gap: 8px; margin: 4px 0 0; }
.field-limit-warning .extend-limit-btn { flex-shrink: 0; white-space: nowrap; }

/* ---------- Footer ---------- */
.site-footer { background: #fff; border-top: 1px solid var(--border); color: var(--ink-soft); margin-top: 44px; padding: 24px 0; font-size: .8rem; }
.site-footer a { color: var(--navy); }
.footer-row { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px; }
.footer-links { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 8px; }
.footer-logo { height: 40px; }
@media (max-width: 600px) { .footer-row { flex-direction: column-reverse; align-items: flex-start; } }

/* ---------- Misc ---------- */
.tag { display: inline-block; padding: 2px 7px; border-radius: 0; background: var(--gold-light); color: var(--navy-dark); font-size: .7rem; font-weight: 700; }
.spinner { text-align: center; padding: 30px; color: var(--ink-soft); font-size: .88rem; }
.toast {
  position: fixed; bottom: 16px; inset-inline: 0; margin: 0 auto; max-width: 340px; background: var(--navy); color: #fff;
  padding: 10px 16px; border-radius: var(--radius); text-align: center; box-shadow: var(--shadow); z-index: 100; font-size: .86rem;
  animation: toast-in .25s cubic-bezier(.22,.61,.36,1) both;
}
.toast.toast-out { animation: toast-out .22s ease both; }
@keyframes toast-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes toast-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(8px); } }
.report-link, .bookmark-btn { background: none; border: 1px solid var(--border); border-radius: 0; padding: 5px 9px; font-size: .76rem; color: var(--ink-soft); }
.bookmark-btn.active { color: var(--gold); border-color: var(--gold); }
.bookmark-btn.pop { animation: bookmark-pop .35s ease; }
@keyframes bookmark-pop { 0% { transform: scale(1); } 40% { transform: scale(1.12); } 100% { transform: scale(1); } }

/* ---------- Editorials ---------- */
/* A distinct nav badge is the whole point here - it's what makes a brand new
   section worth clicking instead of blending into the rest of the nav bar. */
.badge-new-pill {
  display: inline-block; background: var(--cta); color: #fff; font-size: .62rem; font-weight: 800;
  padding: 1px 5px; border-radius: 0; letter-spacing: .03em; margin-inline-start: 2px; vertical-align: 2px;
}
.nav-editorials { display: inline-flex; align-items: center; }

.editorial-hero-band {
  background: linear-gradient(135deg, var(--navy), var(--navy-dark));
  color: #fff; padding: 32px 0; margin-bottom: 20px;
}
.editorial-hero-band h1 { color: #fff; margin-bottom: 4px; }
.editorial-tagline { color: rgba(255,255,255,.8); margin-bottom: 16px; font-size: .94rem; }
.editorial-hero-band .btn-gold { border-color: var(--gold); }

.editorial-featured-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; margin-bottom: 30px; }
.editorial-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; margin-bottom: 10px; }
@media (max-width: 600px) { .editorial-grid, .editorial-featured-strip { grid-template-columns: repeat(2, 1fr); gap: 8px; } }

.editorial-card {
  display: flex; flex-direction: column; background: #fff; border: 1px solid var(--border);
  box-shadow: var(--shadow); overflow: hidden; transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.editorial-card:hover { transform: translateY(-3px); border-color: var(--gold); box-shadow: 0 8px 20px rgba(31, 59, 87, .14); }
.editorial-card-img { height: 140px; background-color: var(--gold-light); background-size: cover; background-position: center; }
.editorial-card-lg .editorial-card-img { height: 220px; }
.editorial-card-body { padding: 13px 14px; flex: 1; display: flex; flex-direction: column; gap: 5px; }
.editorial-card-badges { display: flex; gap: 6px; }
.tag-featured { background: var(--gold); color: #fff; }
.tag-new { background: var(--cta); color: #fff; }
.editorial-card-title { margin: 0; font-family: var(--font-head); font-size: 1.02rem; color: var(--navy); font-weight: 800; line-height: 1.3; }
.editorial-card-lg .editorial-card-title { font-size: 1.3rem; }
.editorial-card-excerpt { margin: 0; font-size: .84rem; color: var(--ink); line-height: 1.5; flex: 1; }
.editorial-card-byline { font-size: .74rem; color: var(--ink-soft); }

/* No cover photo: the "image" area becomes a text cover - title + excerpt
   sit directly on the accent gradient instead of an empty decorative box,
   so a photo-less editorial still looks intentional rather than broken. */
.editorial-card-img-placeholder {
  height: auto; min-height: 140px; background-image: linear-gradient(135deg, var(--gold-light), var(--paper));
  display: flex; flex-direction: column; gap: 6px; justify-content: center; padding: 16px;
}
.editorial-card-lg .editorial-card-img-placeholder { min-height: 220px; padding: 22px; }
.editorial-card-img-placeholder .editorial-card-title { font-size: 1.14rem; }
.editorial-card-lg .editorial-card-img-placeholder .editorial-card-title { font-size: 1.5rem; }
.editorial-card-img-placeholder .editorial-card-excerpt { -webkit-line-clamp: 3; display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; }
.editorial-card-body-slim { padding: 10px 14px; flex: 0; }

@media (max-width: 600px) {
  .editorial-card-img { height: 90px; }
  .editorial-card-lg .editorial-card-img { height: 130px; }
  .editorial-card-img-placeholder { min-height: 90px; padding: 10px; }
  .editorial-card-lg .editorial-card-img-placeholder { min-height: 130px; padding: 14px; }
  .editorial-card-body { padding: 9px 10px; gap: 3px; }
  .editorial-card-body-slim { padding: 6px 10px; }
  .editorial-card-title { font-size: .84rem; }
  .editorial-card-img-placeholder .editorial-card-title { font-size: .9rem; }
  .editorial-card-lg .editorial-card-title { font-size: 1rem; }
  .editorial-card-lg .editorial-card-img-placeholder .editorial-card-title { font-size: 1.1rem; }
  .editorial-card-excerpt { font-size: .72rem; }
  .editorial-card-byline { font-size: .66rem; }
}

.editorial-detail { background: #fff; border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 20px; max-width: 760px; margin: 0 auto; }
.editorial-topline { display: flex; gap: 8px; margin-bottom: 10px; }
.editorial-detail-title { font-size: 1.9rem; margin-bottom: 6px; }
.editorial-detail-byline { font-size: .86rem; color: var(--ink-soft); margin-bottom: 16px; }
.editorial-body { font-size: 1.02rem; line-height: 1.75; }
.editorial-body p { margin: 0 0 1em; }
.editorial-video-embed { position: relative; width: 100%; padding-top: 56.25%; margin: 16px 0; background: #000; }
.editorial-video-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.editorial-comment { padding: 12px 0; border-bottom: 1px solid var(--border); }
.editorial-comment-head { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 4px; font-size: .86rem; }
.editorial-comment p { margin: 0; font-size: .92rem; line-height: 1.5; }
.editorial-comment-form { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border); }

.editorial-instructions {
  background: var(--gold-light); border-inline-start: 3px solid var(--gold); padding: 12px 16px; margin: 12px 0 20px; font-size: .9rem; line-height: 1.6;
}
.editorial-instructions p:last-child { margin-bottom: 0; }

.rich-toolbar { display: flex; gap: 6px; margin-bottom: 6px; }
.rich-editor {
  border: 1px solid var(--border); background: #fff; padding: 10px 12px; min-height: 220px;
  font-family: inherit; font-size: .95rem; line-height: 1.6;
}
.rich-editor:focus { outline: none; border-color: var(--navy); }
.rich-editor p { margin: 0 0 1em; }

.editorial-engagement-row { display: flex; align-items: center; gap: 14px; margin-top: 18px; flex-wrap: wrap; }
.editorial-like-btn {
  display: inline-flex; align-items: center; gap: 6px; font-size: .82rem; font-weight: 700;
  color: var(--navy); background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  padding: 7px 16px; cursor: pointer; font-family: inherit; transition: border-color .15s, color .15s;
}
.editorial-like-btn:hover:not(:disabled) { border-color: var(--gold); color: var(--gold); }
.editorial-like-btn.liked { color: #fff; background: var(--gold); border-color: var(--gold); cursor: default; }
.editorial-like-btn:disabled { cursor: default; }
.editorial-engagement-row .share-row { margin: 0; padding: 0; border: none; }

.home-editorials-teaser { margin-top: 14px; }
.home-editorial-item { display: flex; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border); text-decoration: none; color: inherit; }
.home-editorial-item:last-of-type { border-bottom: none; }
.home-editorial-thumb { width: 56px; height: 56px; flex-shrink: 0; background-size: cover; background-position: center; border-radius: 4px; background-color: var(--gold-light); }
.home-editorial-thumb-placeholder { background: linear-gradient(135deg, var(--navy), var(--gold)); }
.home-editorial-text { min-width: 0; }
.home-editorial-title { font-size: .82rem; font-weight: 700; color: var(--ink); line-height: 1.3; margin-bottom: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home-editorial-excerpt { font-size: .72rem; color: var(--ink-soft); line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.home-editorial-viewall { display: block; margin-top: 8px; font-size: .78rem; font-weight: 700; color: var(--cta); text-decoration: none; }
.home-editorial-viewall:hover { text-decoration: underline; }

/* ---------- Motion: page transitions, loading feedback, success moments ---------- */
/* A thin progress bar at the very top of the viewport during client-side
   navigation - gives instant feedback that a click registered, instead of
   the page just sitting still until the new content is ready. */
#route-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 0%; background: var(--gold);
  z-index: 200; transition: width .25s ease, opacity .3s ease .1s; opacity: 1;
}
#route-progress.done { opacity: 0; transition: width .2s ease, opacity .3s ease; }

/* The new page's content rises and fades in once it's ready - applied to
   #app itself after each route resolves. */
@keyframes app-enter { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
#app.app-enter { animation: app-enter .3s cubic-bezier(.22,.61,.36,1) both; }

/* Cards/editorial cards pop in with a slight stagger instead of all
   appearing at once - capped at the first 8 so long result pages don't
   feel sluggish waiting for the stagger to finish. */
@keyframes card-pop-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.card, .editorial-card { animation: card-pop-in .35s ease backwards; }
.card:nth-child(1), .editorial-card:nth-child(1) { animation-delay: 0s; }
.card:nth-child(2), .editorial-card:nth-child(2) { animation-delay: .04s; }
.card:nth-child(3), .editorial-card:nth-child(3) { animation-delay: .08s; }
.card:nth-child(4), .editorial-card:nth-child(4) { animation-delay: .12s; }
.card:nth-child(5), .editorial-card:nth-child(5) { animation-delay: .16s; }
.card:nth-child(6), .editorial-card:nth-child(6) { animation-delay: .2s; }
.card:nth-child(7), .editorial-card:nth-child(7) { animation-delay: .24s; }
.card:nth-child(8), .editorial-card:nth-child(8) { animation-delay: .28s; }

/* Shimmering placeholder cards shown while a page's data is still loading,
   instead of a blank gap or plain "Loading…" text. */
.skeleton-card { pointer-events: none; }
.skeleton-line {
  display: block; height: 10px; margin-bottom: 9px; background: linear-gradient(90deg, var(--border) 25%, #f4f2eb 37%, var(--border) 63%);
  background-size: 400% 100%; animation: skeleton-shimmer 1.4s ease infinite;
}
.skeleton-line:last-child { margin-bottom: 0; }
@keyframes skeleton-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
.sk-w35 { width: 35%; } .sk-w50 { width: 50%; } .sk-w70 { width: 70%; } .sk-w90 { width: 90%; }

/* The classic "drawn" checkmark for payment/posting success moments -
   restrained (one color, no confetti) so it reads as polish, not a gimmick. */
.success-pop { text-align: center; animation: success-pop-in .4s cubic-bezier(.22,.61,.36,1) both; }
@keyframes success-pop-in { from { opacity: 0; transform: scale(.92) translateY(6px); } to { opacity: 1; transform: none; } }
.success-check { width: 68px; height: 68px; margin: 0 auto 14px; }
.success-check svg { width: 100%; height: 100%; overflow: visible; }
.success-check-circle {
  fill: none; stroke: var(--cta); stroke-width: 2.5; stroke-dasharray: 152; stroke-dashoffset: 152;
  animation: success-draw-circle .5s ease forwards;
}
.success-check-mark {
  fill: none; stroke: var(--cta); stroke-width: 3.5; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 36; stroke-dashoffset: 36; animation: success-draw-check .3s ease .45s forwards;
}
@keyframes success-draw-circle { to { stroke-dashoffset: 0; } }
@keyframes success-draw-check { to { stroke-dashoffset: 0; } }

/* A quick highlight flash on the line a just-applied promo code adds to the
   pricing summary, so the discount registers as an event, not a silent
   number change. */
@keyframes promo-pop { 0% { background: var(--gold-light); } 100% { background: transparent; } }
.promo-line-new { animation: promo-pop .9s ease; }
