.ux-news-page {
  --ux-news-green: #176f55;
  --ux-news-green-dark: #0f5b45;
  --ux-news-green-light: #68d79b;
  --ux-news-green-pale: #eaf6f0;
  --ux-news-ink: #07130f;
  --ux-news-muted: #64736d;
  --ux-news-line: #e3eae6;
  --ux-news-line-strong: #d8e2dd;
  --ux-news-panel: #ffffff;
  --ux-news-bg: #f8faf9;
  --ux-news-dark: #04130f;
  --ux-news-shadow: 0 12px 34px rgba(7, 31, 24, 0.07);
  --ux-news-shadow-hover: 0 22px 54px rgba(7, 31, 24, 0.13);

  width: 100%;
  overflow-x: clip;
  background: var(--ux-news-bg);
  color: var(--ux-news-ink);
  font-family:
    Inter,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    Arial,
    sans-serif;
}

.ux-news-page,
.ux-news-page * {
  box-sizing: border-box;
}

.ux-news-page img {
  max-width: 100%;
}

.ux-news-page a {
  color: inherit;
}

.ux-news-page button,
.ux-news-page input {
  font: inherit;
}

.ux-news-page .ux-news-container,
.ux-news-page .ux-news-hero-shell,
.ux-news-page .ux-news-hero-nav-wrap {
  width: min(1320px, calc(100% - 72px));
  margin-right: auto;
  margin-left: auto;
}

.ux-news-page .ux-news-visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.ux-news-page .ux-news-icon {
  display: block;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}

/* =========================================================
   HERO
   ========================================================= */

.ux-news-page .ux-news-hero {
  position: relative;
  display: flex;
  min-height: 700px;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden;
  padding-top: 142px;
  background: var(--ux-news-dark);
  color: #ffffff;
  isolation: isolate;
}

.ux-news-page .ux-news-hero-media,
.ux-news-page .ux-news-hero-overlay {
  position: absolute;
  inset: 0;
}

.ux-news-page .ux-news-hero-media {
  z-index: -2;
  background: var(--ux-news-dark);
}

.ux-news-page .ux-news-hero-bg-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 68% center;
  filter: saturate(0.94) contrast(1.02);
}

.ux-news-page .ux-news-hero-overlay {
  z-index: -1;
  background:
    linear-gradient(
      90deg,
      rgba(2, 13, 11, 0.99) 0%,
      rgba(3, 17, 14, 0.95) 29%,
      rgba(5, 23, 19, 0.75) 47%,
      rgba(5, 22, 18, 0.31) 68%,
      rgba(4, 18, 15, 0.12) 100%
    ),
    linear-gradient(
      180deg,
      rgba(1, 8, 7, 0.58) 0%,
      rgba(1, 8, 7, 0.03) 42%,
      rgba(1, 10, 8, 0.82) 100%
    );
}

.ux-news-page .ux-news-hero-shell {
  position: relative;
  z-index: 1;
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  padding: 38px 0 52px;
}

.ux-news-page .ux-news-hero-copy {
  width: min(650px, 100%);
}

.ux-news-page .ux-news-eyebrow,
.ux-news-page .ux-news-report-eyebrow {
  margin: 0 0 18px;
  color: var(--ux-news-green-light);
  font-size: 12px;
  line-height: 1.2;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.ux-news-page .ux-news-hero-title {
  margin: 0 0 22px;
  color: #ffffff;
  font-size: clamp(52px, 4.65vw, 72px);
  line-height: 0.99;
  font-weight: 900;
  letter-spacing: -0.048em;
}

.ux-news-page .ux-news-hero-title-line {
  display: block;
}

.ux-news-page .ux-news-hero-title-line-accent {
  color: var(--ux-news-green-light);
}

.ux-news-page .ux-news-hero-intro {
  max-width: 515px;
  margin: 0 0 32px;
  color: rgba(255, 255, 255, 0.88);
  font-size: 16px;
  line-height: 1.68;
  font-weight: 450;
}

.ux-news-page .ux-news-search {
  width: min(510px, 100%);
  margin: 0;
}

.ux-news-page .ux-news-search-box {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) 110px;
  min-height: 56px;
  overflow: hidden;
  border-radius: 6px;
  background: #ffffff;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.25);
}

.ux-news-page .ux-news-search-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #34413d;
}

.ux-news-page .ux-news-search-input {
  width: 100%;
  min-width: 0;
  border: 0 !important;
  outline: 0 !important;
  background: transparent !important;
  color: var(--ux-news-ink);
  font-size: 13px;
  line-height: 1.2;
  box-shadow: none !important;
}

.ux-news-page .ux-news-search-input::placeholder {
  color: #88938f;
}

.ux-news-page .ux-news-search-button {
  appearance: none;
  border: 0;
  border-radius: 0;
  background: linear-gradient(135deg, #176f55, #218267);
  color: #ffffff;
  font-size: 11px;
  line-height: 1;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: 0.035em;
  cursor: pointer;
  transition:
    background 180ms ease,
    box-shadow 180ms ease;
}

.ux-news-page .ux-news-search-button:hover {
  background: var(--ux-news-green-dark);
  box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.05);
}

.ux-news-page .ux-news-hero-nav-wrap {
  position: relative;
  z-index: 1;
  padding: 18px 0 25px;
}

.ux-news-page .ux-news-category-nav {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, auto));
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  overflow-x: auto;
  scrollbar-width: none;
}

.ux-news-page .ux-news-category-nav::-webkit-scrollbar {
  display: none;
}

.ux-news-page .ux-news-category-link {
  display: inline-flex;
  min-height: 44px;
  flex: 0 0 auto;
  align-items: center;
  gap: 9px;
  color: rgba(255, 255, 255, 0.83);
  text-decoration: none;
  font-size: 11px;
  line-height: 1.2;
  font-weight: 750;
  white-space: nowrap;
  transition:
    color 180ms ease,
    transform 180ms ease;
}

.ux-news-page .ux-news-category-link:hover,
.ux-news-page .ux-news-category-link-active {
  color: #ffffff;
  transform: translateY(-1px);
}

.ux-news-page .ux-news-category-icon {
  display: inline-flex;
  width: 29px;
  height: 29px;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 7px;
  color: rgba(255, 255, 255, 0.77);
  transition:
    color 180ms ease,
    border-color 180ms ease,
    background 180ms ease;
}

.ux-news-page .ux-news-category-link:hover .ux-news-category-icon,
.ux-news-page .ux-news-category-link-active .ux-news-category-icon {
  border-color: rgba(101, 214, 154, 0.58);
  background: rgba(101, 214, 154, 0.11);
  color: var(--ux-news-green-light);
}

.ux-news-page .ux-news-category-icon .ux-news-icon {
  width: 16px;
  height: 16px;
}

/* =========================================================
   COMMON
   ========================================================= */

.ux-news-page .ux-news-main {
  padding: 44px 0 0;
  background: var(--ux-news-bg);
}

.ux-news-page .ux-news-button,
.ux-news-page .ux-news-load-more {
  appearance: none;
  display: inline-flex;
  min-height: 46px;
  align-items: center;
  justify-content: center;
  gap: 11px;
  border: 0;
  border-radius: 5px;
  padding: 0 24px;
  background: linear-gradient(135deg, #176f55, #228063);
  color: #ffffff;
  text-decoration: none;
  font-size: 11px;
  line-height: 1;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: 0.035em;
  cursor: pointer;
  transition:
    transform 180ms ease,
    box-shadow 180ms ease,
    background 180ms ease,
    color 180ms ease,
    border-color 180ms ease;
}

.ux-news-page .ux-news-button:hover,
.ux-news-page .ux-news-load-more:hover {
  transform: translateY(-1px);
  background: var(--ux-news-green-dark);
  box-shadow: 0 12px 26px rgba(23, 111, 85, 0.2);
}

.ux-news-page .ux-news-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 22px;
}

.ux-news-page .ux-news-section-title {
  margin: 0;
  color: var(--ux-news-ink);
  font-size: 25px;
  line-height: 1.15;
  font-weight: 900;
  letter-spacing: -0.025em;
}

.ux-news-page .ux-news-section-action {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--ux-news-green);
  text-decoration: none;
  font-size: 10px;
  line-height: 1;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: 0.035em;
  white-space: nowrap;
}

.ux-news-page .ux-news-section-action:hover {
  color: var(--ux-news-green-dark);
}

.ux-news-page .ux-news-section-action .ux-news-icon {
  width: 15px;
  height: 15px;
}

.ux-news-page .ux-news-search-input:focus,
.ux-news-page .ux-news-search-button:focus-visible,
.ux-news-page .ux-news-button:focus-visible,
.ux-news-page .ux-news-load-more:focus-visible,
.ux-news-page .ux-news-category-link:focus-visible,
.ux-news-page .ux-news-card-link:focus-visible,
.ux-news-page .ux-news-featured-media:focus-visible,
.ux-news-page .ux-news-featured-heading a:focus-visible,
.ux-news-page .ux-news-topic-card:focus-visible,
.ux-news-page .ux-news-section-action:focus-visible {
  outline: 3px solid rgba(101, 214, 154, 0.8);
  outline-offset: 3px;
}

/* =========================================================
   FEATURED
   ========================================================= */

.ux-news-page .ux-news-featured-section {
  padding: 0 0 28px;
}

.ux-news-page .ux-news-featured-card {
  display: grid;
  grid-template-columns: 54% 46%;
  min-height: 372px;
  overflow: hidden;
  border: 1px solid var(--ux-news-line);
  border-radius: 7px;
  background: #ffffff;
  box-shadow: 0 10px 32px rgba(7, 31, 24, 0.055);
}

.ux-news-page .ux-news-featured-media {
  display: block;
  min-height: 372px;
  overflow: hidden;
  background: var(--ux-news-dark);
}

.ux-news-page .ux-news-featured-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 280ms ease;
}

.ux-news-page .ux-news-featured-card:hover .ux-news-featured-image {
  transform: scale(1.025);
}

.ux-news-page .ux-news-featured-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 42px 46px 38px;
}

.ux-news-page .ux-news-featured-label {
  margin: 0 0 14px;
  color: var(--ux-news-green);
  font-size: 10px;
  line-height: 1;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: 0.035em;
}

.ux-news-page .ux-news-featured-heading {
  max-width: 430px;
  margin: 0 0 14px;
  color: var(--ux-news-ink);
  font-size: 34px;
  line-height: 1.06;
  font-weight: 900;
  letter-spacing: -0.035em;
}

.ux-news-page .ux-news-featured-heading a {
  color: inherit;
  text-decoration: none;
}

.ux-news-page .ux-news-featured-heading a:hover {
  color: var(--ux-news-green);
}

.ux-news-page .ux-news-featured-excerpt {
  max-width: 500px;
  margin: 0 0 18px;
  color: var(--ux-news-muted);
  font-size: 14px;
  line-height: 1.62;
}

.ux-news-page .ux-news-featured-meta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin-bottom: 22px;
}

.ux-news-page .ux-news-featured-category {
  display: inline-flex;
  min-height: 24px;
  align-items: center;
  padding: 0 12px;
  border: 1px solid var(--ux-news-line);
  border-radius: 999px;
  color: #627069;
  font-size: 10px;
  line-height: 1;
  font-weight: 700;
}

.ux-news-page .ux-news-article-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 13px;
}

.ux-news-page .ux-news-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: #76837e;
  font-size: 10px;
  line-height: 1.2;
  font-weight: 650;
}

.ux-news-page .ux-news-meta-item .ux-news-icon {
  width: 14px;
  height: 14px;
  color: var(--ux-news-green);
}

/* =========================================================
   LATEST NEWS
   ========================================================= */

.ux-news-page .ux-news-latest-section {
  padding: 26px 0 34px;
}

.ux-news-page .ux-news-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 23px;
}

.ux-news-page .ux-news-grid-count-1 {
  grid-template-columns: minmax(0, 1fr);
  max-width: 316px;
}

.ux-news-page .ux-news-grid-count-2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  max-width: 660px;
}

.ux-news-page .ux-news-grid-count-3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  max-width: 1000px;
}

.ux-news-page .ux-news-grid-count-5 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.ux-news-page .ux-news-card {
  min-width: 0;
  height: 100%;
}

.ux-news-page .ux-news-card-link {
  display: flex;
  height: 100%;
  min-height: 307px;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--ux-news-line);
  border-radius: 6px;
  background: var(--ux-news-panel);
  text-decoration: none;
  box-shadow: 0 7px 22px rgba(7, 31, 24, 0.035);
  transition:
    transform 180ms ease,
    box-shadow 180ms ease,
    border-color 180ms ease;
}

.ux-news-page .ux-news-card-link:hover {
  transform: translateY(-4px);
  border-color: rgba(23, 111, 85, 0.28);
  box-shadow: var(--ux-news-shadow-hover);
}

.ux-news-page .ux-news-card-media {
  display: block;
  aspect-ratio: 1.65 / 1;
  overflow: hidden;
  background: var(--ux-news-dark);
}

.ux-news-page .ux-news-card-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 240ms ease;
}

.ux-news-page .ux-news-card-link:hover .ux-news-card-image {
  transform: scale(1.035);
}

.ux-news-page .ux-news-card-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 16px 16px 13px;
}

.ux-news-page .ux-news-card-category {
  display: block;
  min-height: 12px;
  margin-bottom: 9px;
  color: var(--ux-news-green);
  font-size: 9px;
  line-height: 1.2;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: 0.035em;
}

.ux-news-page .ux-news-card-title {
  display: -webkit-box;
  min-height: 43px;
  margin: 0;
  overflow: hidden;
  color: var(--ux-news-ink);
  font-size: 16px;
  line-height: 1.28;
  font-weight: 850;
  letter-spacing: -0.018em;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.ux-news-page .ux-news-card-footer {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 8px;
  margin-top: auto;
  padding-top: 15px;
}

.ux-news-page .ux-news-card-footer .ux-news-article-meta {
  gap: 9px;
}

.ux-news-page .ux-news-card-footer .ux-news-meta-item {
  font-size: 9px;
}

.ux-news-page .ux-news-card-footer .ux-news-meta-item .ux-news-icon {
  width: 12px;
  height: 12px;
}

.ux-news-page .ux-news-card-arrow {
  display: inline-flex;
  width: 24px;
  height: 24px;
  flex: 0 0 24px;
  align-items: center;
  justify-content: center;
  color: var(--ux-news-ink);
}

.ux-news-page .ux-news-card-arrow .ux-news-icon {
  width: 15px;
  height: 15px;
}

.ux-news-page .ux-news-load-more-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-top: 30px;
}

.ux-news-page .ux-news-load-more {
  min-width: 228px;
  border: 1px solid #77a996;
  background: #ffffff;
  color: var(--ux-news-green);
}

.ux-news-page .ux-news-load-more:hover {
  color: #ffffff;
}

.ux-news-page .ux-news-load-more .ux-news-icon {
  width: 15px;
  height: 15px;
  transform: rotate(90deg);
}

.ux-news-page .ux-news-load-more[disabled] {
  opacity: 0.55;
  cursor: wait;
}

.ux-news-page .ux-news-load-more-status {
  min-height: 16px;
  margin: 0;
  color: var(--ux-news-muted);
  font-size: 11px;
}

/* =========================================================
   PERFORMANCE REPORT
   ========================================================= */

.ux-news-page .ux-news-report-section {
  padding: 24px 0 31px;
}

.ux-news-page .ux-news-report {
  position: relative;
  display: grid;
  grid-template-columns:
    minmax(0, 1.2fr)
    minmax(190px, 0.62fr)
    minmax(280px, 0.82fr);
  min-height: 292px;
  align-items: center;
  gap: 34px;
  overflow: visible;
  border-radius: 7px;
  padding: 36px 62px;
  background:
    radial-gradient(
      circle at 55% 54%,
      rgba(71, 203, 137, 0.21) 0,
      rgba(71, 203, 137, 0.09) 18%,
      rgba(71, 203, 137, 0) 40%
    ),
    linear-gradient(110deg, #03130f 0%, #08251e 55%, #051713 100%);
  color: #ffffff;
  box-shadow: 0 11px 32px rgba(7, 31, 24, 0.1);
}

.ux-news-page .ux-news-report::before {
  content: "";
  position: absolute;
  top: 22px;
  bottom: 22px;
  left: 37%;
  width: 31%;
  border: 1px solid rgba(101, 214, 154, 0.1);
  border-radius: 50%;
  pointer-events: none;
}

.ux-news-page .ux-news-report-copy,
.ux-news-page .ux-news-report-cover-wrap,
.ux-news-page .ux-news-report-highlights {
  position: relative;
  z-index: 1;
}

.ux-news-page .ux-news-report-title {
  max-width: 440px;
  margin: 0 0 12px;
  color: #ffffff;
  font-size: 38px;
  line-height: 1.03;
  font-weight: 900;
  letter-spacing: -0.035em;
}

.ux-news-page .ux-news-report-title span {
  color: var(--ux-news-green-light);
}

.ux-news-page .ux-news-report-description {
  max-width: 490px;
  margin: 0 0 22px;
  color: rgba(255, 255, 255, 0.78);
  font-size: 13px;
  line-height: 1.62;
}

.ux-news-page .ux-news-report-button {
  background: linear-gradient(135deg, #176f55, #218267);
}

.ux-news-page .ux-news-report-button:hover {
  background: #ffffff;
  color: var(--ux-news-ink);
}

.ux-news-page .ux-news-report-cover-wrap {
  display: flex;
  height: 100%;
  align-items: center;
  justify-content: center;
}

.ux-news-page .ux-news-report-cover-image {
  display: block;
  width: min(205px, 100%);
  max-height: 322px;
  object-fit: contain;
  border-radius: 3px;
  filter: drop-shadow(18px 22px 24px rgba(0, 0, 0, 0.42));
  transform: translateY(22px);
}

.ux-news-page .ux-news-report-highlights {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ux-news-page .ux-news-report-highlights li {
  display: flex;
  min-height: 43px;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.86);
  font-size: 12px;
  line-height: 1.3;
  font-weight: 550;
}

.ux-news-page .ux-news-report-highlights li:first-child {
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.ux-news-page .ux-news-report-highlights span:first-child {
  display: inline-flex;
  width: 31px;
  height: 31px;
  align-items: center;
  justify-content: center;
  color: var(--ux-news-green-light);
}

.ux-news-page .ux-news-report-highlights .ux-news-icon {
  width: 18px;
  height: 18px;
}

.ux-news-page .ux-news-report-no-cover {
  grid-template-columns: minmax(0, 1fr) minmax(280px, 0.82fr);
}

.ux-news-page .ux-news-report-no-highlights {
  grid-template-columns: minmax(0, 1fr) minmax(190px, 0.62fr);
}

.ux-news-page
  .ux-news-report-no-cover.ux-news-report-no-highlights {
  grid-template-columns: 1fr;
}

/* =========================================================
   TOPICS
   ========================================================= */

.ux-news-page .ux-news-topics-section {
  padding: 24px 0 17px;
}

.ux-news-page .ux-news-topic-grid {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 12px;
}

.ux-news-page .ux-news-topic-card {
  display: flex;
  min-width: 0;
  min-height: 101px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 12px 8px;
  border: 1px solid var(--ux-news-line);
  border-radius: 6px;
  background: #ffffff;
  color: var(--ux-news-ink);
  text-align: center;
  text-decoration: none;
  box-shadow: 0 6px 18px rgba(7, 31, 24, 0.025);
  transition:
    transform 180ms ease,
    box-shadow 180ms ease,
    border-color 180ms ease,
    color 180ms ease;
}

.ux-news-page .ux-news-topic-card:hover,
.ux-news-page .ux-news-topic-card-active {
  transform: translateY(-3px);
  border-color: rgba(23, 111, 85, 0.35);
  color: var(--ux-news-green);
  box-shadow: var(--ux-news-shadow);
}

.ux-news-page .ux-news-topic-icon {
  display: inline-flex;
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  color: var(--ux-news-green);
}

.ux-news-page .ux-news-topic-icon .ux-news-icon {
  width: 27px;
  height: 27px;
}

.ux-news-page .ux-news-topic-label {
  color: inherit;
  font-size: 11px;
  line-height: 1.2;
  font-weight: 800;
}

/* =========================================================
   NEWSLETTER
   ========================================================= */

.ux-news-page .ux-news-newsletter-section {
  padding: 17px 0 45px;
}

.ux-news-page .ux-news-newsletter {
  display: grid;
  grid-template-columns: 58px minmax(260px, 0.92fr) minmax(420px, 1.4fr);
  min-height: 104px;
  align-items: center;
  gap: 22px;
  padding: 20px 28px;
  border: 1px solid var(--ux-news-line);
  border-radius: 7px;
  background: #ffffff;
  box-shadow: 0 7px 22px rgba(7, 31, 24, 0.025);
}

.ux-news-page .ux-news-newsletter-icon {
  display: inline-flex;
  width: 54px;
  height: 54px;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: linear-gradient(135deg, #176f55, #218267);
  color: #ffffff;
}

.ux-news-page .ux-news-newsletter-icon .ux-news-icon {
  width: 29px;
  height: 29px;
}

.ux-news-page .ux-news-newsletter-title {
  margin: 0 0 4px;
  color: var(--ux-news-ink);
  font-size: 21px;
  line-height: 1.15;
  font-weight: 900;
  letter-spacing: -0.02em;
}

.ux-news-page .ux-news-newsletter-copy p {
  margin: 0;
  color: var(--ux-news-muted);
  font-size: 11px;
  line-height: 1.5;
}

.ux-news-page .ux-news-newsletter-form {
  min-width: 0;
}

.ux-news-page .ux-news-newsletter-form form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px;
  align-items: center;
  gap: 10px;
}

.ux-news-page .ux-news-newsletter-form input[type="email"],
.ux-news-page .ux-news-newsletter-form input[type="text"],
.ux-news-page .ux-news-newsletter-form input[type="search"] {
  width: 100%;
  min-height: 44px;
  border: 1px solid var(--ux-news-line-strong);
  border-radius: 5px;
  padding: 0 14px;
  background: #ffffff;
  color: var(--ux-news-ink);
  font-size: 12px;
  box-shadow: none;
}

.ux-news-page .ux-news-newsletter-form input[type="submit"],
.ux-news-page .ux-news-newsletter-form button {
  min-height: 44px;
  border: 0;
  border-radius: 5px;
  padding: 0 24px;
  background: linear-gradient(135deg, #176f55, #218267);
  color: #ffffff;
  font-size: 11px;
  line-height: 1;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: 0.035em;
  cursor: pointer;
}

/* =========================================================
   EMPTY STATE
   ========================================================= */

.ux-news-page .ux-news-empty-state {
  display: flex;
  min-height: 220px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 30px;
  border: 1px solid var(--ux-news-line);
  border-radius: 7px;
  background: #ffffff;
  text-align: center;
  box-shadow: 0 7px 22px rgba(7, 31, 24, 0.025);
}

.ux-news-page .ux-news-empty-state h2 {
  margin: 0 0 8px;
  color: var(--ux-news-ink);
  font-size: 26px;
  line-height: 1.15;
  font-weight: 900;
  letter-spacing: -0.02em;
}

.ux-news-page .ux-news-empty-state p {
  max-width: 520px;
  margin: 0 0 20px;
  color: var(--ux-news-muted);
  font-size: 14px;
  line-height: 1.55;
}

/* =========================================================
   RESPONSIVE
   ========================================================= */

@media (max-width: 1180px) {
  .ux-news-page .ux-news-container,
  .ux-news-page .ux-news-hero-shell,
  .ux-news-page .ux-news-hero-nav-wrap {
    width: min(100% - 54px, 1320px);
  }

  .ux-news-page .ux-news-hero {
    min-height: 650px;
  }

  .ux-news-page .ux-news-category-nav {
    justify-content: flex-start;
    gap: 28px;
  }

  .ux-news-page .ux-news-featured-content {
    padding: 36px;
  }

  .ux-news-page .ux-news-report {
    grid-template-columns:
      minmax(0, 1.1fr)
      minmax(170px, 0.55fr)
      minmax(240px, 0.75fr);
    gap: 25px;
    padding: 34px 40px;
  }

  .ux-news-page .ux-news-topic-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 1024px) {
  .ux-news-page .ux-news-hero {
    min-height: 620px;
    padding-top: 122px;
  }

  .ux-news-page .ux-news-featured-card {
    grid-template-columns: 1fr;
  }

  .ux-news-page .ux-news-featured-media {
    min-height: 350px;
  }

  .ux-news-page .ux-news-grid,
  .ux-news-page .ux-news-grid-count-5 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ux-news-page .ux-news-report,
  .ux-news-page .ux-news-report-no-cover,
  .ux-news-page .ux-news-report-no-highlights {
    grid-template-columns: 1fr;
  }

  .ux-news-page .ux-news-report-cover-wrap {
    justify-content: flex-start;
  }

  .ux-news-page .ux-news-report-cover-image {
    width: 180px;
    transform: none;
  }

  .ux-news-page .ux-news-newsletter {
    grid-template-columns: 58px minmax(0, 1fr);
  }

  .ux-news-page .ux-news-newsletter-form {
    grid-column: 1 / -1;
  }
}

@media (max-width: 768px) {
  .ux-news-page .ux-news-container,
  .ux-news-page .ux-news-hero-shell,
  .ux-news-page .ux-news-hero-nav-wrap {
    width: min(100% - 32px, 1320px);
  }

  .ux-news-page .ux-news-hero {
    min-height: 650px;
    padding-top: 102px;
  }

  .ux-news-page .ux-news-hero-bg-image {
    object-position: 61% center;
  }

  .ux-news-page .ux-news-hero-overlay {
    background:
      linear-gradient(
        90deg,
        rgba(2, 13, 11, 0.98) 0%,
        rgba(3, 17, 14, 0.91) 64%,
        rgba(4, 19, 16, 0.52) 100%
      ),
      linear-gradient(
        180deg,
        rgba(1, 8, 7, 0.6) 0%,
        rgba(1, 8, 7, 0.1) 40%,
        rgba(1, 10, 8, 0.87) 100%
      );
  }

  .ux-news-page .ux-news-hero-title {
    font-size: 43px;
    line-height: 1.03;
  }

  .ux-news-page .ux-news-hero-intro {
    max-width: 460px;
    font-size: 14px;
  }

  .ux-news-page .ux-news-search-box {
    grid-template-columns: 48px minmax(0, 1fr);
  }

  .ux-news-page .ux-news-search-button {
    grid-column: 1 / -1;
    min-height: 48px;
    border-top: 1px solid #e8eeeb;
  }

  .ux-news-page .ux-news-category-nav {
    gap: 20px;
    padding-bottom: 6px;
    scroll-snap-type: x proximity;
  }

  .ux-news-page .ux-news-category-link {
    scroll-snap-align: start;
  }

  .ux-news-page .ux-news-main {
    padding-top: 30px;
  }

  .ux-news-page .ux-news-featured-content {
    padding: 27px 24px;
  }

  .ux-news-page .ux-news-featured-heading {
    font-size: 28px;
  }

  .ux-news-page .ux-news-section-head {
    align-items: flex-start;
    flex-direction: column;
    gap: 10px;
  }

  .ux-news-page .ux-news-grid,
  .ux-news-page .ux-news-grid-count-1,
  .ux-news-page .ux-news-grid-count-2,
  .ux-news-page .ux-news-grid-count-3,
  .ux-news-page .ux-news-grid-count-5 {
    max-width: none;
    grid-template-columns: 1fr;
  }

  .ux-news-page .ux-news-card-link {
    min-height: 0;
  }

  .ux-news-page .ux-news-report {
    padding: 28px 24px;
  }

  .ux-news-page .ux-news-report-title {
    font-size: 30px;
  }

  .ux-news-page .ux-news-topic-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ux-news-page .ux-news-newsletter {
    grid-template-columns: 1fr;
    padding: 22px;
  }

  .ux-news-page .ux-news-newsletter-form form {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 430px) {
  .ux-news-page .ux-news-container,
  .ux-news-page .ux-news-hero-shell,
  .ux-news-page .ux-news-hero-nav-wrap {
    width: min(100% - 26px, 1320px);
  }

  .ux-news-page .ux-news-hero {
    min-height: 625px;
    padding-top: 94px;
  }

  .ux-news-page .ux-news-hero-title {
    font-size: 36px;
  }

  .ux-news-page .ux-news-hero-intro {
    font-size: 13px;
  }

  .ux-news-page .ux-news-featured-media {
    min-height: 235px;
  }

  .ux-news-page .ux-news-featured-heading,
  .ux-news-page .ux-news-report-title,
  .ux-news-page .ux-news-section-title,
  .ux-news-page .ux-news-empty-state h2 {
    font-size: 25px;
  }

  .ux-news-page .ux-news-topic-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 9px;
  }

  .ux-news-page .ux-news-topic-card {
    min-height: 94px;
  }
}

@media (max-width: 360px) {
  .ux-news-page .ux-news-hero-title {
    font-size: 32px;
  }

  .ux-news-page .ux-news-card-body {
    padding: 15px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ux-news-page .ux-news-search-button,
  .ux-news-page .ux-news-button,
  .ux-news-page .ux-news-load-more,
  .ux-news-page .ux-news-category-link,
  .ux-news-page .ux-news-featured-image,
  .ux-news-page .ux-news-card-link,
  .ux-news-page .ux-news-card-image,
  .ux-news-page .ux-news-topic-card {
    transition: none;
  }
}
<?php

if (!defined('ABSPATH')) {
    exit;
}

class UX_News_Page
{
    const UX_NEWS_SHORTCODE = 'ux_news_page';
    const UX_NEWS_FEATURED_META = '_aoro_featured_news';

    /**
     * Categories displayed in the hero navigation.
     *
     * These remain part of the page structure even when they currently
     * contain no published articles.
     */
    private $ux_news_category_labels = array(
        'Company News' => array(
            'slug' => 'company-news',
            'icon' => 'building',
        ),
        'Industry News' => array(
            'slug' => 'industry-news',
            'icon' => 'chart',
        ),
        'Engineering' => array(
            'slug' => 'engineering',
            'icon' => 'gear',
        ),
        'Products' => array(
            'slug' => 'products',
            'icon' => 'box',
        ),
        'Events' => array(
            'slug' => 'events',
            'icon' => 'people',
        ),
        'Press Releases' => array(
            'slug' => 'press-releases',
            'icon' => 'press',
        ),
    );

    /**
     * Topics displayed in the lower topic navigation.
     *
     * Topics use the WordPress post_tag taxonomy, not categories.
     */
    private $ux_news_topic_labels = array(
        'Solar Panels' => array(
            'slug' => 'solar-panels',
            'icon' => 'sun',
        ),
        'Battery Storage' => array(
            'slug' => 'battery-storage',
            'icon' => 'battery',
        ),
        'Heat Pumps' => array(
            'slug' => 'heat-pumps',
            'icon' => 'heat',
        ),
        'Commercial' => array(
            'slug' => 'commercial',
            'icon' => 'building',
        ),
        'Residential' => array(
            'slug' => 'residential',
            'icon' => 'home',
        ),
        'Property Developers' => array(
            'slug' => 'property-developers',
            'icon' => 'developer',
        ),
        'EV Charging' => array(
            'slug' => 'ev-charging',
            'icon' => 'ev',
        ),
        'Finance & ROI' => array(
            'slug' => 'finance-roi',
            'icon' => 'finance',
        ),
    );

    public function __construct()
    {
        add_action(
            'ux_booster_render_news_page_tab',
            array($this, 'ux_news_render_admin_tab')
        );

        add_shortcode(
            self::UX_NEWS_SHORTCODE,
            array($this, 'ux_news_render_shortcode')
        );

        add_action(
            'wp_enqueue_scripts',
            array($this, 'ux_news_enqueue_frontend_assets')
        );

        add_action(
            'admin_enqueue_scripts',
            array($this, 'ux_news_enqueue_admin_assets')
        );

        add_action(
            'admin_init',
            array($this, 'ux_news_register_settings')
        );

        add_action(
            'add_meta_boxes_post',
            array($this, 'ux_news_add_featured_meta_box')
        );

        add_action(
            'save_post_post',
            array($this, 'ux_news_save_featured_meta'),
            10,
            2
        );

        add_action(
            'wp_ajax_ux_news_load_more',
            array($this, 'ux_news_ajax_load_more')
        );

        add_action(
            'wp_ajax_nopriv_ux_news_load_more',
            array($this, 'ux_news_ajax_load_more')
        );
    }

    public function ux_news_register_settings()
    {
        $options = array(
            'ux_news_hero_eyebrow',
            'ux_news_hero_heading',
            'ux_news_hero_intro',
            'ux_news_hero_image_id',
            'ux_news_hero_image_url',
            'ux_news_featured_post_id',
            'ux_news_latest_count',
            'ux_news_load_more_label',
            'ux_news_report_title',
            'ux_news_report_year',
            'ux_news_report_description',
            'ux_news_report_cover_image_id',
            'ux_news_report_cover_image_url',
            'ux_news_report_pdf_id',
            'ux_news_report_pdf_url',
            'ux_news_report_highlights',
            'ux_news_newsletter_heading',
            'ux_news_newsletter_text',
            'ux_news_newsletter_shortcode',
        );

        foreach ($options as $option) {
            register_setting(
                'ux_news_page_options',
                $option
            );
        }
    }

    public function ux_news_enqueue_frontend_assets()
    {
        if (!$this->ux_news_should_enqueue_frontend_assets()) {
            return;
        }

        $css_path = UX_BOOSTER_PATH . 'assets/css/news-page.css';
        $js_path = UX_BOOSTER_PATH . 'assets/js/news-page.js';

        wp_enqueue_style(
            'ux-news-page-css',
            UX_BOOSTER_URL . 'assets/css/news-page.css',
            array(),
            file_exists($css_path)
                ? (string) filemtime($css_path)
                : '1.0.0'
        );

        wp_enqueue_script(
            'ux-news-page-js',
            UX_BOOSTER_URL . 'assets/js/news-page.js',
            array(),
            file_exists($js_path)
                ? (string) filemtime($js_path)
                : '1.0.0',
            true
        );

        wp_localize_script(
            'ux-news-page-js',
            'uxNewsPage',
            array(
                'ajaxUrl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce(
                    'ux_news_load_more_nonce'
                ),
                'action' => 'ux_news_load_more',
                'loadingText' => __(
                    'Loading...',
                    'ux-booster'
                ),
                'errorText' => __(
                    'Unable to load more news right now.',
                    'ux-booster'
                ),
            )
        );
    }

    public function ux_news_enqueue_admin_assets($hook)
    {
        if (strpos((string) $hook, 'ux-booster') === false) {
            return;
        }

        $current_tab = isset($_GET['tab'])
            ? sanitize_key(wp_unslash($_GET['tab']))
            : '';

        if ($current_tab !== 'news_page') {
            return;
        }

        wp_enqueue_media();

        $admin_js_path = UX_BOOSTER_PATH
            . 'assets/js/news-page-admin.js';

        wp_enqueue_script(
            'ux-news-page-admin-js',
            UX_BOOSTER_URL . 'assets/js/news-page-admin.js',
            array('jquery'),
            file_exists($admin_js_path)
                ? (string) filemtime($admin_js_path)
                : '1.0.0',
            true
        );

        wp_localize_script(
            'ux-news-page-admin-js',
            'uxNewsAdminPage',
            array(
                'imageFrameTitle' => __(
                    'Choose image',
                    'ux-booster'
                ),
                'imageFrameText' => __(
                    'Use this image',
                    'ux-booster'
                ),
                'fileFrameTitle' => __(
                    'Choose file',
                    'ux-booster'
                ),
                'fileFrameText' => __(
                    'Use this file',
                    'ux-booster'
                ),
            )
        );
    }

    public function ux_news_render_admin_tab()
    {
        if (!current_user_can('manage_options')) {
            return;
        }

        $this->ux_news_maybe_save_settings();

        $settings = $this->ux_news_get_settings();

        $recent_posts = get_posts(
            array(
                'post_type' => 'post',
                'post_status' => 'publish',
                'posts_per_page' => 50,
                'orderby' => 'date',
                'order' => 'DESC',
                'ignore_sticky_posts' => true,
            )
        );

        $taxonomy_status = $this->ux_news_get_taxonomy_setup_status();
        ?>

        <div class="ux-booster-card">
            <h3>News Page</h3>

            <p>
                Shortcode:
                <code>[ux_news_page]</code>
            </p>

            <form method="post">
                <?php
                wp_nonce_field(
                    'ux_news_save_settings',
                    'ux_news_settings_nonce'
                );
                ?>

                <h4>Hero</h4>

                <table
                    class="form-table"
                    role="presentation"
                >
                    <tbody>
                        <tr>
                            <th scope="row">
                                <label for="ux_news_hero_eyebrow">
                                    Eyebrow
                                </label>
                            </th>

                            <td>
                                <input
                                    type="text"
                                    id="ux_news_hero_eyebrow"
                                    name="ux_news_hero_eyebrow"
                                    value="<?php echo esc_attr($settings['hero_eyebrow']); ?>"
                                    class="regular-text"
                                >
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                <label for="ux_news_hero_heading">
                                    H1
                                </label>
                            </th>

                            <td>
                                <textarea
                                    id="ux_news_hero_heading"
                                    name="ux_news_hero_heading"
                                    rows="3"
                                    class="large-text"
                                ><?php echo esc_textarea($settings['hero_heading']); ?></textarea>
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                <label for="ux_news_hero_intro">
                                    Introduction
                                </label>
                            </th>

                            <td>
                                <textarea
                                    id="ux_news_hero_intro"
                                    name="ux_news_hero_intro"
                                    rows="3"
                                    class="large-text"
                                ><?php echo esc_textarea($settings['hero_intro']); ?></textarea>
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                Hero image
                            </th>

                            <td>
                                <?php
                                $this->ux_news_render_admin_media_field(
                                    'ux_news_hero_image',
                                    $settings['hero_image_id'],
                                    $settings['hero_image_url'],
                                    'image'
                                );
                                ?>
                            </td>
                        </tr>
                    </tbody>
                </table>

                <h4>Featured Story</h4>

                <table
                    class="form-table"
                    role="presentation"
                >
                    <tbody>
                        <tr>
                            <th scope="row">
                                <label for="ux_news_featured_post_id">
                                    Manual featured post
                                </label>
                            </th>

                            <td>
                                <select
                                    id="ux_news_featured_post_id"
                                    name="ux_news_featured_post_id"
                                >
                                    <option value="0">
                                        Automatic: latest marked featured,
                                        then latest post
                                    </option>

                                    <?php foreach ($recent_posts as $recent_post) : ?>
                                        <option
                                            value="<?php echo esc_attr($recent_post->ID); ?>"
                                            <?php selected(
                                                $settings['featured_post_id'],
                                                $recent_post->ID
                                            ); ?>
                                        >
                                            <?php
                                            echo esc_html(
                                                get_the_title($recent_post)
                                            );
                                            ?>
                                        </option>
                                    <?php endforeach; ?>
                                </select>

                                <p class="description">
                                    Post editors can also mark posts using
                                    the AORO Featured News box.
                                </p>
                            </td>
                        </tr>
                    </tbody>
                </table>

                <h4>Latest News</h4>

                <table
                    class="form-table"
                    role="presentation"
                >
                    <tbody>
                        <tr>
                            <th scope="row">
                                <label for="ux_news_latest_count">
                                    Initial posts
                                </label>
                            </th>

                            <td>
                                <input
                                    type="number"
                                    min="1"
                                    max="24"
                                    id="ux_news_latest_count"
                                    name="ux_news_latest_count"
                                    value="<?php echo esc_attr($settings['latest_count']); ?>"
                                >
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                <label for="ux_news_load_more_label">
                                    Load more label
                                </label>
                            </th>

                            <td>
                                <input
                                    type="text"
                                    id="ux_news_load_more_label"
                                    name="ux_news_load_more_label"
                                    value="<?php echo esc_attr($settings['load_more_label']); ?>"
                                    class="regular-text"
                                >
                            </td>
                        </tr>
                    </tbody>
                </table>

                <h4>Performance Report</h4>

                <table
                    class="form-table"
                    role="presentation"
                >
                    <tbody>
                        <tr>
                            <th scope="row">
                                <label for="ux_news_report_title">
                                    Report title
                                </label>
                            </th>

                            <td>
                                <input
                                    type="text"
                                    id="ux_news_report_title"
                                    name="ux_news_report_title"
                                    value="<?php echo esc_attr($settings['report_title']); ?>"
                                    class="regular-text"
                                >
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                <label for="ux_news_report_year">
                                    Report year
                                </label>
                            </th>

                            <td>
                                <input
                                    type="text"
                                    id="ux_news_report_year"
                                    name="ux_news_report_year"
                                    value="<?php echo esc_attr($settings['report_year']); ?>"
                                    class="regular-text"
                                >
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                <label for="ux_news_report_description">
                                    Description
                                </label>
                            </th>

                            <td>
                                <textarea
                                    id="ux_news_report_description"
                                    name="ux_news_report_description"
                                    rows="3"
                                    class="large-text"
                                ><?php echo esc_textarea($settings['report_description']); ?></textarea>
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                Report cover image
                            </th>

                            <td>
                                <?php
                                $this->ux_news_render_admin_media_field(
                                    'ux_news_report_cover_image',
                                    $settings['report_cover_image_id'],
                                    $settings['report_cover_image_url'],
                                    'image'
                                );
                                ?>
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                PDF file or URL
                            </th>

                            <td>
                                <?php
                                $this->ux_news_render_admin_media_field(
                                    'ux_news_report_pdf',
                                    $settings['report_pdf_id'],
                                    $settings['report_pdf_url'],
                                    'file'
                                );
                                ?>
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                <label for="ux_news_report_highlights">
                                    Highlights
                                </label>
                            </th>

                            <td>
                                <textarea
                                    id="ux_news_report_highlights"
                                    name="ux_news_report_highlights"
                                    rows="6"
                                    class="large-text"
                                ><?php echo esc_textarea($settings['report_highlights']); ?></textarea>
                            </td>
                        </tr>
                    </tbody>
                </table>

                <h4>Newsletter</h4>

                <table
                    class="form-table"
                    role="presentation"
                >
                    <tbody>
                        <tr>
                            <th scope="row">
                                <label for="ux_news_newsletter_heading">
                                    Heading
                                </label>
                            </th>

                            <td>
                                <input
                                    type="text"
                                    id="ux_news_newsletter_heading"
                                    name="ux_news_newsletter_heading"
                                    value="<?php echo esc_attr($settings['newsletter_heading']); ?>"
                                    class="regular-text"
                                >
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                <label for="ux_news_newsletter_text">
                                    Text
                                </label>
                            </th>

                            <td>
                                <textarea
                                    id="ux_news_newsletter_text"
                                    name="ux_news_newsletter_text"
                                    rows="3"
                                    class="large-text"
                                ><?php echo esc_textarea($settings['newsletter_text']); ?></textarea>
                            </td>
                        </tr>

                        <tr>
                            <th scope="row">
                                <label for="ux_news_newsletter_shortcode">
                                    Integration shortcode
                                </label>
                            </th>

                            <td>
                                <input
                                    type="text"
                                    id="ux_news_newsletter_shortcode"
                                    name="ux_news_newsletter_shortcode"
                                    value="<?php echo esc_attr($settings['newsletter_shortcode']); ?>"
                                    class="large-text"
                                    placeholder="[newsletter_form id=&quot;1&quot;]"
                                >

                                <p class="description">
                                    The public newsletter section appears
                                    after a valid form shortcode is configured.
                                </p>
                            </td>
                        </tr>
                    </tbody>
                </table>

                <h4>Taxonomy Setup</h4>

                <table class="widefat striped">
                    <thead>
                        <tr>
                            <th>Type</th>
                            <th>Label</th>
                            <th>Slug</th>
                            <th>Status</th>
                        </tr>
                    </thead>

                    <tbody>
                        <?php foreach ($taxonomy_status as $item) : ?>
                            <tr>
                                <td>
                                    <?php echo esc_html($item['type']); ?>
                                </td>

                                <td>
                                    <?php echo esc_html($item['label']); ?>
                                </td>

                                <td>
                                    <code>
                                        <?php echo esc_html($item['slug']); ?>
                                    </code>
                                </td>

                                <td>
                                    <?php
                                    echo $item['exists']
                                        ? 'Configured'
                                        : 'Missing in WordPress';
                                    ?>
                                </td>
                            </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>

                <?php
                submit_button(
                    'Save News Settings',
                    'primary large',
                    'ux_news_save_settings'
                );
                ?>
            </form>
        </div>

        <?php
    }

    private function ux_news_render_admin_media_field(
        $base_name,
        $attachment_id,
        $url,
        $type
    ) {
        $preview_url = '';

        if ($attachment_id && $type === 'image') {
            $preview_url = wp_get_attachment_image_url(
                $attachment_id,
                'medium'
            );
        } elseif ($type === 'image' && $url) {
            $preview_url = $url;
        }
        ?>

        <div
            data-ux-news-admin-media-field
            data-ux-news-admin-media-type="<?php echo esc_attr($type); ?>"
        >
            <input
                type="hidden"
                class="ux-news-admin-media-id"
                name="<?php echo esc_attr($base_name); ?>_id"
                value="<?php echo esc_attr($attachment_id); ?>"
            >

            <input
                type="url"
                class="regular-text ux-news-admin-media-url"
                name="<?php echo esc_attr($base_name); ?>_url"
                value="<?php echo esc_url($url); ?>"
                placeholder="https://"
            >

            <button
                type="button"
                class="button ux-news-admin-media-select"
            >
                <?php
                echo $type === 'image'
                    ? esc_html__('Choose Image', 'ux-booster')
                    : esc_html__('Choose File', 'ux-booster');
                ?>
            </button>

            <button
                type="button"
                class="button ux-news-admin-media-clear"
            >
                <?php esc_html_e('Clear', 'ux-booster'); ?>
            </button>

            <?php if ($type === 'image') : ?>
                <div class="ux-news-admin-media-preview">
                    <?php if ($preview_url) : ?>
                        <img
                            src="<?php echo esc_url($preview_url); ?>"
                            alt=""
                        >
                    <?php endif; ?>
                </div>
            <?php endif; ?>
        </div>

        <?php
    }

    private function ux_news_maybe_save_settings()
    {
        if (!isset($_POST['ux_news_save_settings'])) {
            return;
        }

        if (
            !isset($_POST['ux_news_settings_nonce'])
            || !wp_verify_nonce(
                sanitize_text_field(
                    wp_unslash($_POST['ux_news_settings_nonce'])
                ),
                'ux_news_save_settings'
            )
        ) {
            echo '<div class="notice notice-error"><p>'
                . 'News settings could not be saved. '
                . 'Please refresh and try again.'
                . '</p></div>';

            return;
        }

        if (!current_user_can('manage_options')) {
            return;
        }

        update_option(
            'ux_news_hero_eyebrow',
            sanitize_text_field(
                wp_unslash(
                    $_POST['ux_news_hero_eyebrow'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_hero_heading',
            sanitize_textarea_field(
                wp_unslash(
                    $_POST['ux_news_hero_heading'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_hero_intro',
            sanitize_textarea_field(
                wp_unslash(
                    $_POST['ux_news_hero_intro'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_hero_image_id',
            absint(
                $_POST['ux_news_hero_image_id'] ?? 0
            )
        );

        update_option(
            'ux_news_hero_image_url',
            esc_url_raw(
                wp_unslash(
                    $_POST['ux_news_hero_image_url'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_featured_post_id',
            absint(
                $_POST['ux_news_featured_post_id'] ?? 0
            )
        );

        update_option(
            'ux_news_latest_count',
            min(
                24,
                max(
                    1,
                    absint(
                        $_POST['ux_news_latest_count'] ?? 8
                    )
                )
            )
        );

        update_option(
            'ux_news_load_more_label',
            sanitize_text_field(
                wp_unslash(
                    $_POST['ux_news_load_more_label']
                        ?? 'Load More News'
                )
            )
        );

        update_option(
            'ux_news_report_title',
            sanitize_text_field(
                wp_unslash(
                    $_POST['ux_news_report_title'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_report_year',
            sanitize_text_field(
                wp_unslash(
                    $_POST['ux_news_report_year'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_report_description',
            sanitize_textarea_field(
                wp_unslash(
                    $_POST['ux_news_report_description'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_report_cover_image_id',
            absint(
                $_POST['ux_news_report_cover_image_id'] ?? 0
            )
        );

        update_option(
            'ux_news_report_cover_image_url',
            esc_url_raw(
                wp_unslash(
                    $_POST['ux_news_report_cover_image_url'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_report_pdf_id',
            absint(
                $_POST['ux_news_report_pdf_id'] ?? 0
            )
        );

        update_option(
            'ux_news_report_pdf_url',
            esc_url_raw(
                wp_unslash(
                    $_POST['ux_news_report_pdf_url'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_report_highlights',
            sanitize_textarea_field(
                wp_unslash(
                    $_POST['ux_news_report_highlights'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_newsletter_heading',
            sanitize_text_field(
                wp_unslash(
                    $_POST['ux_news_newsletter_heading'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_newsletter_text',
            sanitize_textarea_field(
                wp_unslash(
                    $_POST['ux_news_newsletter_text'] ?? ''
                )
            )
        );

        update_option(
            'ux_news_newsletter_shortcode',
            sanitize_text_field(
                wp_unslash(
                    $_POST['ux_news_newsletter_shortcode'] ?? ''
                )
            )
        );

        echo '<div class="notice notice-success is-dismissible"><p>'
            . 'News settings saved.'
            . '</p></div>';
    }

    public function ux_news_add_featured_meta_box()
    {
        add_meta_box(
            'ux_news_featured_news_meta_box',
            __('AORO Featured News', 'ux-booster'),
            array($this, 'ux_news_render_featured_meta_box'),
            'post',
            'side',
            'high'
        );
    }

    public function ux_news_render_featured_meta_box($post)
    {
        wp_nonce_field(
            'ux_news_save_featured_meta',
            'ux_news_featured_meta_nonce'
        );

        $is_featured = get_post_meta(
            $post->ID,
            self::UX_NEWS_FEATURED_META,
            true
        ) === '1';
        ?>

        <p>
            <label>
                <input
                    type="checkbox"
                    name="ux_news_featured_post"
                    value="1"
                    <?php checked($is_featured); ?>
                >

                <?php
                esc_html_e(
                    'Feature this post on the AORO News page',
                    'ux-booster'
                );
                ?>
            </label>
        </p>

        <?php
    }

    public function ux_news_save_featured_meta(
        $post_id,
        $post
    ) {
        if (
            !($post instanceof WP_Post)
            || $post->post_type !== 'post'
        ) {
            return;
        }

        if (
            defined('DOING_AUTOSAVE')
            && DOING_AUTOSAVE
        ) {
            return;
        }

        if (wp_is_post_revision($post_id)) {
            return;
        }

        if (
            !isset($_POST['ux_news_featured_meta_nonce'])
            || !wp_verify_nonce(
                sanitize_text_field(
                    wp_unslash(
                        $_POST['ux_news_featured_meta_nonce']
                    )
                ),
                'ux_news_save_featured_meta'
            )
        ) {
            return;
        }

        if (!current_user_can('edit_post', $post_id)) {
            return;
        }

        if (!empty($_POST['ux_news_featured_post'])) {
            update_post_meta(
                $post_id,
                self::UX_NEWS_FEATURED_META,
                '1'
            );
        } else {
            delete_post_meta(
                $post_id,
                self::UX_NEWS_FEATURED_META
            );
        }
    }

    public function ux_news_render_shortcode($atts = array())
    {
        $settings = $this->ux_news_get_settings();
        $filter_state = $this->ux_news_get_filter_state();

        $featured_post = $this->ux_news_get_featured_post(
            $settings
        );

        $featured_post_id = $featured_post
            ? (int) $featured_post->ID
            : 0;

        $latest_query = $this->ux_news_get_latest_query(
            $featured_post_id,
            $filter_state,
            0,
            $settings['latest_count']
        );

        $category_nav = $this->ux_news_get_category_nav(
            $filter_state
        );

        $topic_nav = $this->ux_news_get_topic_nav(
            $filter_state
        );

        $report_highlights = $this->ux_news_get_report_highlights(
            $settings['report_highlights']
        );

        $newsletter_shortcode = trim(
            (string) $settings['newsletter_shortcode']
        );

        $news_page_url = $this->ux_news_get_page_url();

        $has_more = (
            (int) $latest_query->found_posts
        ) > count($latest_query->posts);

        ob_start();

        include dirname(__FILE__)
            . '/news-page-template.php';

        return ob_get_clean();
    }

    public function ux_news_ajax_load_more()
    {
        check_ajax_referer(
            'ux_news_load_more_nonce',
            'nonce'
        );

        $settings = $this->ux_news_get_settings();

        $offset = max(
            0,
            absint($_POST['offset'] ?? 0)
        );

        $per_page = min(
            24,
            max(
                1,
                absint(
                    $_POST['perPage']
                        ?? $settings['latest_count']
                )
            )
        );

        $featured_post_id = absint(
            $_POST['featuredPost'] ?? 0
        );

        $filter_state = array(
            'search' => sanitize_text_field(
                wp_unslash(
                    $_POST['search'] ?? ''
                )
            ),
            'category' => sanitize_title(
                wp_unslash(
                    $_POST['category'] ?? ''
                )
            ),
            'topic' => sanitize_title(
                wp_unslash(
                    $_POST['topic'] ?? ''
                )
            ),
        );

        $latest_query = $this->ux_news_get_latest_query(
            $featured_post_id,
            $filter_state,
            $offset,
            $per_page
        );

        ob_start();

        foreach ($latest_query->posts as $news_post) {
            echo $this->ux_news_render_article_card(
                $news_post
            );
        }

        $html = ob_get_clean();

        $next_offset = $offset
            + count($latest_query->posts);

        wp_send_json_success(
            array(
                'html' => $html,
                'nextOffset' => $next_offset,
                'hasMore' => (
                    (int) $latest_query->found_posts
                ) > $next_offset,
            )
        );
    }

    private function ux_news_should_enqueue_frontend_assets()
    {
        if (!is_singular()) {
            return false;
        }

        $post = get_post();

        if (!$post instanceof WP_Post) {
            return false;
        }

        return has_shortcode(
            $post->post_content,
            self::UX_NEWS_SHORTCODE
        );
    }

    private function ux_news_get_settings()
    {
        $report_description = 'Our annual report presents key '
            . 'performance data, market intelligence and insights '
            . 'shaping the future of solar energy in the '
            . 'United Kingdom.';

        return array(
            'hero_eyebrow' => get_option(
                'ux_news_hero_eyebrow',
                'NEWS & INSIGHTS'
            ),

            'hero_heading' => get_option(
                'ux_news_hero_heading',
                "Engineering News.\n"
                . "Industry Insights.\n"
                . "Company Updates."
            ),

            'hero_intro' => get_option(
                'ux_news_hero_intro',
                'The latest updates, engineering insights and '
                . 'industry news from AORO Solar and the world '
                . 'of clean energy.'
            ),

            'hero_image_id' => absint(
                get_option(
                    'ux_news_hero_image_id',
                    0
                )
            ),

            'hero_image_url' => get_option(
                'ux_news_hero_image_url',
                ''
            ),

            'featured_post_id' => absint(
                get_option(
                    'ux_news_featured_post_id',
                    0
                )
            ),

            'latest_count' => min(
                24,
                max(
                    1,
                    absint(
                        get_option(
                            'ux_news_latest_count',
                            8
                        )
                    )
                )
            ),

            'load_more_label' => get_option(
                'ux_news_load_more_label',
                'Load More News'
            ),

            'report_title' => get_option(
                'ux_news_report_title',
                'AORO Solar Performance Index'
            ),

            'report_year' => get_option(
                'ux_news_report_year',
                '2026'
            ),

            'report_description' => get_option(
                'ux_news_report_description',
                $report_description
            ),

            'report_cover_image_id' => absint(
                get_option(
                    'ux_news_report_cover_image_id',
                    0
                )
            ),

            'report_cover_image_url' => get_option(
                'ux_news_report_cover_image_url',
                ''
            ),

            'report_pdf_id' => absint(
                get_option(
                    'ux_news_report_pdf_id',
                    0
                )
            ),

            'report_pdf_url' => get_option(
                'ux_news_report_pdf_url',
                ''
            ),

            'report_highlights' => get_option(
                'ux_news_report_highlights',
                "Market Overview\n"
                . "System Performance\n"
                . "Homeowner Savings\n"
                . "Industry Insights\n"
                . "Future Outlook"
            ),

            'newsletter_heading' => get_option(
                'ux_news_newsletter_heading',
                'Stay Updated'
            ),

            'newsletter_text' => get_option(
                'ux_news_newsletter_text',
                'Subscribe to receive the latest AORO news, '
                . 'engineering insights and clean-energy updates.'
            ),

            'newsletter_shortcode' => get_option(
                'ux_news_newsletter_shortcode',
                ''
            ),
        );
    }

    private function ux_news_get_filter_state()
    {
        return array(
            'search' => isset($_GET['ux_news_search'])
                ? sanitize_text_field(
                    wp_unslash(
                        $_GET['ux_news_search']
                    )
                )
                : '',

            'category' => isset($_GET['ux_news_category'])
                ? sanitize_title(
                    wp_unslash(
                        $_GET['ux_news_category']
                    )
                )
                : '',

            'topic' => isset($_GET['ux_news_topic'])
                ? sanitize_title(
                    wp_unslash(
                        $_GET['ux_news_topic']
                    )
                )
                : '',
        );
    }

    private function ux_news_get_featured_post($settings)
    {
        $manual_post_id = absint(
            $settings['featured_post_id']
        );

        if ($manual_post_id) {
            $manual_post = get_post($manual_post_id);

            if (
                $manual_post instanceof WP_Post
                && $manual_post->post_type === 'post'
                && $manual_post->post_status === 'publish'
            ) {
                return $manual_post;
            }
        }

        $featured_query = new WP_Query(
            array(
                'post_type' => 'post',
                'post_status' => 'publish',
                'posts_per_page' => 1,
                'meta_key' => self::UX_NEWS_FEATURED_META,
                'meta_value' => '1',
                'orderby' => 'date',
                'order' => 'DESC',
                'ignore_sticky_posts' => true,
                'no_found_rows' => true,
            )
        );

        if (!empty($featured_query->posts[0])) {
            return $featured_query->posts[0];
        }

        $latest_query = new WP_Query(
            array(
                'post_type' => 'post',
                'post_status' => 'publish',
                'posts_per_page' => 1,
                'orderby' => 'date',
                'order' => 'DESC',
                'ignore_sticky_posts' => true,
                'no_found_rows' => true,
            )
        );

        return !empty($latest_query->posts[0])
            ? $latest_query->posts[0]
            : null;
    }

    private function ux_news_get_latest_query(
        $featured_post_id,
        $filter_state,
        $offset,
        $per_page
    ) {
        $args = array(
            'post_type' => 'post',
            'post_status' => 'publish',
            'posts_per_page' => $per_page,
            'offset' => $offset,
            'orderby' => 'date',
            'order' => 'DESC',
            'ignore_sticky_posts' => true,
            'post__not_in' => $featured_post_id
                ? array($featured_post_id)
                : array(),
        );

        if (!empty($filter_state['search'])) {
            $args['s'] = $filter_state['search'];
        }

        $tax_query = array();

        if (!empty($filter_state['category'])) {
            $tax_query[] = array(
                'taxonomy' => 'category',
                'field' => 'slug',
                'terms' => sanitize_title(
                    $filter_state['category']
                ),
            );
        }

        if (!empty($filter_state['topic'])) {
            $tax_query[] = array(
                'taxonomy' => 'post_tag',
                'field' => 'slug',
                'terms' => sanitize_title(
                    $filter_state['topic']
                ),
            );
        }

        if (!empty($tax_query)) {
            if (count($tax_query) > 1) {
                $tax_query['relation'] = 'AND';
            }

            $args['tax_query'] = $tax_query;
        }

        return new WP_Query($args);
    }

    private function ux_news_get_category_nav(
        $filter_state
    ) {
        $items = array();

        foreach (
            $this->ux_news_category_labels
            as $label => $config
        ) {
            $slug = $config['slug'];
            $term = $this->ux_news_find_term(
                $label,
                $slug,
                'category'
            );

            $items[] = array(
                'label' => $label,
                'slug' => $slug,
                'icon' => $config['icon'],
                'term' => $term,
                'url' => $this->ux_news_build_filter_url(
                    $slug,
                    '',
                    $filter_state['search']
                ),
                'active' => (
                    $filter_state['category'] === $slug
                ),
            );
        }

        return $items;
    }

    private function ux_news_get_topic_nav(
        $filter_state
    ) {
        $items = array();

        foreach (
            $this->ux_news_topic_labels
            as $label => $config
        ) {
            $slug = $config['slug'];

            $term = $this->ux_news_find_term(
                $label,
                $slug,
                'post_tag'
            );

            $items[] = array(
                'label' => $label,
                'slug' => $slug,
                'icon' => $config['icon'],
                'term' => $term,
                'url' => $this->ux_news_build_filter_url(
                    '',
                    $slug,
                    $filter_state['search']
                ),
                'active' => (
                    $filter_state['topic'] === $slug
                ),
            );
        }

        return $items;
    }

    private function ux_news_get_taxonomy_setup_status()
    {
        $items = array();

        foreach (
            $this->ux_news_category_labels
            as $label => $config
        ) {
            $items[] = array(
                'type' => 'Category',
                'label' => $label,
                'slug' => $config['slug'],
                'exists' => (bool) $this->ux_news_find_term(
                    $label,
                    $config['slug'],
                    'category'
                ),
            );
        }

        foreach (
            $this->ux_news_topic_labels
            as $label => $config
        ) {
            $items[] = array(
                'type' => 'Tag',
                'label' => $label,
                'slug' => $config['slug'],
                'exists' => (bool) $this->ux_news_find_term(
                    $label,
                    $config['slug'],
                    'post_tag'
                ),
            );
        }

        return $items;
    }

    private function ux_news_find_term(
        $label,
        $slug,
        $taxonomy
    ) {
        $term = get_term_by(
            'slug',
            sanitize_title($slug),
            $taxonomy
        );

        if ($term instanceof WP_Term) {
            return $term;
        }

        $term = get_term_by(
            'name',
            $label,
            $taxonomy
        );

        return $term instanceof WP_Term
            ? $term
            : null;
    }

    private function ux_news_build_filter_url(
        $category_slug = '',
        $topic_slug = '',
        $search = ''
    ) {
        $args = array();

        if ($category_slug !== '') {
            $args['ux_news_category'] = sanitize_title(
                $category_slug
            );
        }

        if ($topic_slug !== '') {
            $args['ux_news_topic'] = sanitize_title(
                $topic_slug
            );
        }

        if ($search !== '') {
            $args['ux_news_search'] = sanitize_text_field(
                $search
            );
        }

        if (empty($args)) {
            return $this->ux_news_get_page_url();
        }

        return add_query_arg(
            $args,
            $this->ux_news_get_page_url()
        );
    }

    private function ux_news_get_page_url()
    {
        $post = get_post();

        if ($post instanceof WP_Post) {
            return get_permalink($post);
        }

        return home_url('/news/');
    }

    private function ux_news_get_report_highlights(
        $value
    ) {
        $lines = preg_split(
            '/\r\n|\r|\n/',
            (string) $value
        );

        $items = array();

        foreach ($lines as $line) {
            $line = trim($line);

            if ($line !== '') {
                $items[] = $line;
            }
        }

        return $items;
    }

    private function ux_news_get_report_pdf_url(
        $settings
    ) {
        if (!empty($settings['report_pdf_id'])) {
            $url = wp_get_attachment_url(
                $settings['report_pdf_id']
            );

            if ($url) {
                return $url;
            }
        }

        return !empty($settings['report_pdf_url'])
            ? $settings['report_pdf_url']
            : '';
    }

    private function ux_news_get_default_hero_url()
    {
        $candidates = array(
            'news-hero.jpg',
            'news-hero-bg.jpg',
            'spuk-hero-bg.jpg',
            'fsuk-hero.jpg',
            'csuk-hero.jpg',
            'sysp-hero.jpg',
        );

        foreach ($candidates as $candidate) {
            $path = UX_BOOSTER_PATH
                . 'assets/images/'
                . $candidate;

            if (file_exists($path)) {
                return UX_BOOSTER_URL
                    . 'assets/images/'
                    . $candidate;
            }
        }

        return '';
    }

    private function ux_news_render_image(
        $attachment_id,
        $url,
        $size,
        $class,
        $alt,
        $loading = 'lazy',
        $fetchpriority = ''
    ) {
        $attrs = array(
            'class' => $class,
            'loading' => $loading,
            'decoding' => 'async',
            'alt' => $alt,
        );

        if ($fetchpriority) {
            $attrs['fetchpriority'] = $fetchpriority;
        }

        if ($attachment_id) {
            $image = wp_get_attachment_image(
                $attachment_id,
                $size,
                false,
                $attrs
            );

            if ($image) {
                return $image;
            }
        }

        if ($url) {
            return sprintf(
                '<img src="%1$s" alt="%2$s" '
                . 'class="%3$s" loading="%4$s" '
                . 'decoding="async"%5$s>',
                esc_url($url),
                esc_attr($alt),
                esc_attr($class),
                esc_attr($loading),
                $fetchpriority
                    ? ' fetchpriority="'
                        . esc_attr($fetchpriority)
                        . '"'
                    : ''
            );
        }

        return '';
    }

    private function ux_news_get_configured_hero_image_url()
    {
        $hero_image_id = absint(
            get_option(
                'ux_news_hero_image_id',
                0
            )
        );

        if ($hero_image_id) {
            $attachment_url = wp_get_attachment_image_url(
                $hero_image_id,
                'full'
            );

            if ($attachment_url) {
                return $attachment_url;
            }
        }

        $hero_image_url = get_option(
            'ux_news_hero_image_url',
            ''
        );

        if ($hero_image_url) {
            return $hero_image_url;
        }

        return $this->ux_news_get_default_hero_url();
    }

    private function ux_news_render_post_image(
        $post_id,
        $class,
        $size = 'medium_large',
        $loading = 'lazy'
    ) {
        $thumbnail_id = get_post_thumbnail_id(
            $post_id
        );

        if ($thumbnail_id) {
            $image = wp_get_attachment_image(
                $thumbnail_id,
                $size,
                false,
                array(
                    'class' => $class,
                    'loading' => $loading,
                    'decoding' => 'async',
                    'alt' => get_the_title($post_id),
                )
            );

            if ($image) {
                return $image;
            }
        }

        $fallback_url = $this
            ->ux_news_get_configured_hero_image_url();

        if ($fallback_url) {
            return sprintf(
                '<img src="%1$s" alt="%2$s" '
                . 'class="%3$s" loading="%4$s" '
                . 'decoding="async">',
                esc_url($fallback_url),
                esc_attr(get_the_title($post_id)),
                esc_attr($class),
                esc_attr($loading)
            );
        }

        return '';
    }

    private function ux_news_get_primary_category(
        $post_id
    ) {
        /**
         * Respect Rank Math's selected primary category when available.
         */
        $primary_category_id = absint(
            get_post_meta(
                $post_id,
                'rank_math_primary_category',
                true
            )
        );

        if ($primary_category_id) {
            $primary_category = get_term(
                $primary_category_id,
                'category'
            );

            if (
                $primary_category instanceof WP_Term
                && !is_wp_error($primary_category)
            ) {
                return $primary_category;
            }
        }

        $categories = get_the_category($post_id);

        if (
            !empty($categories[0])
            && $categories[0] instanceof WP_Term
        ) {
            return $categories[0];
        }

        return null;
    }

    private function ux_news_get_reading_time(
        $post_id
    ) {
        $content = get_post_field(
            'post_content',
            $post_id
        );

        $plain_content = wp_strip_all_tags(
            strip_shortcodes((string) $content)
        );

        $word_count = str_word_count(
            html_entity_decode(
                $plain_content,
                ENT_QUOTES,
                get_bloginfo('charset')
            )
        );

        return max(
            1,
            (int) ceil($word_count / 200)
        );
    }

    private function ux_news_get_excerpt(
        $post_id,
        $words = 22
    ) {
        if (has_excerpt($post_id)) {
            $excerpt = get_the_excerpt($post_id);
        } else {
            $excerpt = get_post_field(
                'post_content',
                $post_id
            );

            $excerpt = strip_shortcodes(
                (string) $excerpt
            );

            $excerpt = wp_strip_all_tags(
                $excerpt
            );
        }

        return wp_trim_words(
            $excerpt,
            absint($words),
            '...'
        );
    }

    private function ux_news_render_article_meta(
        $post_id
    ) {
        $date = get_the_date(
            'j M Y',
            $post_id
        );

        $read_time = $this->ux_news_get_reading_time(
            $post_id
        );

        return '<div class="ux-news-article-meta">'
            . '<span class="ux-news-meta-item">'
            . $this->ux_news_get_icon('calendar')
            . esc_html($date)
            . '</span>'
            . '<span class="ux-news-meta-item">'
            . $this->ux_news_get_icon('clock')
            . esc_html($read_time . ' min read')
            . '</span>'
            . '</div>';
    }

    private function ux_news_render_article_card($post)
    {
        if (!$post instanceof WP_Post) {
            return '';
        }

        $post_id = (int) $post->ID;

        $category = $this->ux_news_get_primary_category(
            $post_id
        );

        $category_label = $category
            ? $category->name
            : 'News';

        $permalink = get_permalink($post_id);
        $title = get_the_title($post_id);

        ob_start();
        ?>

        <article class="ux-news-card">
            <a
                class="ux-news-card-link"
                href="<?php echo esc_url($permalink); ?>"
                aria-label="<?php echo esc_attr(
                    sprintf(
                        'Read article: %s',
                        $title
                    )
                ); ?>"
            >
                <span class="ux-news-card-media">
                    <?php
                    echo $this->ux_news_render_post_image(
                        $post_id,
                        'ux-news-card-image',
                        'medium_large',
                        'lazy'
                    );
                    ?>
                </span>

                <span class="ux-news-card-body">
                    <span class="ux-news-card-category">
                        <?php echo esc_html($category_label); ?>
                    </span>

                    <h3 class="ux-news-card-title">
                        <?php echo esc_html($title); ?>
                    </h3>

                    <span class="ux-news-card-footer">
                        <?php
                        echo $this->ux_news_render_article_meta(
                            $post_id
                        );
                        ?>

                        <span
                            class="ux-news-card-arrow"
                            aria-hidden="true"
                        >
                            <?php
                            echo $this->ux_news_get_icon(
                                'arrow'
                            );
                            ?>
                        </span>
                    </span>
                </span>
            </a>
        </article>

        <?php

        return ob_get_clean();
    }

    private function ux_news_get_icon($name)
    {
        $icons = array(
            'search' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<circle cx="11" cy="11" r="7" '
                . 'stroke="currentColor" stroke-width="1.8"/>'
                . '<path d="m16.5 16.5 4 4" '
                . 'stroke="currentColor" stroke-width="1.8" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'arrow' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M5 12h14M13 6l6 6-6 6" '
                . 'stroke="currentColor" stroke-width="1.8" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '</svg>',

            'calendar' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<rect x="4" y="5" width="16" height="15" rx="2" '
                . 'stroke="currentColor" stroke-width="1.6"/>'
                . '<path d="M8 3v4M16 3v4M4 10h16" '
                . 'stroke="currentColor" stroke-width="1.6" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'clock' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<circle cx="12" cy="12" r="8" '
                . 'stroke="currentColor" stroke-width="1.6"/>'
                . '<path d="M12 8v4l3 2" '
                . 'stroke="currentColor" stroke-width="1.6" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '</svg>',

            'download' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M12 4v10M8 10l4 4 4-4M5 20h14" '
                . 'stroke="currentColor" stroke-width="1.8" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '</svg>',

            'grid' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<rect x="4" y="4" width="6" height="6" rx="1.5" '
                . 'stroke="currentColor" stroke-width="1.6"/>'
                . '<rect x="14" y="4" width="6" height="6" rx="1.5" '
                . 'stroke="currentColor" stroke-width="1.6"/>'
                . '<rect x="4" y="14" width="6" height="6" rx="1.5" '
                . 'stroke="currentColor" stroke-width="1.6"/>'
                . '<rect x="14" y="14" width="6" height="6" rx="1.5" '
                . 'stroke="currentColor" stroke-width="1.6"/>'
                . '</svg>',

            'category' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M7 5h10l2 5-7 9-7-9 2-5Z" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linejoin="round"/>'
                . '<path d="M9 10h6" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'building' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M4 21h16M6 21V5l7-2v18M13 8h5v13" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '<path d="M9 7h1M9 11h1M9 15h1M16 11h1M16 15h1" '
                . 'stroke="currentColor" stroke-width="1.8" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'chart' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M4 20V11M9 20V7M14 20V13M19 20V4M2 20h20" '
                . 'stroke="currentColor" stroke-width="1.6" '
                . 'stroke-linecap="round"/>'
                . '<path d="m4 8 5-3 5 4 5-7" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '</svg>',

            'gear' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<circle cx="12" cy="12" r="3" '
                . 'stroke="currentColor" stroke-width="1.6"/>'
                . '<path d="M12 2v3M12 19v3M4.93 4.93l2.12 2.12'
                . 'M16.95 16.95l2.12 2.12M2 12h3M19 12h3'
                . 'M4.93 19.07l2.12-2.12M16.95 7.05l2.12-2.12" '
                . 'stroke="currentColor" stroke-width="1.6" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'box' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="m4 7 8-4 8 4-8 4-8-4Z'
                . 'M4 7v10l8 4 8-4V7M12 11v10" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '</svg>',

            'people' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<circle cx="9" cy="8" r="3" '
                . 'stroke="currentColor" stroke-width="1.5"/>'
                . '<circle cx="17" cy="9" r="2.5" '
                . 'stroke="currentColor" stroke-width="1.5"/>'
                . '<path d="M3 20c0-4 2-6 6-6s6 2 6 6'
                . 'M14 15c3.5 0 5 1.7 5 5" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'press' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<rect x="4" y="4" width="16" height="16" rx="2" '
                . 'stroke="currentColor" stroke-width="1.5"/>'
                . '<path d="M8 8h8M8 12h8M8 16h5" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'sun' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<circle cx="12" cy="12" r="4" '
                . 'stroke="currentColor" stroke-width="1.6"/>'
                . '<path d="M12 2v3M12 19v3M4.9 4.9 7 7'
                . 'M17 17l2.1 2.1M2 12h3M19 12h3'
                . 'M4.9 19.1 7 17M17 7l2.1-2.1" '
                . 'stroke="currentColor" stroke-width="1.6" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'battery' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<rect x="5" y="6" width="13" height="13" rx="2" '
                . 'stroke="currentColor" stroke-width="1.5"/>'
                . '<path d="M9 3h5M19 10h2v5h-2" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round"/>'
                . '<path d="m12 8-3 5h3l-1 4 4-6h-3l2-3Z" '
                . 'stroke="currentColor" stroke-width="1.4" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '</svg>',

            'heat' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M7 20c-2-2-2-4 0-6s2-4 0-6'
                . 'M12 20c-2-2-2-4 0-6s2-4 0-6'
                . 'M17 20c-2-2-2-4 0-6s2-4 0-6" '
                . 'stroke="currentColor" stroke-width="1.6" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'home' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="m3 11 9-8 9 8M6 10v10h12V10'
                . 'M10 20v-6h4v6" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '</svg>',

            'developer' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M3 20h18M5 20V8h6v12'
                . 'M13 20V4h6v16" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '<path d="M7 11h2M7 14h2M15 7h2'
                . 'M15 10h2M15 13h2M15 16h2" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'ev' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M6 17h12l2-6-3-4H7l-3 4 2 6Z'
                . 'M8 17v2M16 17v2M7 12h10" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '<path d="M18 5h3M20 3v4" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round"/>'
                . '</svg>',

            'finance' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M4 20V12M9 20V8M14 20v-5M19 20V5'
                . 'M2 20h20" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round"/>'
                . '<path d="m4 9 5-4 5 5 5-7" '
                . 'stroke="currentColor" stroke-width="1.5" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '</svg>',

            'mail' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<rect x="4" y="6" width="16" height="12" rx="2" '
                . 'stroke="currentColor" stroke-width="1.6"/>'
                . '<path d="m5 8 7 5 7-5" '
                . 'stroke="currentColor" stroke-width="1.6" '
                . 'stroke-linecap="round" '
                . 'stroke-linejoin="round"/>'
                . '</svg>',

            'topic' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<path d="M5 8h14M5 12h10M5 16h7" '
                . 'stroke="currentColor" stroke-width="1.7" '
                . 'stroke-linecap="round"/>'
                . '<rect x="3" y="4" width="18" height="16" rx="3" '
                . 'stroke="currentColor" stroke-width="1.5"/>'
                . '</svg>',

            'report' =>
                '<svg class="ux-news-icon" viewBox="0 0 24 24" '
                . 'fill="none" aria-hidden="true">'
                . '<rect x="5" y="4" width="14" height="16" rx="2" '
                . 'stroke="currentColor" stroke-width="1.5"/>'
                . '<path d="M9 15V11M12 15V8M15 15v-3" '
                . 'stroke="currentColor" stroke-width="1.7" '
                . 'stroke-linecap="round"/>'
                . '</svg>',
        );

        return isset($icons[$name])
            ? $icons[$name]
            : '';
            
    }
}
