/* ==========================================================================
   Obgin FK-UMI — inner pages (archives, singles, search)
   Loaded alongside theme.css; tokens come from there.
   ========================================================================== */

.wrap--narrow { width: min(100% - 2.4rem, 860px); }

/* ------------------------------------------------------------- page hero */
.page-hero { position: relative; padding-block: clamp(2rem, 5vw, 3.4rem); color: #fff; overflow: hidden; }
.page-hero__bg {
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(700px 380px at 88% -30%, rgb(18 165 150 / .35), transparent 62%),
    linear-gradient(140deg, var(--navy-900), var(--navy-700));
}
.page-hero__title { font-size: var(--step-3); margin-top: .6rem; color: #fff; }
.page-hero__intro { margin-top: .55rem; color: rgb(255 255 255 / .82); max-width: 70ch; }

.crumbs ol { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: .3rem .55rem; font-size: var(--step--1); }
.crumbs li + li::before { content: "/"; margin-inline-end: .55rem; opacity: .5; }
.crumbs a { color: rgb(255 255 255 / .8); text-decoration: none; }
.crumbs a:hover { color: #fff; text-decoration: underline; }
.crumbs span { color: rgb(255 255 255 / .95); }
/* Lecturer titles carry six post-nominals; the trail has to break inside a
   word rather than push the banner off a phone screen. */
.crumbs li { min-width: 0; overflow-wrap: anywhere; }

/* ------------------------------------------------------- profile masthead */

/* The generic banner spent a whole navy band on one line of title while the
   portrait, the name again, and the figures worth reading sat in a card below
   it. Here the band is the profile header, and the column beneath it is free
   to run full width — which is what a list of twenty-seven paper titles wants. */

.phero { position: relative; padding-block: clamp(1.8rem, 4vw, 3rem); color: #fff; overflow: hidden; }
.phero__bg {
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(760px 420px at 82% -25%, rgb(18 165 150 / .38), transparent 62%),
    linear-gradient(140deg, var(--navy-900), var(--navy-700));
}

.phero__grid {
  display: grid; grid-template-columns: 172px minmax(0, 1fr);
  gap: clamp(1.2rem, 3vw, 2.2rem);
  align-items: center; margin-top: 1rem;
}
.phero__portrait {
  width: 172px; aspect-ratio: 4 / 5;
  border-radius: var(--radius-lg); overflow: hidden;
  /* A ring rather than a border: the studio backdrops vary, and a soft rim
     keeps every portrait sitting on the navy the same way. */
  box-shadow: 0 0 0 3px rgb(255 255 255 / .18), var(--shadow-lg);
  background: var(--navy-800);
}
.phero__portrait img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }

/* No `justify-items: start` here: it sizes every child to max-content, and a
   name like "Dr. dr. Nasrudin, Sp.OG, Subsp. Obginsos., MARS., M.Sc., FISQua.,
   AIFO-K" then runs straight off a phone screen instead of wrapping. The rows
   below are flex containers that already pack to the start. */
.phero__body { min-width: 0; display: grid; gap: .85rem; }
.phero__name {
  font-size: clamp(1.45rem, 1.1rem + 1.5vw, 2.4rem);
  line-height: 1.18; color: #fff; text-wrap: balance; margin: 0;
  overflow-wrap: break-word;
}
.phero__role {
  display: flex; flex-wrap: wrap; align-items: center; gap: .45rem .7rem;
  color: rgb(255 255 255 / .82); font-size: var(--step-0); margin: 0;
}
.phero__division {
  padding: .18rem .7rem; border-radius: 999px;
  background: rgb(255 255 255 / .14); color: #fff; font-weight: 650;
  font-size: var(--step--1);
}

.phero__figures {
  display: flex; flex-wrap: wrap; gap: .4rem 2.2rem; margin: .25rem 0 0;
}
.phero__figure { display: grid; }
.phero__figures dd {
  margin: 0; font-size: clamp(1.5rem, 1.2rem + 1vw, 2.1rem); line-height: 1.05;
  font-weight: 700; color: #fff; font-variant-numeric: tabular-nums;
}
.phero__figures dt {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .09em;
  color: rgb(255 255 255 / .68); font-weight: 700; margin-top: .2rem;
}
.phero__figures dt small {
  display: block; text-transform: none; letter-spacing: 0;
  font-size: .72rem; font-weight: 500; color: rgb(255 255 255 / .55);
}

.phero__links { list-style: none; padding: 0; margin: .35rem 0 0; display: flex; flex-wrap: wrap; gap: .5rem; }
.phero__links a {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .42rem .9rem; border-radius: 999px;
  border: 1px solid rgb(255 255 255 / .28);
  background: rgb(255 255 255 / .1); color: #fff;
  font-size: var(--step--1); font-weight: 650; text-decoration: none;
  transition: background .16s ease, border-color .16s ease;
}
.phero__links a:hover, .phero__links a:focus-visible {
  background: rgb(255 255 255 / .2); border-color: rgb(255 255 255 / .55);
}
.phero__links .ico--ext { width: .8em; height: .8em; opacity: .75; }
@media (prefers-reduced-motion: reduce) { .phero__links a { transition: none; } }

@media (max-width: 700px) {
  .phero__grid { grid-template-columns: minmax(0, 1fr); gap: 1.1rem; }
  .phero__portrait { width: 116px; }
  .phero__figures { gap: .4rem 1.5rem; }
}

/* ------------------------------------------------------------ contact form */

.cform__wrap {
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: clamp(1.6rem, 3vw, 2.2rem);
  border-top: 1px solid var(--line);
}

.cform { display: grid; gap: 1rem; margin-top: 1.2rem; max-width: 46rem; }
/* Two fields to a row where they are short, one where they are not. */
.cform__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1rem; }

.cform .field { display: grid; gap: .35rem; }
.cform .field__label {
  font-size: var(--step--1); font-weight: 650; color: var(--ink-900);
}
.cform .field__label b { color: var(--red-600); font-weight: 700; }

.cform input,
.cform textarea {
  width: 100%; padding: .7rem .9rem;
  font: inherit; font-size: var(--step-0); color: var(--ink-900);
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.cform textarea { resize: vertical; min-height: 8rem; line-height: 1.6; }
.cform input:focus-visible,
.cform textarea:focus-visible {
  outline: none; border-color: var(--accent); box-shadow: var(--ring);
}
@media (prefers-reduced-motion: reduce) { .cform input, .cform textarea { transition: none; } }

.cform__captcha-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.cform__captcha-img {
  flex: none; line-height: 0;
  border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden;
}
.cform__captcha-row input { flex: 1 1 8rem; min-width: 0; max-width: 12rem; }

.cform__refresh {
  flex: none; display: grid; place-items: center;
  width: 2.6rem; height: 2.6rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink-500); cursor: pointer;
}
.cform__refresh:hover { border-color: var(--accent); color: var(--accent); }
.cform__refresh:focus-visible { outline: none; box-shadow: var(--ring); }
.cform__refresh .ico { width: 1.1em; height: 1.1em; }

.cform__foot { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-top: .3rem; }
.cform__note { font-size: var(--step--1); color: var(--ink-500); margin: 0; }

/* The honeypot must be reachable by a bot and invisible to everyone else, so
   it is moved off-screen rather than hidden — `display:none` is the first
   thing a form-filling script learns to skip. */
.hp-field {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* --------------------------------------------------------- message masthead */

/* Same navy band as every other page banner, so a message still reads as part
   of the site — what changes is that it carries the writer. */
.mhero { position: relative; padding-block: clamp(1.8rem, 4vw, 2.8rem); color: #fff; overflow: hidden; }
.mhero__bg {
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(720px 400px at 85% -25%, rgb(18 165 150 / .34), transparent 62%),
    linear-gradient(140deg, var(--navy-900), var(--navy-700));
}

/* The banner and the letter below it share one measure and one left edge, so
   the portrait lines up with the first word of every paragraph. Without it the
   masthead started at the page margin while the centred reading column began
   170px further in, and the two read as separate pages stacked. */
.mhero .crumbs ol,
.mhero__grid { max-width: var(--message-measure); margin-inline: auto; }

.mhero__grid {
  display: grid; grid-template-columns: 150px minmax(0, 1fr);
  gap: clamp(1.1rem, 3vw, 2rem);
  align-items: center; margin-top: 1rem;
}
.mhero__grid--noportrait { grid-template-columns: minmax(0, 1fr); }

.mhero__portrait {
  width: 150px; aspect-ratio: 3 / 4; margin: 0;
  border-radius: var(--radius-lg); overflow: hidden;
  box-shadow: 0 0 0 3px rgb(255 255 255 / .18), var(--shadow-lg);
  background: var(--navy-800);
}
/* These are studio portraits framed head-near-the-top, the same as the
   lecturer photographs; a centred crop takes the forehead. */
.mhero__portrait img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }

.mhero__body { min-width: 0; display: grid; gap: .3rem; }
.mhero__title {
  font-size: clamp(1.5rem, 1.15rem + 1.5vw, 2.4rem);
  line-height: 1.15; color: #fff; margin: 0; text-wrap: balance;
  overflow-wrap: break-word;
}
.mhero__signer {
  margin: .5rem 0 0; font-size: var(--step-1); font-weight: 650; color: #fff;
  line-height: 1.35;
}
.mhero__role {
  margin: 0; font-size: var(--step--1); color: rgb(255 255 255 / .72);
  line-height: 1.45;
}

@media (max-width: 640px) {
  .mhero__grid { grid-template-columns: minmax(0, 1fr); gap: .9rem; }
  .mhero__portrait { width: 104px; }
}

/* A letter is read straight down; a contents rail beside it is scaffolding the
   reader did not ask for. The body keeps the single measured column, and that
   measure is the one the masthead above it uses. */
:root { --message-measure: 860px; }
.pagebody--message .pagebody__grid {
  grid-template-columns: minmax(0, 1fr);
  max-width: var(--message-measure);
}

/* -------------------------------------------------------- lecturer profile */

.lecturer {
  max-width: 1160px; margin-inline: auto;
  padding-block: clamp(1.8rem, 4vw, 3rem);
}

/* Registry number, position, address — kept out of the masthead, which is for
   the headline, but out in the open rather than behind a tab. */
.idlist {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1px; margin: 0;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
}
.idlist__item {
  padding: .85rem 1rem;
  border-inline-start: 1px solid var(--line);
  border-block-start: 1px solid var(--line);
  margin-inline-start: -1px; margin-block-start: -1px;
}
.idlist dt {
  font-size: .68rem; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-500); font-weight: 700; margin-bottom: .25rem;
}
.idlist dd { margin: 0; color: var(--ink-900); font-weight: 600; overflow-wrap: anywhere; }
.idlist dd a { color: var(--brand); }

.lecturer__body { min-width: 0; display: grid; gap: clamp(1.6rem, 3vw, 2.4rem); }
.lecturer__block { min-width: 0; }
.lecturer__heading {
  font-size: var(--step-1); margin-bottom: .9rem;
  padding-bottom: .5rem; border-bottom: 2px solid var(--navy-100);
}

.chips { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: .45rem; }
.chip {
  padding: .35rem .8rem; border-radius: 999px;
  background: var(--navy-50); border: 1px solid var(--navy-100);
  font-size: var(--step--1); font-weight: 600; color: var(--navy-700);
}

/* Education: a dated rail rather than a bulleted list. */
.railway { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; }
.railway__item {
  display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 1rem;
  padding: .85rem 0 .85rem 0; position: relative;
}
.railway__item + .railway__item { border-top: 1px dashed var(--line); }
.railway__year {
  font-variant-numeric: tabular-nums; font-weight: 700; color: var(--accent);
  font-size: var(--step--1); padding-top: .15rem;
}
.railway__body strong { display: block; font-size: var(--step-0); }
.railway__body span { display: block; color: var(--ink-700); font-size: var(--step--1); }
.railway__body small { display: block; color: var(--ink-500); font-size: .78rem; margin-top: .15rem; }

/* Citation figures as tiles, not a spreadsheet. */
.metrics + .metrics { margin-top: 1rem; }
.metrics__source {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-500); font-weight: 700; margin-bottom: .5rem;
}
.metrics__list {
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: .6rem;
}
.metrics__list li {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .8rem .9rem; text-align: center;
}
.metrics__list strong { display: block; font-size: var(--step-2); line-height: 1.1; color: var(--navy-700); font-variant-numeric: tabular-nums; }
.metrics__list span { font-size: .74rem; color: var(--ink-500); }

/* ------------------------------------------------- profile tab strip */

/* Panels only collapse once theme.js has taken over — `[data-ready]` is the
   switch. Until then every section is on the page, which is what a reader with
   no JavaScript, and any crawler that skips it, gets to see. */
.ptabs { display: grid; gap: clamp(1.6rem, 3vw, 2.4rem); }
.ptabs[data-ready] { gap: 1.4rem; }
/* The panel carries the rhythm between its own sections: the gap used to come
   from `.lecturer__body`, whose only child is now the tab set. */
.ptabs__panel { display: grid; gap: clamp(1.6rem, 3vw, 2.4rem); align-content: start; }
.ptabs[data-ready] .ptabs__panel { display: none; }
.ptabs[data-ready] .ptabs__panel.is-active { display: grid; }
.ptabs[data-ready] .ptabs__panel-title { display: none; }

.ptabs__bar {
  display: flex; flex-wrap: wrap; gap: .4rem;
  border-bottom: 1px solid var(--line);
  padding-bottom: .55rem;
}
.ptabs__tab {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .5rem .95rem;
  border: 1px solid transparent; border-radius: 999px;
  background: none; color: var(--ink-500);
  font: inherit; font-size: var(--step--1); font-weight: 650;
  cursor: pointer;
  transition: background .16s ease, color .16s ease;
}
.ptabs__tab:hover { background: var(--surface-2); color: var(--ink-900); }
.ptabs__tab:focus-visible { outline: none; box-shadow: var(--ring); }
.ptabs__tab.is-active { background: var(--navy-700); color: #fff; }
.ptabs__tab.is-active:hover { background: var(--navy-800); color: #fff; }

/* The count is a fact about the tab, so it stays legible on both grounds. */
.ptabs__count {
  min-width: 1.5em; padding: .05rem .4rem;
  border-radius: 999px;
  background: var(--navy-100); color: var(--navy-700);
  font-size: .68rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.ptabs__tab.is-active .ptabs__count { background: rgb(255 255 255 / .22); color: #fff; }

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

.papers__none { color: var(--ink-500); font-size: var(--step--1); margin-top: .6rem; }

/* ------------------------------------------------- research summary row */

/* Chart and figures on one line. The chart is the flexible half — it is the
   part that benefits from every pixel — and the table takes the width its four
   columns need and no more. */
.research {
  display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: clamp(1.2rem, 3vw, 2.4rem);
  /* Centred, not top-aligned: the table is half the chart's height, and hung
     from the top it left an obvious well of white beneath it. */
  align-items: center;
}
.research--single { grid-template-columns: minmax(0, 1fr); align-items: start; }
.research__chart, .research__stats { min-width: 0; }
/* Nine bars do not improve with more room — past about 700px the columns stay
   24px wide by spec and the gaps just grow, so the series reads as spindly
   marks adrift in white. Capping the plot keeps the rhythm tight; the column
   itself may be wider, and the chart sits at its start. */
.research__chart .chart__svg { max-width: 700px; }

/* Below this the table's four columns and the chart's nine years are both
   fighting for the same half. */
@media (max-width: 900px) {
  .research { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------------------------------------ chart */

/* One validated hue, `--navy-500`: it clears the lightness band, the chroma
   floor and 3:1 contrast against the light *and* the dark chart surface, so a
   single series needs no per-theme swap and no legend — the caption names it. */
:root { --chart-ink: var(--navy-500); }

.chart { margin: 0; }
.chart__caption {
  font-size: var(--step--1); color: var(--ink-500);
  margin-bottom: .6rem;
}
.chart__svg { display: block; width: 100%; height: auto; max-width: 640px; overflow: visible; }

.chart__bar { fill: var(--chart-ink); transition: fill .15s ease; }
.chart__col:hover .chart__bar { fill: var(--navy-600); }
[data-theme="dark"] .chart__col:hover .chart__bar { fill: #4a9fd4; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .chart__col:hover .chart__bar { fill: #4a9fd4; }
}
@media (prefers-reduced-motion: reduce) { .chart__bar { transition: none; } }

/* Recessive: hairline, solid, one step off the surface. */
.chart__grid { stroke: var(--line); stroke-width: 1; shape-rendering: crispEdges; }
/* Text wears text tokens, never the data colour. */
.chart__tick { fill: var(--ink-500); font-size: 11px; font-family: var(--font); }
.chart__value { fill: var(--ink-900); font-size: 12px; font-weight: 700; font-family: var(--font); }

.chart__table { margin-top: .9rem; }
.chart__table summary {
  cursor: pointer; font-size: var(--step--1); color: var(--brand);
  font-weight: 650; width: max-content;
}
.chart__table summary:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 4px; }
.chart__table .tablewrap { margin-top: .7rem; }

/* --------------------------------------------------------------- timeline */

/* Dates in their own column so the eye can run down the years, with a rule
   joining them: a chronology is read vertically, not sentence by sentence. */
.prose .timeline {
  list-style: none; padding: 0; margin-block: 1.9em; max-width: none;
  display: grid; gap: 0;
}
.prose .timeline li + li { margin-top: 0; }

.timeline__item {
  display: grid; grid-template-columns: 9.5rem minmax(0, 1fr);
  gap: 0;
  padding-block: .85rem;
}

/* No `white-space: nowrap` here. Each row is its own grid, so the date column
   has to be one fixed width for the dates to line up — and a fixed width plus
   nowrap means a long date ("November 2024") is clipped rather than shown. A
   date that wraps to two lines is untidy; a date missing its year is wrong. */
.timeline__when {
  color: var(--brand); font-weight: 700; font-size: var(--step--1);
  font-variant-numeric: tabular-nums; line-height: 1.5;
  padding-inline-end: 1rem; overflow-wrap: break-word;
}
/* Note for whoever touches this next: the `9.5rem` track above does not hold —
   the column resolves to the width of the longest *short* date, so "November
   2024" wraps to two lines. Forcing it with `min-width` on the span only trades
   the wrap for a clipped year, which is worse: a date missing its year is
   wrong, a date on two lines is merely untidy. Left wrapping on purpose. */

/* The rail and its dot hang off the body column rather than sitting at a
   hand-measured offset from the row. Pinned to a guessed inset they drifted
   the moment the date column resolved narrower than the value I had assumed,
   and every marker landed on top of the first word of its own entry. */
.timeline__what {
  position: relative; min-width: 0;
  padding-inline-start: 1.4rem;
  border-inline-start: 1px solid var(--line);
  color: var(--ink-700); line-height: 1.6;
}
.timeline__what::before {
  content: ""; position: absolute;
  inset-inline-start: -4.5px; top: .55em;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--surface);
}
/* The rail runs unbroken between rows, so the years read as points on one
   line; the first and last stop at their own dot rather than in mid-air. */
.timeline__item:first-child .timeline__what { border-image: linear-gradient(var(--surface) .55em, var(--line) .55em) 1; }
.timeline__item:last-child .timeline__what { border-image: linear-gradient(var(--line) 1.1em, var(--surface) 1.1em) 1; }

@media (max-width: 560px) {
  .timeline__item { grid-template-columns: minmax(0, 1fr); padding-block: .7rem; }
  .timeline__when { padding-inline-end: 0; margin-bottom: .15rem; }
  .timeline__what { padding-inline-start: 0; border-inline-start: 0; }
  .timeline__what::before { content: none; }
  .timeline__item + .timeline__item { border-top: 1px dashed var(--line); }
}

/* -------------------------------------------------------------------- SDG */

/* The goal's colour is the UN's own and belongs to the goal, so it rides a
   small marker beside the label rather than behind the text: seventeen fixed
   hues cannot all clear contrast as a background, and the name reads in
   ordinary ink either way. */
.sdg__lead { color: var(--ink-500); font-size: var(--step--1); margin-bottom: .9rem; max-width: 62ch; }
.sdg { list-style: none; padding: 0; margin: 0; display: grid; gap: .1rem; }
.sdg__item {
  display: flex; align-items: center; gap: .8rem;
  padding: .6rem 0;
}
.sdg__item + .sdg__item { border-top: 1px dashed var(--line); }
.sdg__mark {
  flex: none; display: grid; place-items: center;
  width: 2rem; height: 2rem; border-radius: var(--radius-sm);
  background: var(--sdg, var(--ink-300)); color: #fff;
  font-size: .8rem; font-weight: 800; font-variant-numeric: tabular-nums;
}
.sdg__body { min-width: 0; display: grid; }
.sdg__body strong { font-size: var(--step-0); color: var(--ink-900); font-weight: 650; line-height: 1.35; }
.sdg__body small { font-size: var(--step--1); color: var(--ink-500); }

.paper__sdg {
  padding: .1rem .5rem; border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--ink-700); font-size: .7rem; font-weight: 700;
  display: inline-flex; align-items: center; gap: .32rem;
}
.paper__sdg::before {
  content: ""; width: .55em; height: .55em; border-radius: 50%;
  background: var(--sdg, var(--ink-300));
}

/* The seventeen goal colours, quoted from the UN's own palette. Kept in the
   stylesheet because the CSP carries a nonce and no `unsafe-inline`, so an
   inline style attribute on the marker would simply be refused. */
[data-sdg="1"]  { --sdg: #E5243B; }
[data-sdg="2"]  { --sdg: #DDA63A; }
[data-sdg="3"]  { --sdg: #4C9F38; }
[data-sdg="4"]  { --sdg: #C5192D; }
[data-sdg="5"]  { --sdg: #FF3A21; }
[data-sdg="6"]  { --sdg: #26BDE2; }
[data-sdg="7"]  { --sdg: #FCC30B; }
[data-sdg="8"]  { --sdg: #A21942; }
[data-sdg="9"]  { --sdg: #FD6925; }
[data-sdg="10"] { --sdg: #DD1367; }
[data-sdg="11"] { --sdg: #FD9D24; }
[data-sdg="12"] { --sdg: #BF8B2E; }
[data-sdg="13"] { --sdg: #3F7E44; }
[data-sdg="14"] { --sdg: #0A97D9; }
[data-sdg="15"] { --sdg: #56C02B; }
[data-sdg="16"] { --sdg: #00689D; }
[data-sdg="17"] { --sdg: #19486A; }

/* Index comparison: read down a column, so the figures are the emphasis and
   the index names are the quiet stub. */
.indextable { width: 100%; border-collapse: collapse; font-size: var(--step--1); }
.indextable thead th {
  background: var(--navy-50); color: var(--ink-500);
  font-size: .68rem; text-transform: uppercase; letter-spacing: .07em; font-weight: 700;
  padding: .55rem .8rem; text-align: end; border-bottom: 1px solid var(--line);
}
.indextable thead th:first-child { text-align: start; }
.indextable tbody th {
  text-align: start; font-weight: 650; color: var(--ink-900);
  padding: .7rem .8rem; white-space: nowrap;
}
/* One step down from the masthead's figures, deliberately. 463 and the h-index
   appear in both places; if the table sets them at the same weight it competes
   with the headline instead of breaking it down, and the eye lands on the
   detail first. */
.indextable td {
  text-align: end; padding: .7rem .8rem;
  font-size: var(--step-0); font-weight: 700; color: var(--navy-700);
  font-variant-numeric: tabular-nums; line-height: 1.2;
}
.indextable tbody tr + tr th, .indextable tbody tr + tr td { border-top: 1px solid var(--line); }
.indextable__note {
  margin-top: .7rem; font-size: var(--step--1); color: var(--ink-500); line-height: 1.5;
}

/* Publications: year on a rail, title leading. */
.papers { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; }
.paper { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 1rem; padding: .9rem 0; }
.paper + .paper { border-top: 1px dashed var(--line); }
.paper__year { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--accent); font-size: var(--step--1); padding-top: .15rem; }
.paper__title { font-weight: 600; line-height: 1.45; margin: 0; }
.paper__meta { margin: .25rem 0 0; font-size: var(--step--1); color: var(--ink-500); display: flex; flex-wrap: wrap; gap: .5rem; align-items: baseline; }
.paper__meta em { font-style: italic; }
.paper__cited {
  padding: .1rem .5rem; border-radius: 999px;
  background: var(--gold-100); color: #8a6b0c; font-size: .72rem; font-weight: 700;
}
/* Scopus quartile — the one ranking signal the sync can carry. */
/* Quartile is the one ranking signal the sync can carry, and Q1 against Q4 is
   the difference a reader is looking for. Rendered in one flat colour it said
   nothing; the ramp runs from the accent down to a plain outline, so the strong
   ones stand out without turning the list into a traffic light. */
.paper__q {
  padding: .1rem .5rem; border-radius: 999px;
  border: 1px solid transparent;
  background: var(--surface-2); color: var(--ink-500);
  font-size: .72rem; font-weight: 800; letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
}
.paper__q[data-q="Q1"] { background: var(--teal-600); color: #fff; }
.paper__q[data-q="Q2"] { background: var(--teal-100); color: var(--teal-600); border-color: var(--teal-500); }
.paper__q[data-q="Q3"] { background: var(--navy-50); color: var(--navy-600); border-color: var(--navy-100); }
.paper__q[data-q="Q4"] { background: none; color: var(--ink-500); border-color: var(--line); }
/* Which index the row came from; quiet, because it is provenance not content. */
.paper__source {
  padding: .1rem .5rem; border-radius: 999px; border: 1px solid var(--line);
  color: var(--ink-500); font-size: .7rem; font-weight: 600;
}

@media (max-width: 900px) {
  .railway__item, .paper { grid-template-columns: 68px minmax(0, 1fr); gap: .7rem; }
}

/* ------------------------------------------------------------ static page */

.pagebody { padding-block: clamp(2.2rem, 5vw, 4rem); }

.pagebody__grid {
  display: grid; grid-template-columns: minmax(0, 1fr) 268px;
  gap: clamp(1.5rem, 4vw, 4rem);
  max-width: 1180px; margin-inline: auto; align-items: start;
}
/* Without a contents rail the column has no reason to sit off-centre. */
.pagebody__grid--plain { grid-template-columns: minmax(0, 1fr); max-width: 78ch; }

.pagebody__main { min-width: 0; }

.pagebody__cover {
  margin-bottom: clamp(1.4rem, 3vw, 2.2rem);
  border-radius: var(--radius-lg); overflow: hidden;
  box-shadow: var(--shadow);
}
.pagebody__cover img { display: block; width: 100%; height: auto; }

/* The opening line, set larger — it carries the page before the reader
   commits to the rest. The rule beside it is the only ornament on a page that
   is otherwise all text, so it stays thin and stops short of the last line. */
.pagebody__lead {
  font-size: var(--step-1); line-height: 1.62; color: var(--ink-900);
  margin-bottom: clamp(1.4rem, 3vw, 2rem);
  padding-inline-start: clamp(.9rem, 2vw, 1.3rem);
  border-inline-start: 3px solid var(--accent);
  text-wrap: pretty;
}

.pagebody__updated {
  display: flex; align-items: center; gap: .45rem;
  margin-top: clamp(2rem, 4vw, 3rem); padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-size: var(--step--1); color: var(--ink-500);
}
.pagebody__updated .ico { width: 1em; height: 1em; }

/* ------------------------------------------------------------ contents rail */

.pagebody__aside { position: sticky; top: calc(var(--header-h) + 1.4rem); }

.toc { border-inline-start: 2px solid var(--line); padding-inline-start: 1rem; }
.toc__title {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .1em;
  color: var(--ink-500); margin-bottom: .8rem; font-weight: 700;
}
.toc__list { margin: 0; padding: 0; list-style: none; display: grid; gap: .1rem; }
.toc__list a {
  display: block; position: relative;
  padding: .38rem 0 .38rem .1rem;
  color: var(--ink-500); text-decoration: none;
  font-size: var(--step--1); line-height: 1.4;
  transition: color .16s ease;
}
.toc__list a::before {
  /* The marker rides on the rail itself, so the active row reads as a position
     in the page rather than as a highlighted link. */
  content: ""; position: absolute;
  inset-inline-start: calc(-1rem - 2px); top: .38rem; bottom: .38rem;
  width: 2px; background: transparent;
  transition: background .16s ease;
}
.toc__list a:hover { color: var(--ink-900); }
.toc__list a.is-current { color: var(--brand); font-weight: 650; }
.toc__list a.is-current::before { background: var(--accent); }

@media (max-width: 900px) {
  .pagebody__grid { grid-template-columns: minmax(0, 1fr); max-width: 78ch; }
  .pagebody__aside { position: static; order: -1; }
  .toc {
    border-inline-start: 0; padding: .9rem 1.1rem;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--surface-2);
  }
  .toc__list { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
  .toc__list a::before { content: none; }
}

.emptystate {
  display: grid; justify-items: center; gap: .9rem; text-align: center;
  padding: clamp(2.5rem, 6vw, 4rem) 1.5rem;
  border: 1px dashed var(--line); border-radius: var(--radius-lg);
  background: var(--surface-2); color: var(--ink-500);
}
.emptystate__ico { width: 2rem; height: 2rem; color: var(--ink-300); }

/* ----------------------------------------------------------------- prose */

.prose {
  font-size: var(--step-0); line-height: 1.78; color: var(--ink-700);
  text-wrap: pretty;
}
.prose > * + * { margin-top: 1.05em; }
.prose p { max-width: 72ch; }

/* Headings carry a hairline above them instead of extra air: on an imported
   page that is one long run of sections, space alone stops reading as a break
   somewhere around the fourth heading. */
.prose h2 {
  font-size: var(--step-2); color: var(--ink-900); line-height: 1.25;
  margin-top: 2.2em; padding-top: 1.1em; border-top: 1px solid var(--line);
  scroll-margin-top: calc(var(--header-h) + 1.5rem);
  text-wrap: balance;
}
.prose > h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.prose h3 {
  font-size: var(--step-1); color: var(--ink-900); line-height: 1.35;
  margin-top: 1.9em;
  scroll-margin-top: calc(var(--header-h) + 1.5rem);
  text-wrap: balance;
}
.prose h4 { font-size: var(--step-0); color: var(--ink-900); margin-top: 1.5em; }
.prose > :first-child { margin-top: 0; }

.prose a { color: var(--brand); text-decoration: underline; text-underline-offset: .18em; text-decoration-thickness: 1px; }
.prose a:hover { color: var(--accent); text-decoration-thickness: 2px; }
/* The arrow says the link leaves the site. A glyph rather than an icon file:
   it inherits colour and size for free, and there is no request to lose. */
.prose a.link--external::after {
  content: "\2197"; margin-inline-start: .18em;
  font-size: .82em; line-height: 1; opacity: .65;
  text-decoration: none; display: inline-block;
}

.prose ul, .prose ol { padding-inline-start: 1.3em; max-width: 72ch; }
.prose li + li { margin-top: .4em; }
.prose ul > li::marker { color: var(--accent); }
.prose ol > li::marker { color: var(--ink-500); font-variant-numeric: tabular-nums; }

.prose blockquote {
  padding: 1rem 1.3rem; margin-inline: 0;
  border-inline-start: 4px solid var(--accent);
  background: var(--surface-2);
  border-radius: 0 var(--radius) var(--radius) 0;
  color: var(--ink-700); font-size: var(--step-1); line-height: 1.6;
}
.prose hr { border: 0; border-top: 1px solid var(--line); margin-block: 2.4em; }
.prose code {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: .88em; background: var(--surface-2);
  padding: .1em .35em; border-radius: 4px;
}

/* ------------------------------------------------------------ prose figure */

.prose__figure, .prose figure { margin-block: 1.8em; }
.prose__figure img, .prose figure img {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.prose figcaption {
  font-size: var(--step--1); color: var(--ink-500);
  margin-top: .6rem; padding-inline-start: .1rem;
  border-inline-start: 2px solid var(--line); padding-inline-start: .7rem;
  line-height: 1.5;
}

/* A portrait dropped into a text page fills the column and pushes the reading
   off the screen. Capping both axes keeps the page a page rather than a
   gallery, and letting width follow height means a tall photo shrinks instead
   of being cropped. Fixed pixels, not viewport units: the cap has to hold on a
   tall window too, where 70vh is most of a page. */
.prose__figure { display: grid; justify-items: start; }
.prose__figure img {
  width: auto; height: auto;
  max-width: min(100%, 640px); max-height: 520px;
}

/* ------------------------------------------------------------------ embeds */

.embed {
  margin-block: 1.8em;
  border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--line); box-shadow: var(--shadow-sm);
  background: var(--surface-2);
}
.embed iframe { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; }
.embed--map iframe { aspect-ratio: 16 / 10; min-height: 300px; }

/* A lazy iframe is an empty rectangle until it loads, and if the third party
   is blocked it stays one. The pin and the label sit behind it, so the space
   reads as a map that has not arrived rather than as a hole in the page. */
.embed--map {
  position: relative;
  background:
    radial-gradient(circle at 50% 44%, var(--navy-100) 0 12px, transparent 12px),
    var(--surface-2);
}
.embed--map::after {
  content: attr(data-placeholder);
  position: absolute; inset-inline: 0; top: calc(44% + 1.6rem);
  text-align: center; color: var(--ink-500); font-size: var(--step--1);
  pointer-events: none;
}
.embed--map iframe { position: relative; z-index: 1; }

.embed--map figcaption { position: relative; z-index: 2; }
.prose .embed__fallback {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .55rem .95rem; margin: .7rem;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--brand);
  font-size: var(--step--1); font-weight: 650; text-decoration: none;
}
.prose .embed__fallback:hover,
.prose .embed__fallback:focus-visible {
  border-color: var(--accent); color: var(--teal-600); text-decoration: none;
}

/* The video facade brings its own black frame and radius. */
.embed--video { border: 0; box-shadow: var(--shadow); background: none; }
.prose .prose__video { max-width: 900px; }
/* `.prose figure img` wins over `.video-card__frame img` on specificity, so the
   poster has to be restated here in full: without object-fit it renders at its
   own ratio and YouTube's letterbox bars show above and below the frame. */
.prose .prose__video img {
  width: 100%; height: 100%; object-fit: cover;
  max-width: none; max-height: none;
  border-radius: 0; box-shadow: none;
}

/* The play triangle, drawn rather than fetched: the sprite lives in the page
   shell and this markup is built inside the body. */
.video-card__play-mark {
  width: 0; height: 0;
  border-block: 11px solid transparent;
  border-inline-start: 18px solid currentColor;
  border-inline-end: 0;
  margin-inline-start: 5px;
}
.prose a.video-card__play { text-decoration: none; }
.prose a.video-card__play::after { content: none; }
.prose a.video-card__play:hover { background: #fff; }

/* ------------------------------------------------------------------ tables */

.tablewrap {
  margin-block: 1.8em; overflow-x: auto;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface);
}
.tablewrap:focus-visible { outline: none; box-shadow: var(--ring); }
.prose table { width: 100%; border-collapse: collapse; font-size: var(--step--1); }
.prose th, .prose td { padding: .7rem .9rem; text-align: start; vertical-align: top; }
.prose thead th, .prose tr:first-child th {
  background: var(--navy-50); color: var(--ink-900); font-weight: 700;
  border-bottom: 2px solid var(--line);
}
.prose tbody tr + tr td, .prose tr + tr td { border-top: 1px solid var(--line); }
.prose tbody tr:hover td { background: var(--surface-2); }

/* ------------------------------------------------------------- fact tiles */

/* Label/value couples the source theme wrote as headings — "Dosen / 17",
   "Akreditasi / Baik". As headings they read as six tiny sections; as tiles
   they read as what they are, a summary of the programme. */
/* The dividers are borders on the tiles, not a coloured gap showing through:
   a row that does not fill — seven facts in a four-column grid — would leave
   the gap colour standing in the empty cell as a grey block. The negative
   offsets slide the first row and column of borders under the frame. */
.factlist {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  margin-block: 1.9em;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
}
.factlist__item {
  padding: 1rem 1.1rem; min-width: 0;
  border-inline-start: 1px solid var(--line);
  border-block-start: 1px solid var(--line);
  margin-inline-start: -1px; margin-block-start: -1px;
}
.factlist dt {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-500); font-weight: 700; margin-bottom: .35rem;
}
.factlist dt a { color: inherit; text-decoration: none; }
.factlist dt a:hover { color: var(--brand); text-decoration: underline; }
.factlist dd {
  margin: 0; color: var(--ink-900); font-weight: 650;
  font-size: var(--step-0); line-height: 1.35; overflow-wrap: anywhere;
}
.factlist .factlist__num {
  font-size: var(--step-3); line-height: 1; color: var(--brand);
  font-variant-numeric: tabular-nums; font-weight: 700;
}

/* -------------------------------------------------------------- quote card */

.prose .quotegrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
  gap: 1rem; margin-block: 1.9em;
}
.prose .quotegrid > * + * { margin-top: 0; }

.prose .quotecard {
  display: grid; grid-template-rows: auto 1fr auto;
  gap: .85rem; margin: 0;
  padding: 1.3rem;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
/* Scoped through .quotecard on purpose: `.prose figure img` above sets a full
   width, and a two-class selector would lose to it and stretch the portrait
   across the card. */
.prose .quotecard .quotecard__portrait {
  width: 64px; height: 64px; max-width: none; max-height: none;
  border-radius: 50%; object-fit: cover; object-position: top center;
  box-shadow: none; border: 2px solid var(--navy-100);
}
.prose .quotecard__text {
  margin: 0; padding: 0; border: 0; background: none; border-radius: 0;
  font-size: var(--step-0); line-height: 1.7; color: var(--ink-700);
}
/* The quotation mark is decoration, so it is drawn rather than typed — a real
   character here would be read out before every testimonial. */
.prose .quotecard__text::before {
  content: "\201C"; display: block;
  font-size: 2.4rem; line-height: .7; color: var(--accent);
  opacity: .45; margin-bottom: .2rem;
}
.quotecard__by { display: grid; gap: .1rem; margin: 0; border: 0; padding: 0; }
.prose .quotecard__by { font-size: var(--step--1); }
.quotecard__by strong { color: var(--ink-900); font-weight: 700; line-height: 1.35; }
.quotecard__by span { color: var(--ink-500); }

/* One card on its own is a pull quote, not a grid item: let it run wide and
   put the portrait beside the words. */
.prose > .quotecard { max-width: 72ch; }

/* ---------------------------------------------------------- standalone link */

/* "Baca Selengkapnya" and its kin: a link that stands between two blocks
   rather than inside a sentence. */
.prose .prose__more {
  display: inline-flex; align-items: center; gap: .45rem;
  margin-top: .9em;
  padding: .5rem .95rem;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface);
  color: var(--brand); font-weight: 650; font-size: var(--step--1);
  text-decoration: none;
  transition: border-color .16s ease, background .16s ease, gap .16s ease;
}
.prose .prose__more::after {
  content: "\2192"; font-size: 1.05em; line-height: 1;
}
.prose .prose__more:hover,
.prose .prose__more:focus-visible {
  border-color: var(--accent); background: var(--teal-100);
  color: var(--teal-600); text-decoration: none; gap: .7rem;
}
@media (prefers-reduced-motion: reduce) {
  .prose .prose__more { transition: none; }
  .prose .prose__more:hover { gap: .45rem; }
}
[dir="rtl"] .prose .prose__more::after { content: "\2190"; }

/* -------------------------------------------------------- document shelf */

/* A list whose every row is one link to a PDF is a shelf of documents. As
   bullets it reads as a footnote; as rows with a type badge and a weight it
   reads as something you can act on. */
.prose .doclist {
  list-style: none; padding: 0; margin-block: 1.9em; max-width: none;
  display: grid; gap: .5rem;
}
.prose .doclist li + li { margin-top: 0; }

/* Scoped through .prose: the underline on `.prose a` would otherwise win on
   specificity and run a line under the whole card. */
.prose .doclink {
  display: flex; align-items: center; gap: .9rem;
  padding: .85rem 1rem;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); color: var(--ink-900);
  text-decoration: none; font-weight: 600; line-height: 1.4;
  transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
/* The badge tint is a token so the dark palette can restate it: a pale wash
   that reads as "paper" on white reads as a lit panel on a dark card. */
:root {
  --doc-pdf-bg:  #fdeceb;      --doc-pdf-ink:  var(--red-600);
  --doc-word-bg: var(--navy-100); --doc-word-ink: var(--navy-600);
  --doc-xls-bg:  var(--teal-100); --doc-xls-ink:  var(--teal-600);
  --doc-ppt-bg:  var(--gold-100); --doc-ppt-ink:  var(--gold-600);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --doc-pdf-bg:  #34201f; --doc-pdf-ink:  #e8827e;
    --doc-word-bg: #14293a; --doc-word-ink: #7fb6dc;
    --doc-xls-bg:  #102b28; --doc-xls-ink:  #5fc2b1;
    --doc-ppt-bg:  #2c2413; --doc-ppt-ink:  #dfb254;
  }
}
:root[data-theme="dark"] {
  --doc-pdf-bg:  #34201f; --doc-pdf-ink:  #e8827e;
  --doc-word-bg: #14293a; --doc-word-ink: #7fb6dc;
  --doc-xls-bg:  #102b28; --doc-xls-ink:  #5fc2b1;
  --doc-ppt-bg:  #2c2413; --doc-ppt-ink:  #dfb254;
}

.prose .doclink::before {
  content: attr(data-ext);
  flex: none; display: grid; place-items: center;
  width: 3rem; height: 2.4rem;
  border-radius: var(--radius-sm);
  background: var(--navy-50); color: var(--brand);
  font-size: .64rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
}
.prose .doclink[data-ext="pdf"]::before { background: var(--doc-pdf-bg); color: var(--doc-pdf-ink); }
.prose .doclink[data-ext="doc"]::before, .prose .doclink[data-ext="docx"]::before { background: var(--doc-word-bg); color: var(--doc-word-ink); }
.prose .doclink[data-ext="xls"]::before, .prose .doclink[data-ext="xlsx"]::before { background: var(--doc-xls-bg); color: var(--doc-xls-ink); }
.prose .doclink[data-ext="ppt"]::before, .prose .doclink[data-ext="pptx"]::before { background: var(--doc-ppt-bg); color: var(--doc-ppt-ink); }

.prose .doclink:hover, .prose .doclink:focus-visible {
  border-color: var(--accent); box-shadow: var(--shadow-sm);
  color: var(--ink-900); text-decoration: none; transform: translateY(-1px);
}
@media (prefers-reduced-motion: reduce) {
  .prose .doclink { transition: none; }
  .prose .doclink:hover { transform: none; }
}

.doclink__size {
  margin-inline-start: auto; flex: none;
  font-size: var(--step--1); font-weight: 600; color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
.prose .doclink.link--external::after { content: none; }

@media (max-width: 480px) {
  .doclink { flex-wrap: wrap; gap: .6rem .9rem; }
  .doclink__size { margin-inline-start: calc(3rem + .9rem); }
}


/* ---------------------------------------------------------------- single */
.single__hero { position: relative; padding-block: clamp(2.5rem, 6vw, 4.5rem); color: #fff; overflow: hidden; }
.single__hero-bg { position: absolute; inset: 0; z-index: -2; }
.single__hero-bg img { width: 100%; height: 100%; object-fit: cover; }
.single__hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgb(6 36 58 / .78), rgb(6 36 58 / .93));
}
.single__hero-inner { max-width: 900px; }
.single__title { font-size: var(--step-3); margin-block: .7rem .6rem; color: #fff; }
.single__meta { display: flex; flex-wrap: wrap; gap: .4rem 1.3rem; font-size: var(--step--1); color: rgb(255 255 255 / .8); }
.single__meta span { display: inline-flex; align-items: center; gap: .35rem; }

.term-list { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .9rem; }
.term-list a {
  display: inline-block; padding: .22rem .7rem; border-radius: 999px;
  background: rgb(255 255 255 / .16); color: #fff; font-size: .74rem; font-weight: 650; text-decoration: none;
}
.term-list a:hover { background: var(--accent); color: #fff; }

/* The shell widened to 1440 so listings and grids can use a large monitor, but
   a reading column that grows with it becomes hard to track from line to line.
   These three are the reading layouts, so they keep the earlier measure and
   sit centred in the wider page. */
.single__layout, .detail, .profile {
  display: grid; grid-template-columns: minmax(0, 1fr) 320px;
  gap: clamp(1.5rem, 3.5vw, 3rem); padding-block: clamp(2rem, 4vw, 3.2rem);
  max-width: 1200px; margin-inline: auto;
}
.profile { grid-template-columns: 340px minmax(0, 1fr); padding-block: 0; }

/* An entry with nothing but its facts — the imported agenda records are all
   like this — drops the empty main column and centres the cards instead of
   leaving a tall void beside them. */
.detail--facts-only { grid-template-columns: minmax(0, 640px); justify-content: center; }
.detail--facts-only .detail__aside { display: grid; gap: 1.2rem; }

.aside-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 1.2rem; box-shadow: var(--shadow-sm);
}
.aside-card + .aside-card { margin-top: 1rem; }
.aside-card__title { font-size: var(--step--1); text-transform: uppercase; letter-spacing: .09em; color: var(--ink-500); margin-bottom: .9rem; }
.aside-list { list-style: none; padding: 0; display: grid; gap: .85rem; }
/* Flex, not a two-track grid: an entry without a featured image would otherwise
   drop its title into the 84px image column and wrap it to shreds. */
.aside-list a { display: flex; gap: .7rem; align-items: center; text-decoration: none; color: inherit; }
/* responsive_image() emits <picture> when a WebP/AVIF sibling exists and a bare
   <img> when it does not, so the thumbnail slot has to be sized on whichever
   element actually turns up as the flex item. */
.aside-list a > picture,
.aside-list a > img { flex: 0 0 84px; width: 84px; }
.aside-list img { display: block; width: 100%; border-radius: var(--radius-sm); aspect-ratio: 4 / 3; object-fit: cover; }
.aside-list a > span { flex: 1 1 auto; min-width: 0; }
.aside-list strong { display: block; font-size: var(--step--1); font-weight: 650; line-height: 1.35; }
.aside-list small { font-size: .74rem; color: var(--ink-500); }
.aside-list a:hover strong { color: var(--accent); }

.share { list-style: none; padding: 0; display: flex; gap: .5rem; }
.share a {
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line); color: var(--ink-700);
}
.share a:hover { background: var(--accent); border-color: var(--accent); color: #fff; }

/* --------------------------------------------------------------- profile */
.profile__photo { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; border-radius: var(--radius-lg); box-shadow: var(--shadow); }
.profile__facts { display: grid; grid-template-columns: auto 1fr; gap: .45rem .9rem; margin-top: 1.2rem; font-size: var(--step--1); }
.profile__facts dt { font-weight: 700; color: var(--ink-500); }
.profile__facts dd { margin: 0; color: var(--ink-900); word-break: break-word; }
.profile__name { font-size: var(--step-2); }
.profile__subtitle { font-size: var(--step-1); margin-top: 2rem; margin-bottom: .9rem; }

.timeline { list-style: none; padding: 0; display: grid; gap: .1rem; }
.timeline__item {
  display: grid; grid-template-columns: 86px 1fr; gap: 1rem; align-items: start;
  padding: .85rem 0; border-bottom: 1px solid var(--line);
}
.timeline__item:last-child { border-bottom: 0; }
.timeline__year { font-family: var(--font-head); font-weight: 800; color: var(--accent); }
.timeline__item strong { display: block; font-size: var(--step-0); }
.timeline__item span { font-size: var(--step--1); color: var(--ink-500); }

/* ---------------------------------------------------------------- detail */
.detail__figure, .page-figure { margin: 0 0 1.6rem; border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-sm); }
.detail__figure img, .page-figure img { width: 100%; max-height: 520px; object-fit: cover; }
.detail__video { margin-bottom: 1.6rem; }
.btn--block { display: flex; width: 100%; margin-top: 1rem; }

.gallery { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: .8rem; }
.gallery a { display: block; aspect-ratio: 4 / 3; border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-sm); }
.gallery img { transition: transform .35s ease; }
.gallery a:hover img { transform: scale(1.06); }

.note { padding: .8rem 1.1rem; border-radius: var(--radius); font-size: var(--step--1); margin-top: 1.4rem; }
.note--pending { background: var(--gold-100); border: 1px solid rgb(217 165 32 / .4); color: #6b5210; }
[data-theme="dark"] .note--pending { background: rgb(217 165 32 / .12); color: var(--gold-500); }

/* -------------------------------------------------------------- archives */
.post-grid { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1.2rem; }
.flyer-grid { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 1.2rem; }
.flyer-grid .flyer { flex: none; }
.testi-grid--light .testi { background: var(--surface); border-color: var(--line); }
.testi-grid--light .testi__text { color: var(--ink-700); }
.testi-grid--light .testi__quote { color: var(--navy-100); }
.testi-grid--light .testi__by { border-top-color: var(--line); }
.testi-grid--light .testi__by strong { color: var(--ink-900); }
.testi-grid--light .testi__by small { color: var(--ink-500); }

.empty-state {
  padding: 3rem 1rem; text-align: center; color: var(--ink-500);
  background: var(--surface-2); border: 1px dashed var(--line); border-radius: var(--radius-lg);
}

/* ---------------------------------------------------------------- search */
.search-inline { display: flex; gap: .6rem; margin-bottom: 1.8rem; }
.search-inline input {
  flex: 1; padding: .8rem 1.1rem; border: 1.5px solid var(--line);
  border-radius: 999px; background: var(--surface-2);
}
.search-inline input:focus { border-color: var(--accent); background: var(--surface); outline: none; box-shadow: var(--ring); }

.result-list { list-style: none; padding: 0; display: grid; gap: 1.1rem; }
.result { display: grid; grid-template-columns: 130px 1fr; gap: 1rem; padding-bottom: 1.1rem; border-bottom: 1px solid var(--line); }
.result:last-child { border-bottom: 0; }
.result:not(:has(.result__media)) { grid-template-columns: 1fr; }
.result__media { display: block; aspect-ratio: 4 / 3; border-radius: var(--radius-sm); overflow: hidden; background: var(--navy-50); }
.result__type { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; color: var(--accent); font-weight: 700; }
.result__title { font-size: var(--step-1); margin-top: .2rem; }
.result__title a { color: inherit; text-decoration: none; }
.result__title a:hover { color: var(--accent); }
.result__excerpt { font-size: var(--step--1); color: var(--ink-500); margin-top: .3rem; }

/* ----------------------------------------------------------------- pager */
.pager { margin-top: 2.4rem; }
.pager ul { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: .35rem; justify-content: center; }
.pager a, .pager span {
  display: grid; place-items: center; min-width: 42px; height: 42px; padding-inline: .8rem;
  border-radius: var(--radius-sm); border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-700); text-decoration: none; font-size: var(--step--1); font-weight: 600;
}
.pager a:hover { border-color: var(--accent); color: var(--accent); }
.pager .is-current, .pager .active span { background: var(--brand); border-color: var(--brand); color: #fff; }
.pager .disabled span { opacity: .45; }

@media (max-width: 900px) {
  .single__layout, .detail, .profile { grid-template-columns: 1fr; }
  .profile__side { max-width: 380px; }
  .result { grid-template-columns: 96px 1fr; }
}
