/* ==========================================================================
   CoxRoom — design tokens + the few effects that aren't practical in Tailwind.
   Everything else is done with Tailwind utility classes in the templates.
   ========================================================================== */

:root {
  /* Palette (RGB triplets so Tailwind can apply opacity modifiers).
     Saturated enough to feel like a travel brand, muted enough to stay
     readable: every accent below has AA contrast as text on white. */
  --brand-blue: 11 114 231;       /* #0B72E7 — primary */
  --brand-sky: 56 152 255;        /* #3898FF — lighter end of gradients */
  --brand-blue-soft: 232 243 255; /* #E8F3FF */
  --brand-navy: 16 42 67;         /* #102A43 */
  --brand-ink: 38 54 74;          /* #26364A */
  --brand-muted: 100 116 139;     /* #64748B — secondary text */
  --brand-tint: 240 247 255;      /* #F0F7FF — section wash */
  --brand-sand: 255 248 237;      /* #FFF8ED — warm wash */
  --brand-mint: 238 250 247;      /* #EEFAF7 — cool wash */
  --brand-orange: 234 88 12;      /* #EA580C */
  --brand-amber: 217 119 6;       /* #D97706 */
  --brand-coral: 244 63 94;       /* #F43F5E */
  --brand-green: 5 150 105;       /* #059669 */
  --brand-teal: 13 148 136;       /* #0D9488 */
  --brand-violet: 124 58 237;     /* #7C3AED */
  --brand-pink: 219 39 119;       /* #DB2777 */
  --brand-whatsapp: 13 127 69;    /* #0D7F45 — WhatsApp green, AA on white */
  --brand-line: 226 235 245;      /* #E2EBF5 */

  /* Accent tones used by the section eyebrows and category tiles. Each is a
     paired surface/ink so the pill and the icon chip stay consistent. */
  --tone-blue-surface: 232 243 255;
  --tone-blue-ink: 11 114 231;
  --tone-amber-surface: 255 244 224;
  --tone-amber-ink: 180 83 9;
  --tone-teal-surface: 230 250 246;
  --tone-teal-ink: 13 148 136;
  --tone-pink-surface: 255 236 245;
  --tone-pink-ink: 190 24 93;

  /* Footer palette (dark surfaces). */
  --brand-navy-deep: 7 29 50;     /* #071D32 — footer base */
  --brand-navy-mid: 13 41 66;     /* #0D2942 — footer bottom bar */
  --brand-mist: 170 184 199;      /* #AAB8C7 — muted text on dark */
  --brand-dim: 127 145 163;       /* #7F91A3 — fine print on dark */
  --brand-accent: 63 160 255;     /* #3FA0FF — accent blue on dark */

  /* Typography — change the family in one place. Inter has no Bengali glyphs,
     so the Bangla pages fall through to Noto Sans Bengali, which is loaded in
     partials/site_head.html. */
  --font-sans: 'Inter', 'Noto Sans Bengali', ui-sans-serif, system-ui, -apple-system,
    'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

  --header-height: 72px;
  --radius-pill: 12px;
}

@media (min-width: 1024px) {
  :root {
    --header-height: 74px;
  }
}

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

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

/* --------------------------------------------------------------- a11y ---- */
.skip-link {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 100;
  padding: 0.625rem 1rem;
  border-radius: 0.75rem;
  background: rgb(var(--brand-navy));
  color: #fff;
  font-size: 0.8125rem;
  font-weight: 600;
  transform: translateY(-200%);
  transition: transform 0.15s ease;
}

.skip-link:focus-visible {
  transform: translateY(0);
  outline: 2px solid rgb(var(--brand-blue));
  outline-offset: 2px;
}

:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid rgb(var(--brand-blue));
  outline-offset: 2px;
  border-radius: 0.5rem;
}

/* ------------------------------------------------------- header / nav ---- */
.nav-link {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 14px;
  border-radius: var(--radius-pill);
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1;
  color: rgb(var(--brand-ink));
  transition: color 150ms ease, background-color 150ms ease;
}

.nav-link:hover,
.nav-link:focus-visible {
  color: rgb(var(--brand-blue));
  background-color: rgb(var(--brand-blue-soft));
}

.nav-link--active {
  color: rgb(var(--brand-blue));
  background-color: rgb(var(--brand-blue-soft));
}

.mobile-link {
  display: flex;
  align-items: center;
  height: 44px;
  padding: 0 12px;
  border-radius: var(--radius-pill);
  font-size: 15px;
  font-weight: 600;
  color: rgb(var(--brand-ink));
  transition: color 150ms ease, background-color 150ms ease;
}

.mobile-link:hover,
.mobile-link:focus-visible {
  color: rgb(var(--brand-blue));
  background-color: rgb(var(--brand-blue-soft));
}

.mobile-link--active {
  color: rgb(var(--brand-blue));
  background-color: rgb(var(--brand-blue-soft));
}

/* Collapsible mobile menu: a light height + fade, no heavy animation. */
.mobile-menu {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition:
    max-height 260ms ease,
    opacity 180ms ease,
    transform 220ms ease,
    visibility 0s linear 260ms;
}

.mobile-menu[data-open='true'] {
  max-height: min(72vh, 560px);
  overflow-y: auto;
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition:
    max-height 260ms ease,
    opacity 200ms ease,
    transform 220ms ease,
    visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
  .mobile-menu,
  .mobile-menu[data-open='true'] {
    transition: none;
  }
}

/* --------------------------------------------------------- back to top ---- */
/* Floating, bottom-right, above whatever the page ends with. The script shows it
   once the footer is in view — the bottom area of a long listing or article — and
   hides it again on the way up. The hiding is scoped to `.has-js` (set in the
   head) so a visitor without JavaScript gets a button that is simply always
   there: a `#` jump still works, and a control that can never appear is worse
   than one that is early. */
.to-top {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 40;
  display: grid;
  place-items: center;
  height: 2.75rem;
  width: 2.75rem;
  border-radius: 9999px;
  border: 1px solid rgb(var(--brand-line));
  background-color: #fff;
  color: rgb(var(--brand-blue));
  box-shadow:
    0 12px 28px -14px rgb(16 42 67 / 45%),
    0 2px 6px rgb(16 42 67 / 10%);
  transition:
    background-color 200ms ease,
    color 200ms ease;
}

.to-top:hover,
.to-top:focus-visible {
  background-color: rgb(var(--brand-blue));
  color: #fff;
}

@media (min-width: 1024px) {
  .to-top {
    right: 2rem;
    bottom: 2rem;
  }
}

.has-js .to-top {
  opacity: 0;
  transform: translateY(0.75rem);
  pointer-events: none;
  transition:
    opacity 220ms ease,
    transform 220ms ease,
    background-color 200ms ease,
    color 200ms ease;
}

.has-js .to-top.is-visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .has-js .to-top,
  .has-js .to-top.is-visible {
    transition: none;
  }
}

@media print {
  .to-top {
    display: none;
  }
}

/* --------------------------------------------------------------- hero ---- */
/* A photographic hero: a centred flex box with a minimum height, so the copy
   sits in the optical middle of the photograph at every size. */
.hero {
  min-height: 460px;
}

@media (min-width: 640px) {
  .hero {
    min-height: 500px;
  }
}

@media (min-width: 1024px) {
  .hero {
    min-height: 520px;
  }
}

/* Navy scrim over the photograph: dense behind the copy on the left, clearing
   to nothing on the right. The previous version laid a near-opaque white veil
   over the image, which hid it; this keeps white copy legible while letting the
   beach photograph read as the hero. */
.hero-scrim {
  background-image:
    linear-gradient(
      to right,
      rgba(7, 29, 50, 0.86) 0%,
      rgba(7, 29, 50, 0.72) 26%,
      rgba(7, 29, 50, 0.44) 54%,
      rgba(7, 29, 50, 0.14) 80%,
      rgba(7, 29, 50, 0) 100%
    ),
    linear-gradient(to top, rgba(7, 29, 50, 0.4) 0%, rgba(7, 29, 50, 0) 36%);
}

/* On narrow screens the copy sits over the whole width of the photo, so the
   scrim runs top-to-bottom instead of left-to-right. */
@media (max-width: 639px) {
  .hero-scrim {
    background-image:
      linear-gradient(
        to bottom,
        rgba(7, 29, 50, 0.68) 0%,
        rgba(7, 29, 50, 0.56) 46%,
        rgba(7, 29, 50, 0.82) 100%
      );
  }
}

/* Headline line one: a light, faintly cool white so the hero reads luminous
   rather than flat. Solid white is the fallback for browsers without
   background-clip on text. No text-shadow here — a shadow under clipped text
   paints over the gradient in some browsers. */
.hero-title-line {
  color: #ffffff;
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .hero-title-line {
    background-image: linear-gradient(180deg, #ffffff 0%, #d3ebff 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

/* Headline accent — a vivid tropical-sunset gradient that stays bright against
   the navy scrim. Both lines need Tailwind `w-fit`: a full-width block stretches
   the gradient so only its first colours land behind the glyphs. */
.hero-accent {
  color: #ffd98a;
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .hero-accent {
    background-image: linear-gradient(
      96deg,
      #ffe066 0%,
      #ff9f45 32%,
      #ff5fa2 66%,
      #a97bff 100%
    );
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

/* Shown only when the hero photograph is missing from static/images/. Tuned for
   the dark scrim above it, so the hero never turns muddy. */
.hero-fallback {
  background-color: #0a3350;
  background-image:
    linear-gradient(180deg, rgba(56, 152, 255, 0.35) 0%, rgba(7, 29, 50, 0) 62%),
    repeating-linear-gradient(
      -45deg,
      rgba(255, 255, 255, 0.08) 0 2px,
      rgba(255, 255, 255, 0) 2px 18px
    );
}

/* ------------------------------------------------------------- footer ---- */
.footer-link {
  display: inline-block;
  font-size: 13.5px;
  line-height: 1.45;
  color: rgb(var(--brand-mist));
  transition: color 175ms ease, transform 175ms ease;
}

.footer-link:hover,
.footer-link:focus-visible {
  color: rgb(var(--brand-accent));
  /* A nudge rather than a jump: transform does not reflow the column. */
  transform: translateX(3px);
}

/* "Evening at the beach": a warm horizon glow over a cool ocean gradient, with a
   soft sun sitting just above the wave crest. */
.footer-sky {
  background-image:
    radial-gradient(115% 85% at 84% 0%, rgba(255, 170, 96, 0.3), rgba(255, 170, 96, 0) 58%),
    radial-gradient(90% 72% at 6% 0%, rgba(56, 152, 255, 0.22), rgba(56, 152, 255, 0) 60%),
    linear-gradient(180deg, #0a3d59 0%, #082c45 48%, #061d31 100%);
}

.footer-sun {
  position: absolute;
  top: 6px;
  right: 9%;
  width: 200px;
  height: 200px;
  border-radius: 999px;
  background: radial-gradient(
    closest-side,
    rgba(255, 216, 162, 0.55),
    rgba(255, 176, 94, 0.18) 60%,
    rgba(255, 176, 94, 0) 100%
  );
  pointer-events: none;
}

/* Warm hairline under each footer column heading. */
.footer-heading::after {
  content: '';
  display: block;
  width: 26px;
  height: 2px;
  margin-top: 10px;
  border-radius: 999px;
  background-image: linear-gradient(
    to right,
    rgb(var(--brand-accent)),
    rgba(255, 190, 120, 0.85)
  );
}


/* ==========================================================================
   Colour system
   Saturated accents, soft surfaces. Used by the homepage sections, the
   category tiles and the listing cards — one place to retune the whole site.
   ========================================================================== */

/* -------------------------------------------------- section eyebrow pill --- */
.tone-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 12px 6px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1;
}

.tone-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: currentColor;
}

.tone-pill--blue { background: rgb(var(--tone-blue-surface)); color: rgb(var(--tone-blue-ink)); }
.tone-pill--amber { background: rgb(var(--tone-amber-surface)); color: rgb(var(--tone-amber-ink)); }
.tone-pill--teal { background: rgb(var(--tone-teal-surface)); color: rgb(var(--tone-teal-ink)); }
.tone-pill--pink { background: rgb(var(--tone-pink-surface)); color: rgb(var(--tone-pink-ink)); }

/* ------------------------------------------------------- section washes --- */
.wash-blue {
  background-image: linear-gradient(180deg, #ffffff 0%, rgb(var(--brand-tint)) 46%, #ffffff 100%);
}

.wash-sand {
  background-image: linear-gradient(180deg, #ffffff 0%, rgb(var(--brand-sand)) 50%, #ffffff 100%);
}

.wash-mint {
  background-image: linear-gradient(180deg, #ffffff 0%, rgb(var(--brand-mint)) 50%, #ffffff 100%);
}

/* Thin gradient rule between the white sections. */
.section-rule {
  height: 1px;
  background-image: linear-gradient(
    to right,
    rgba(226, 235, 245, 0),
    rgba(11, 114, 231, 0.22) 22%,
    rgba(217, 119, 6, 0.18) 62%,
    rgba(226, 235, 245, 0)
  );
}

/* ------------------------------------------------------- rating in a row --- */
/* The rating that shares a hotel card's price line. Plain text on a phone card:
   at 390px the card leaves 136px for that row, and "৳2,500 – ৳3,500" at 12px plus
   the star chip is 137px when the pill keeps its padding — which is exactly what
   pushed the two onto separate lines. The amber pill comes back at 640px, where
   the row is 165px. */
.rating-inline {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  color: rgb(var(--brand-ink));
}

@media (min-width: 640px) {
  .rating-inline {
    gap: 5px;
    padding: 2px 6px;
    border-radius: 999px;
    background: rgb(var(--tone-amber-surface));
    color: rgb(var(--tone-amber-ink));
  }
}

/* Badge on a photo, e.g. Popular Choice. */
.badge-float {
  position: absolute;
  top: 10px;
  left: 10px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
  background: linear-gradient(135deg, rgb(var(--brand-orange)), rgb(var(--brand-coral)));
  box-shadow: 0 6px 16px -10px rgba(234, 88, 12, 0.9);
}

/* ---------------------------------------------------- listing filter bar -- */
/* On a phone the bar folds behind this toggle; from 640px up the toggle is
   hidden and the row is always shown. The toggle is a checkbox and the stylesheet
   is what answers it, so no JavaScript is involved — and it is a checkbox rather
   than a `<details>` because a browser hides a closed `<details>`'s content its
   own way (Chrome takes it out of the rendering flow), which no stylesheet can
   undo per screen size. */
.filter-panel__state {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  opacity: 0;
  pointer-events: none;
}

.filter-panel__summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.filter-panel__summary:focus-within {
  outline: 2px solid rgb(var(--brand-blue) / 0.55);
  outline-offset: 2px;
  border-radius: 14px;
}

.filter-panel__title {
  font-size: 12.5px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: rgb(var(--brand-navy));
}

/* How many filters are on, so a folded bar still says the list is narrowed. */
.filter-panel__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: rgb(var(--brand-blue));
  font-size: 10.5px;
  font-weight: 800;
  line-height: 1;
  color: #fff;
}

.filter-panel__chevron {
  display: inline-flex;
  margin-left: auto;
  color: rgb(var(--brand-muted));
}

.filter-panel__chevron svg {
  transform: rotate(90deg);
  transition: transform 0.2s ease;
}

.filter-panel__state:checked ~ .filter-panel__summary .filter-panel__chevron svg {
  transform: rotate(-90deg);
}

/* The body: folded until the toggle is tapped, always out from 640px up. */
.filter-panel__body {
  display: none;
  flex-wrap: wrap;
  align-items: center;
}

.filter-panel__state:checked ~ .filter-panel__body {
  display: flex;
}

/* Three dropdowns on one line. `.filter-select` is the label/select pair, kept
   inline so the row is a single line at every width — the row wraps rather than
   the controls growing, which is what keeps it short on a phone. */
.filter-select {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.filter-select__label {
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1;
  color: rgb(var(--brand-muted));
}

.filter-select__input {
  max-width: 44vw;
  height: 34px;
  padding: 0 8px;
  border: 1px solid rgb(var(--brand-line));
  border-radius: 10px;
  background: #fff;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: rgb(var(--brand-ink));
  cursor: pointer;
}

.filter-select__input:hover {
  border-color: rgb(var(--brand-blue) / 0.45);
}

.filter-select__input:focus-visible {
  outline: 2px solid rgb(var(--brand-blue) / 0.55);
  outline-offset: 1px;
}

@media (min-width: 640px) {
  /* The row fits from here on, so the panel is simply open — and the toggle is
     gone rather than sitting there saying nothing. */
  .filter-panel__state,
  .filter-panel__summary {
    display: none;
  }

  .filter-panel__body {
    display: flex;
  }

  .filter-select__input {
    max-width: none;
  }
}

/* The five-across card is ~170px wide and carries a favourite button in the
   opposite corner, so the badge is a size down — it must never reach the heart. */
.badge-float--sm {
  top: 8px;
  left: 8px;
  padding: 4px 8px;
  font-size: 9.5px;
}

/* ---------------------------------------------------------- favourites --- */
/* The heart on a hotel card. Once a hotel is saved in the browser (see the
   favourites block in main.js) it fills in and turns pink; the colour lives on
   the button so the outline and the fill always match. */
.favourite-btn svg {
  transition: fill 175ms ease, transform 175ms ease;
}

.favourite-btn.is-saved {
  color: rgb(var(--brand-pink));
}

.favourite-btn.is-saved svg {
  fill: currentColor;
  transform: scale(1.06);
}

@media (prefers-reduced-motion: reduce) {
  .favourite-btn svg {
    transition: none;
  }

  .favourite-btn.is-saved svg {
    transform: none;
  }
}

/* ------------------------------------------------- attractions slider --- */
/* Portrait (9:16) attraction tiles on a horizontal rail. `--per-view` is set
   inline from the homepage template (Homepage → Attractions section in the
   admin) and only applies from 1024px up; narrower screens show fewer tiles. */
.attraction-rail__track {
  --rail-gap: 1rem;
  display: flex;
  gap: var(--rail-gap);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-bottom: 0.5rem;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.attraction-rail__track::-webkit-scrollbar {
  display: none;
}

.attraction-rail__item {
  --cols: var(--per-view, 5);
  flex: 0 0 calc((100% - (var(--cols) - 1) * var(--rail-gap)) / var(--cols));
  scroll-snap-align: start;
}

@media (max-width: 1023.98px) {
  .attraction-rail__item {
    --cols: 3;
  }
}

@media (max-width: 639.98px) {
  .attraction-rail__item {
    --cols: 2;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .attraction-rail__track {
    scroll-behavior: smooth;
  }
}

/* Overlay arrows, revealed by main.js only when the rail actually overflows. */
.attraction-rail__btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #fff;
  color: rgb(var(--brand-navy));
  box-shadow: 0 12px 28px -12px rgba(16, 42, 67, 0.6);
  transition: background-color 175ms ease, color 175ms ease, opacity 175ms ease;
}

.attraction-rail__btn:hover,
.attraction-rail__btn:focus-visible {
  background: rgb(var(--brand-blue));
  color: #fff;
}

.attraction-rail__btn:disabled {
  opacity: 0.35;
  cursor: default;
}

.attraction-rail__btn[hidden] {
  display: none;
}

.attraction-rail__btn--prev {
  left: 0.25rem;
}

.attraction-rail__btn--next {
  right: 0.25rem;
}

@media (min-width: 1024px) {
  .attraction-rail__btn--prev {
    left: 0.75rem;
  }

  .attraction-rail__btn--next {
    right: 0.75rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .attraction-rail__btn {
    transition: none;
  }
}

/* --------------------------------------------------------- cta banner --- */
/* The closing banner above the footer. Its height comes from the copy and the
   padding, so it stays compact instead of reading as a second hero. */
.cta-banner {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: 24px;
  background: #0a3350;
  box-shadow: 0 26px 60px -34px rgba(7, 29, 50, 0.75);
}

.cta-banner__photo {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Keeps the loungers and the horizon in shot when the banner crops. */
  object-position: center 60%;
}

/* Sunset light on the open right-hand side, navy behind the copy on the left.
   The left half stays at 0.8 alpha or more so the white copy keeps its contrast
   even where the photo is brightest. */
.cta-banner__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(
      100deg,
      rgba(6, 24, 41, 0.9) 0%,
      rgba(6, 24, 41, 0.8) 30%,
      rgba(6, 24, 41, 0.52) 62%,
      rgba(6, 24, 41, 0.08) 100%
    ),
    linear-gradient(to top, rgba(6, 24, 41, 0.45) 0%, rgba(6, 24, 41, 0) 62%);
}

/* Narrow screens stack the copy across the whole photo, so the wash runs
   top-to-bottom instead of left-to-right. */
@media (max-width: 639px) {
  .cta-banner__scrim {
    background-image: linear-gradient(
      to bottom,
      rgba(6, 24, 41, 0.7) 0%,
      rgba(6, 24, 41, 0.62) 46%,
      rgba(6, 24, 41, 0.9) 100%
    );
  }
}

.cta-banner__content {
  position: relative;
  max-width: 560px;
  padding: 26px 24px 28px;
}

@media (min-width: 640px) {
  .cta-banner__content {
    padding: 32px 36px;
  }
}

@media (min-width: 1024px) {
  .cta-banner__content {
    padding: 34px 44px 36px;
  }
}

.cta-banner__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.32);
  background: rgba(255, 255, 255, 0.14);
  backdrop-filter: blur(6px);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.08em;
  line-height: 1;
  text-transform: uppercase;
  color: #fff;
}

.cta-banner__eyebrow::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: currentColor;
}

.cta-banner__title {
  margin-top: 14px;
  font-size: 26px;
  font-weight: 800;
  line-height: 1.16;
  letter-spacing: -0.02em;
  color: #fff;
}

@media (min-width: 640px) {
  .cta-banner__title {
    font-size: 30px;
  }
}

@media (min-width: 1024px) {
  .cta-banner__title {
    font-size: 34px;
  }
}

/* The words wrapped in *asterisks* in the admin. Flat amber is the fallback for
   browsers that cannot clip a gradient to text. */
.cta-banner__accent {
  color: #ffd98a;
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .cta-banner__accent {
    background-image: linear-gradient(96deg, #ffe066 0%, #ffb05c 42%, #ff8fb8 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

.cta-banner__text {
  margin-top: 10px;
  max-width: 480px;
  font-size: 14.5px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.9);
}

@media (min-width: 640px) {
  .cta-banner__text {
    font-size: 15.5px;
  }
}

.cta-banner__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
  margin-top: 20px;
}

.cta-banner__btn {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 44px;
  padding: 0 22px;
  border-radius: 999px;
  background-image: linear-gradient(96deg, #ffc061 0%, #ff9a4d 52%, #ff7593 100%);
  font-size: 13.5px;
  font-weight: 700;
  color: #10243a;
  box-shadow: 0 14px 30px -16px rgba(255, 138, 76, 0.95);
  transition: transform 200ms ease, box-shadow 200ms ease;
}

.cta-banner__btn:hover,
.cta-banner__btn:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 20px 38px -18px rgba(255, 138, 76, 1);
}

/* A light sweep across the button on hover — the one piece of motion that is
   decorative rather than informative. */
.cta-banner__btn::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: -60%;
  width: 45%;
  background-image: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.55) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  transform: skewX(-18deg);
  transition: transform 620ms ease;
  pointer-events: none;
}

.cta-banner__btn:hover::after,
.cta-banner__btn:focus-visible::after {
  transform: translateX(300%) skewX(-18deg);
}

.cta-banner__btn-arrow {
  width: 16px;
  height: 16px;
  flex: none;
  transition: transform 200ms ease;
}

.cta-banner__btn:hover .cta-banner__btn-arrow,
.cta-banner__btn:focus-visible .cta-banner__btn-arrow {
  transform: translateX(3px);
}

.cta-banner__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 600;
  color: #fff;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.45);
  text-underline-offset: 4px;
  transition: color 175ms ease, text-decoration-color 175ms ease;
}

.cta-banner__link:hover,
.cta-banner__link:focus-visible {
  color: #ffd98a;
  text-decoration-color: #ffd98a;
}

/* ------------------------------------------------- scroll reveal ------ */
/* Scoped to `.has-js` (set by an inline script in base.html) so a no-JS visitor
   never gets content that is stuck invisible. */
.has-js .reveal {
  opacity: 0;
  transform: translateY(22px);
}

.has-js .reveal.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 700ms ease, transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.has-js .cta-banner__eyebrow,
.has-js .cta-banner__title,
.has-js .cta-banner__text,
.has-js .cta-banner__actions {
  opacity: 0;
  transform: translateY(14px);
}

.has-js .is-visible .cta-banner__eyebrow,
.has-js .is-visible .cta-banner__title,
.has-js .is-visible .cta-banner__text,
.has-js .is-visible .cta-banner__actions {
  opacity: 1;
  transform: none;
  transition: opacity 560ms ease, transform 560ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.has-js .is-visible .cta-banner__eyebrow {
  transition-delay: 120ms;
}

.has-js .is-visible .cta-banner__title {
  transition-delay: 200ms;
}

.has-js .is-visible .cta-banner__text {
  transition-delay: 280ms;
}

.has-js .is-visible .cta-banner__actions {
  transition-delay: 360ms;
}

/* A very slow drift on the photo, so the banner is alive without being busy. */
@media (prefers-reduced-motion: no-preference) {
  .cta-banner__photo {
    animation: cta-drift 28s ease-in-out infinite alternate;
  }
}

@keyframes cta-drift {
  from {
    transform: scale(1.03) translate3d(0, 0, 0);
  }

  to {
    transform: scale(1.09) translate3d(-1.5%, -1.5%, 0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .has-js .reveal,
  .has-js .cta-banner__eyebrow,
  .has-js .cta-banner__title,
  .has-js .cta-banner__text,
  .has-js .cta-banner__actions {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .cta-banner__photo {
    animation: none;
  }

  .cta-banner__btn,
  .cta-banner__btn::after,
  .cta-banner__btn-arrow {
    transition: none;
  }

  .cta-banner__btn:hover,
  .cta-banner__btn:focus-visible {
    transform: none;
  }

  .cta-banner__btn:hover::after,
  .cta-banner__btn:focus-visible::after {
    transform: skewX(-18deg);
  }
}

/* -------------------------------------------------------- page articles --- */
/* The body of a blog post is HTML the owner wrote — either a whole page pasted
   into the panel (see `richtext.page`) or an article converted to HTML by
   `tools/make_blog_bangla.py`.

   A pasted page can be wider than the column it lands in: a table with fixed
   column widths, a `min-w-[900px]` row. Left alone, that one element gives the
   WHOLE page a horizontal scrollbar and slides the sidebar out of the content
   area, so the body scrolls inside its own column instead. (The sticky sidebar
   lives outside this element, so it is unaffected.) */
.page-body {
  overflow-x: auto;
}

/* Tailwind's preflight strips every default an article depends on: headings lose
   their size and weight, paragraphs and lists lose their spacing, bullets lose
   their markers. The elements that were given **no class** therefore get a real
   reading style here. Anything carrying a class is left exactly as it is — a
   pasted page lays itself out with utilities, and a rule like `.page-body h2`
   would outrank `class="mt-0"` and fight it. */
.page-body :is(h2, h3, h4, p, ul, ol, blockquote, table, hr, img, a, code):not([class]) {
  overflow-wrap: break-word;
}

.page-body :is(h2, h3, h4):not([class]) {
  color: rgb(var(--brand-navy));
  font-weight: 700;
  line-height: 1.35;
  margin-top: 2.25rem;
}

.page-body h2:not([class]) { font-size: 1.25rem; }
.page-body h3:not([class]) { font-size: 1.0625rem; margin-top: 1.75rem; }
.page-body h4:not([class]) { font-size: 1rem; margin-top: 1.5rem; }

.page-body p:not([class]) {
  color: rgb(var(--brand-muted));
  font-size: 0.9375rem;
  line-height: 1.75;
  margin-top: 0.75rem;
}

.page-body :is(ul, ol):not([class]) {
  color: rgb(var(--brand-ink));
  font-size: 0.90625rem;
  line-height: 1.7;
  margin-top: 1rem;
  padding-left: 1.25rem;
}

.page-body ul:not([class]) { list-style: disc; }
.page-body ol:not([class]) { list-style: decimal; }
.page-body :is(ul, ol) :is(ul, ol):not([class]) { margin-top: 0.5rem; }

.page-body li:not([class]) { margin-top: 0.375rem; }
.page-body li:not([class])::marker { color: rgb(var(--brand-blue)); }

.page-body a:not([class]) {
  color: rgb(var(--brand-blue));
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: rgb(var(--brand-blue) / 0.35);
  text-underline-offset: 2px;
}

.page-body a:not([class]):hover { text-decoration-color: currentColor; }

.page-body strong:not([class]) { color: rgb(var(--brand-navy)); font-weight: 700; }

.page-body blockquote:not([class]) {
  border-left: 3px solid rgb(var(--brand-blue) / 0.35);
  color: rgb(var(--brand-muted));
  margin-top: 1.25rem;
  padding: 0.25rem 0 0.25rem 1rem;
  font-style: italic;
}

.page-body code:not([class]) {
  background: rgb(var(--brand-blue-soft));
  border-radius: 5px;
  color: rgb(var(--brand-navy));
  font-size: 0.9em;
  padding: 0.1em 0.4em;
}

.page-body hr:not([class]) {
  border: 0;
  border-top: 1px solid rgb(var(--brand-line));
  margin: 2rem 0;
}

.page-body img:not([class]) {
  border-radius: 14px;
  height: auto;
  margin-top: 1rem;
  max-width: 100%;
}

.page-body table:not([class]) {
  border-collapse: collapse;
  font-size: 0.875rem;
  margin-top: 1.25rem;
  width: 100%;
}

.page-body :is(th, td):not([class]) {
  border: 1px solid rgb(var(--brand-line));
  padding: 0.6rem 0.75rem;
  text-align: left;
}

.page-body th:not([class]) {
  background: rgb(var(--brand-blue-soft));
  color: rgb(var(--brand-navy));
  font-weight: 700;
}

.page-body > :first-child { margin-top: 0; }

/* An article converted from the old sections editor keeps the readable measure
   the panel used to render it with. A pasted page carries its own container, so
   `page-body` sets no width at all. */
.article-prose {
  max-width: 760px;
}

