/* ==========================================================================
   APMF 2027 Bangkok — theme v2: header, hero and footer
   ========================================================================== */

/* --- sticky header ------------------------------------------------------ */
/* Deliberately a copy of theme v1's header in every measurement — logo size and
   indent, bar padding, link padding and type scale, shrink behaviour. The only
   difference is the typeface: v1 uses Kanit, this uses IBM Plex Sans Thai. */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: #ffffff;
  border-bottom: 1px solid var(--line);
  transition: background 0.25s ease, box-shadow 0.25s ease;
}

.hdr-inner {
  max-width: none;
  margin: 0 auto;
  padding: 8px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  /* The logo and the menu stay on one bar. Letting this row wrap dropped the
     whole menu underneath the logo as soon as it ran out of width — around
     1280px — which reads as two separate bars. The menu has its own
     `flex-wrap`, so when it is too wide it now folds onto a second line beside
     the logo instead, and the header simply grows taller. */
  flex-wrap: nowrap;
}

.hdr-logo {
  display: block;
  width: 330px;
  max-width: 40vw;
  height: auto;
  margin-left: 130px;
  transition: width 0.25s ease, margin-left 0.25s ease;
  /* The lockup is 783x177. If a width and a height are ever both in force at
     once it is squashed, which is what happened on a phone and on an iPad held
     upright. `contain` makes that impossible: the worst a bad pair of rules can
     now do is leave space around it, not distort the artwork. */
  object-fit: contain;
}

.hdr-nav {
  display: flex;
  align-items: center;
  gap: 0;
  flex-wrap: wrap;
  flex: 1 1 auto;
  min-width: 0;
  justify-content: center;
}

.hdr-nav a {
  position: relative;
  /* the shrunk state inherits these, so one change covers both */
  padding: 8px 12px;
  font-family: var(--font-sans);
  /* 16.5px everywhere, on the client's instruction. It was 1rem here and 18px
     in three other rules; the menu is a row of labels rather than something
     read, so it does not follow the body copy up. The rules below now only
     tighten the spacing, never the size. */
  font-size: 16.5px;
  font-weight: 500;
  letter-spacing: 0;
  white-space: nowrap;
  text-transform: uppercase;
  color: oklch(0.3 0.02 60);
}

.hdr-nav a:hover {
  color: var(--magenta-hover);
}

.hdr-nav a.is-active {
  color: var(--pink);
}

/* selected item: a plain solid underline, no background */
.hdr-nav a.is-active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 1px;
  height: 2px;
  background: var(--magenta-bright);
}

/* A dot between items. It is positioned in the gap, outside any link box, so
   it neither joins the underline of the selected item nor becomes clickable. */
.hdr-nav > .hdr-sub {
  position: relative;
}

.hdr-nav > *:not(:first-child)::before {
  content: "·";
  position: absolute;
  left: -3px;
  top: 50%;
  transform: translateY(-50%);
  color: oklch(0.3 0.02 60 / 0.4);
  pointer-events: none;
}

.site-header[data-shrunk="1"] .hdr-nav > *:not(:first-child)::before {
  color: rgba(239, 228, 247, 0.5);
}

/* the longer labels need less room per item between 992 and 1560px, exactly as
   v1 does, so the nine items stay on one row */
/* Register and Abstracts gained a submenu, and each caret costs about 18px, so
   the tighter spacing now starts higher up — without this the row wrapped
   under the logo at 1600px, which it did not before. */
@media screen and (min-width: 992px) and (max-width: 1760px) {
  .hdr-nav a {
    /* Spacing only. The size used to drop here to squeeze nine items onto
       one row; there are eight now, the row may fold to a second line beside
       the logo, and the size is one figure for the whole menu. */
    padding-left: 6px;
    padding-right: 6px;
  }
}

/* "Accommodation" became "Venue & Accommodation", eight characters longer, and
   at the narrow end of that band it pushed "Contact us" onto a second line
   under the logo. A little less room per item and a slightly smaller label
   bring the row back to one line; measured at 1024, 1100 and 1200px. */
@media screen and (min-width: 992px) and (max-width: 1280px) {
  .hdr-nav a {
    padding-left: 3px;
    padding-right: 3px;
  }
}

/* The dropdown caret. Its size is set in one place only, further down with
   the rest of the caret's rules -- a `font-size` here as well was dead, since
   the later rule has the same weight and won on order alone. */
.hdr-sub-toggle i {
  opacity: 0.75;
}

/* --- shrink on scroll --------------------------------------------------- */

.site-header[data-shrunk="1"] {
  background: #2a1b52;
  border-bottom-color: transparent;
  box-shadow: 0 4px 18px rgba(27, 16, 70, 0.25);
}

.site-header[data-shrunk="1"] .hdr-nav a {
  color: #efe4f7;
}

.site-header[data-shrunk="1"] .hdr-nav a:hover,
.site-header[data-shrunk="1"] .hdr-nav a.is-active {
  color: #fff;
}

/* The shrunk bar turns its links pale, and on the desktop dropdown — which is
   its own near-white panel — that left pale text on white. The dropdown keeps
   its own colours. Below 992px the submenu is inline on the bar itself, so the
   pale colour is right there and this stays scoped to the desktop layout. */
@media (min-width: 992px) {
  .site-header[data-shrunk="1"] .hdr-sub-menu a {
    color: oklch(0.3 0.02 60);
  }

  .site-header[data-shrunk="1"] .hdr-sub-menu a:hover {
    color: var(--magenta-hover);
  }
}

.site-header[data-shrunk="1"] .hdr-burger span {
  background: var(--off-white);
}

@media (min-width: 992px) {
  .site-header[data-shrunk="1"] .hdr-logo {
    width: 215px;
    margin-left: 85px;
  }
}

/* the shrunk bar is deep purple and the artwork is dark navy and pink, so it
   sinks into it. A white plate keeps the lockup readable. */
.site-header[data-shrunk="1"] .hdr-logo {
  box-sizing: content-box;
  background: #fff;
  padding: 6px 12px;
  border-radius: 6px;
}

/* --- announcement bar --------------------------------------------------- */

.announce-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 10px 20px;
  background: var(--deep);
  color: var(--off-white);
  /* 16.5px, the same figure the menu is set in. The bar and the menu are the
     two strips above the page rather than part of it, and they were reading
     at the body size, which made the announcement compete with the heading
     under it. */
  font-size: 16.5px;
}

.announce-pill {
  padding: 3px 8px;
  border: 1px solid oklch(0.58 0.08 262);
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 16.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.announce-bar a {
  color: var(--off-white);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.announce-bar a:hover {
  color: #fff;
}

.announce-close {
  margin-left: 4px;
  padding: 0 4px;
  background: none;
  border: none;
  color: oklch(0.84 0.04 262);
  font-size: 16.5px;
  line-height: 1;
  cursor: pointer;
}

.announce-close:hover {
  color: #fff;
}

/* --- homepage hero ------------------------------------------------------ */

.hero-band {
  position: relative;
  overflow: hidden;
  /* The photo is 1672x941, so 56.3vw is exactly its own aspect ratio. Giving
     the band that height means `cover` scales the image to the full width with
     nothing left over vertically, so the tower tops stop being cropped. Taller
     content still wins, since this is only a floor. */
  min-height: 56.3vw;
  display: flex;
  /* the band is now taller than its content, so centring left the block
     sitting low in the frame; anchor it to the top and let .hero-inner's own
     top padding set the distance */
  align-items: flex-start;
  background-color: var(--banner-base);
  /* matched to theme v1's hero scrim, which is considerably lighter and lets
     the palace and the river read. The prototype's darker mid-band was there
     to protect the wordmark, but the client chose the brighter photograph and
     a wordmark with no shadow at all, so that protection is gone by choice. */
  background-image: linear-gradient(
      180deg,
      rgba(42, 27, 82, 0.35) 0%,
      rgba(42, 27, 82, 0.55) 22%,
      rgba(42, 27, 82, 0.55) 46%,
      rgba(42, 27, 82, 0) 70%
    ),
    url("../images/banner-bangkok.jpg");
  background-size: cover, cover;
  /* centre the photograph, as v1 does. Anchoring it to the bottom pushed the
     sky off the top of the band, which is what made the crop look wrong. */
  background-position: center, center center;
}

.hero-inner {
  position: relative;
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: clamp(44px, 6vw, 76px) var(--gutter) clamp(48px, 6vw, 80px);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 26px;
}

/* the logo is pale pink on a pale purple sky, so it needs its own shadow to
   lift off the photograph rather than sinking into it */
.hero-mark {
  height: clamp(96px, 10vw, 140px);
  width: auto;
  display: block;
  /* a light halo, not a dark one: the artwork is pale pink on a bright
     photograph, so a white glow separates it while keeping the hero light */
  filter: drop-shadow(0 0 7px rgba(255, 255, 255, 0.45))
    drop-shadow(0 0 20px rgba(255, 255, 255, 0.28));
}

/* With the scrim lightened to match v1 these lines sit over the lit palace
   roofs, so they carry their own shadow stack instead: a tight dark halo for
   edge contrast plus a wide soft one to separate them from the highlights.
   Local to the text, so the photograph stays bright. */
.hero-federation,
.hero-when {
  color: #fff;
  text-shadow: 0 1px 2px rgba(10, 4, 34, 0.95), 0 2px 8px rgba(10, 4, 34, 0.85),
    0 4px 24px rgba(10, 4, 34, 0.7);
}

.hero-federation {
  font-size: clamp(19px, 2.3vw, 28px);
  line-height: 1.35;
}

.hero-federation sup {
  font-size: 0.6em;
}

.hero-when {
  font-size: clamp(17px, 2vw, 25px);
  line-height: 1.45;
}

/* the wordmark carries the logo's own gradient, sampled straight off the
   artwork, and no shadow at all */
.hero-wordmark {
  font-size: clamp(62px, 11vw, 148px);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.02em;
  background: linear-gradient(95deg, #5870fd 0%, #ad6be0 52%, #ff66c4 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

.hero-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
}

/* The Register button is the same artwork theme v1 uses, at the same sizes
   (images/Register_Button-04.png), so the two homepages carry one button. */
.btn-register {
  display: inline-block;
  text-decoration: none;
}

.btn-register img {
  display: block;
  width: 100%;
  max-width: 300px;
  height: auto;
  transition: transform 0.3s ease;
}

.btn-register:hover img {
  transform: scale(1.05);
}

@media screen and (min-width: 767px) and (max-width: 1199px) {
  .btn-register img {
    max-width: 280px;
  }
}

@media screen and (max-width: 766px) {
  .btn-register img {
    max-width: 250px;
  }
}

/* --- homepage sections -------------------------------------------------- */

.section {
  max-width: var(--container);
  margin: 0 auto;
  padding: 72px var(--gutter);
}

.section-tight {
  padding-top: 56px;
  padding-bottom: 48px;
}

.band {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background-color: var(--surface);
}

.band-dark {
  background: var(--deep);
  color: var(--off-white);
}

.band-dark h2 {
  color: var(--off-white);
}

/* Copy on the left, the venue video on the right. 0.62fr keeps the player
   roughly the width of the metric row's last two columns, so the two halves
   read as one block rather than two panels. */
.intro-block {
  display: grid;
  /* The video is half as wide again as it was. The column is not simply
     0.62 x 1.5: both columns share the same row, so the fraction has to be
     solved for the share, not the ratio — 0.62fr took 38% of the width, and
     1.35fr takes 57%, which is the 50% increase asked for. */
  grid-template-columns: minmax(0, 1fr) minmax(380px, 1.35fr);
  gap: 48px;
  align-items: start;
}

.intro-copy {
  min-width: 0;
}

.video-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 12px;
  background: #170f2b;
  box-shadow: 0 10px 30px rgba(45, 20, 80, 0.16);
}

.video-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  /* YouTube shows its title bar, share and watch-later buttons as soon as the
     pointer touches the player. The embed asks for no controls, and ignoring
     the pointer keeps the rest of that furniture away as well, so the frame
     stays a moving picture. The link under it is there for anyone who wants
     the video itself, with sound. */
  pointer-events: none;
}

.video-note {
  margin: 10px 0 0;
  font-size: 18px;
  color: var(--ink-faint);
}

/* below the tablet breakpoint the player drops under the copy, where it keeps
   its full width instead of being squeezed beside the heading */
@media (max-width: 991px) {
  .intro-block {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
}

/*
 * The size is tied to the column, not to the window.
 *
 * "across the Asia-Pacific" must not break -- three lines, never four. What
 * decides that is whether the phrase fits the copy column, and that column is a
 * share of the grid rather than of the viewport: about 40% of the content width
 * once the video's 1.35fr and the 48px gap are taken out. The phrase needs
 * about ten times the font size, so against a 453px column 45px is the ceiling,
 * and `4.2vw - 6px` tracks the column as the window narrows so it does not
 * start breaking again at 1100 or 1000px.
 *
 * Chosen over the larger heading that spanned both columns: this keeps the
 * heading beside the video rather than above it.
 */
.intro-block h1 {
  margin: 0 0 20px;
  font-size: clamp(30px, calc(4.2vw - 6px), 45px);
  line-height: 1.04;
}

/* Below this the video drops under the copy and the column becomes the full
   width, so the heading is free to be larger again. */
@media (max-width: 991px) {
  .intro-block h1 {
    font-size: clamp(36px, 6vw, 52px);
  }
}

.intro-block h1 em {
  font-style: italic;
}

.intro-lead {
  margin: 0 0 28px;
  max-width: 52ch;
  /* Lead size -- see .page-lead. */
  font-size: 22px;
  line-height: 1.3;
  color: var(--ink-muted);
}

@media (max-width: 991px) {
  .intro-lead {
    font-size: 20px;
  }
}

.stat-grid {
  max-width: var(--container);
  margin: 0 auto;
  padding: 44px var(--gutter);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 32px;
}

.stat-value {
  margin-bottom: 8px;
  font-family: var(--font-serif);
  font-size: 44px;
  line-height: 1;
  color: var(--purple);
}

.stat-label {
  font-size: 18px;
  color: var(--ink-muted);
}

.date-grid {
  display: grid;
  /* Five cards, one row. Widening the page gutter took 40px out of the content
     column, which dropped this to four across and left the fifth stranded on a
     row of its own — worse than five slightly narrower cards. 205px brings the
     five back from 1169px up, a little earlier than the 1179px it managed
     before the gutter changed. */
  grid-template-columns: repeat(auto-fit, minmax(205px, 1fr));
  gap: 14px;
}

.date-card {
  position: relative;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 26px 22px 22px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
}

/* The step number is the thread through the five cards: it says this is one
   sequence with an order, not five separate notices. Ringed, so it reads as a
   step in a sequence at a glance rather than as a stray numeral.
   `inline-flex` with a fixed width and height keeps the ring a circle whether
   the number is one digit or two, and `line-height: 1` stops the inherited
   line height stretching it into an oval. */
.date-step {
  display: inline-flex;
  /* Top right of the card. `align-self` rather than absolute positioning: the
     card is a flex column, so this moves the ring across without taking it out
     of the flow, and the date line underneath can never run behind it. */
  align-self: flex-end;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: 1.5px solid currentColor;
  border-radius: 50%;
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 600;
  line-height: 1;
  color: var(--ink-faint);
  /* the tracking would push a centred numeral off centre */
  letter-spacing: 0;
}

.date-when {
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--magenta);
}

.date-what {
  font-size: 18px;
  font-weight: 600;
  line-height: 1.3;
}

.date-note {
  font-size: 18px;
  color: var(--ink-soft);
}

.date-go {
  margin-top: auto;
  padding-top: 12px;
  font-size: 18px;
  font-weight: 600;
  color: var(--purple);
}
.date-go:hover { text-decoration: underline; }

.date-done {
  margin-top: auto;
  padding-top: 12px;
  font-size: 18px;
  color: var(--ink-faint);
}

/* What is next gets the weight: a tinted card, a heavier edge and a flag. A
   delegate scanning the strip should find the one thing they have to act on
   without reading the dates and working it out. */
.date-card.is-next {
  background: var(--purple-tint);
  border-color: var(--purple);
  box-shadow: 0 0 0 1px var(--purple);
}
.date-card.is-next .date-step { color: var(--purple); }

.date-flag {
  position: absolute;
  top: -10px;
  left: 20px;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--purple);
  color: #fff;
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* What has passed stays on the page — the sequence is easier to read whole —
   but steps back so it cannot be mistaken for something still to do. */
.date-card.is-past {
  background: transparent;
  border-style: dashed;
}
.date-card.is-past .date-when,
.date-card.is-past .date-what { color: var(--ink-faint); }
.date-card.is-past .date-note { color: var(--ink-faint); }

.split {
  max-width: var(--container);
  margin: 0 auto;
  padding: 72px var(--gutter);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 48px;
  align-items: start;
}

/* --- the welcome letter ---------------------------------------------------
 *
 * One column, the same width as every other section on the page. It was capped
 * at 900px when it was first rebuilt, which indented the whole letter relative
 * to the Committee section below it.
 */
.welcome-wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding: 72px var(--gutter);
}

/*
 * The two people who sign the letter: their photographs at the head of it and
 * their names at the foot, under "Warm regards,".
 *
 * Both rows are the same grid, so a name falls under its own photograph rather
 * than merely near it -- the length of the letter between them is exactly why
 * that has to be built in rather than eyeballed.
 *
 * NEITHER ROW EVER STACKS. There is no narrow-screen rule turning these into
 * one column, and that is deliberate: the client asked, in as many words, that
 * the Chair's photograph must never sit underneath the President's. On a phone
 * the columns simply get narrower and the photographs shrink with them. If a
 * future change adds a `grid-template-columns: 1fr` here for small screens, it
 * breaks a promise rather than a layout.
 */
/* Both rows centre their contents inside their own half. That is what keeps a
   name under its photograph whatever length the name is: the two share a
   centre line rather than a left edge, so neither has to be measured against
   the other. */
.welcome-people,
.welcome-signers {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 28px;
  justify-items: center;
  text-align: center;
}

.welcome-people {
  margin-bottom: 44px;
}

/* 290px is the ceiling rather than the width: the Chair's photograph is the
   300px file the committee list uses and there is no larger original, so
   anything wider would show as soft beside the President's. Below that the
   picture tracks its column. */
.welcome-people .welcome-portrait {
  width: 100%;
  max-width: 290px;
}

.welcome-regards {
  margin: 30px 0 0;
  text-align: center;
  font-size: 18px;
  /* Bold, and in the ordinary ink rather than the soft grey it was: bold grey
     reads as a half-measure at this size. It now matches the weight the two
     names are set in below it. */
  font-weight: 600;
}

.welcome-signers {
  margin-top: 10px;
  font-size: 18px;
  line-height: 1.45;
  /* Two columns, always -- the same strict rule the portraits above follow,
     inherited from the shared block at the top of this section. The client
     asked for the names side by side, left and right, and that is the whole
     of it: `auto-fit` used to stand here and it was dropping them one above
     the other on a phone with its font size turned up, because at that size
     two columns of 15ch genuinely stopped fitting and the grid collapsed to
     one. Fitting was the wrong thing to optimise for.

     Forcing them to stay side by side cannot make them overlap: each column
     is `minmax(0, 1fr)`, so it is free to be narrower than its contents want,
     and `.welcome-signer-name` breaks mid-word as a last resort. A name too
     long for its half therefore wraps inside its own half rather than running
     into the one beside it. */

  /* The shared block above sets `justify-items: center`, which is right for
     the portraits and wrong here. A grid item that is not stretched is sized
     to its own min-content, and the min-content of a column of names is the
     longest unbreakable word in it -- so the half grew to fit
     "Rattanachaiyanont," and hung out over the half beside it. Stretching
     each half to its column instead caps it at `minmax(0, 1fr)`, which is
     free to be narrower than the word; the text stays centred because the
     block is still `text-align: center`. */
  justify-items: stretch;
}

.welcome-signer {
  min-width: 0;
}

.welcome-signer-name {
  font-weight: 600;
  /* A surname is one long unbreakable word. On a very narrow screen with very
     large text it breaks rather than running over the name beside it.
     `anywhere` rather than `break-word`: the two break a word in the same
     place, but only `anywhere` also counts that break when the browser
     measures how narrow the column is allowed to be. `break-word` broke the
     line and still asked for the full width of the word, which is how the two
     names came to be drawn on top of each other. Last resort, not the usual
     case.

     Both are declared: `anywhere` is unknown to Safari before 15.4, which
     would drop the line and leave the name with no break at all. A browser
     that does not understand the second line keeps the first, and with each
     half now stretched to its column that is already enough to break the
     word -- the second line only makes the measurement agree as well. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
}

.welcome-signer-role {
  color: var(--ink-soft);
}

/* Two columns of names on a phone are tight, so the type gives a little rather
   than the layout. */
@media (max-width: 560px) {
  .welcome-people,
  .welcome-signers {
    gap: 18px;
  }

  /* The names are held in two columns at every width now, so this is where
     the type gives instead of the layout: a little smaller buys each half
     enough room to break at a space rather than through the middle of a
     surname. */
  .welcome-signers {
    font-size: 16px;
  }
}

/* the supplied portrait is square, so the frame is square too rather than
   cropping a headshot into the 3:4 placeholder the layout started with */
.welcome-portrait {
  aspect-ratio: 1/1;
  width: 100%;
  height: auto;
  object-fit: cover;
  /* the client asked for a softer frame; 22px reads as rounded at every width
     the portrait is shown at, from 260px on a phone to 420px on a desktop */
  border-radius: 22px;
  border: 1px solid var(--line);
  display: block;
}

/* The section's title, set at the same size as the letter's opening line so
   the two read as one block, with a rule under it to separate the heading from
   the letter itself. */
.welcome-heading {
  /* 34px below, not 20: the rule now has two photographs under it rather than
     a paragraph, and they need more air than a line of text does. */
  margin: 0 0 34px;
  text-align: center;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-serif);
  font-weight: 700;
  /* No size here. A section heading is sized once, on the h2 rule in app.css,
     and this is an h2 -- a second figure in a second file is how two headings
     that should match drift apart. */
  line-height: 1.2;
  /* the magenta it was as an eyebrow, kept now that it is a heading */
  color: var(--magenta);
}

/* The letter's opening paragraph, set as the section's lead line.
 *
 * No measure cap on either of these since 26 Sep 2026: the client asked for the
 * letter to run the full width of the content column, from the left edge to the
 * right, and marked it on a screenshot. A cap of 40ch and 62ch was holding the
 * text to a little over half the space the section occupies.
 */
.welcome-quote {
  margin: 0 0 22px;
  font-family: var(--font-serif);
  /* Plain, and deliberately so. It was set bold on 29 Sep 2026 at the client's
     request and taken back the same evening once they had seen it.

     Worth knowing before anyone tries again: Instrument Serif ships a single
     weight, so the browser has only two states here -- the real 400 outlines,
     and those same outlines thickened by the browser from 600 upwards. There
     is no semibold to land on in between, and 600 and 700 draw exactly the
     same picture. A genuinely heavier cut of this paragraph means changing the
     serif, not the number. */
  font-weight: 400;
  /* Back to the fluid size this paragraph had before the standfirsts were
     given one figure each, on the client's instruction: 29px on a desktop,
     22px on a phone, and every size between as the window narrows.

     It is the only standfirst that keeps its own size. The others announce a
     page; this one opens a letter that runs on below it, and it is set in the
     serif rather than the sans, so it was never really the same thing. */
  font-size: clamp(22px, 2.4vw, 29px);
  line-height: 1.25;
}

.welcome-body {
  margin: 0 0 16px;
  /* The letter is the longest stretch of reading on the site and the one the
     client was looking at when they asked for larger and darker text, so it
     is set a step above the body copy around it rather than with it.
     Deliberately 400 and not 500: it was tried at 500 on 29 Sep 2026 and the
     client, holding it beside apmf2025malaysia.org.my, asked for it back --
     that site's letter is Poppins 400, and what had read as "heavier" there
     was its darker ink, which we now have without the extra weight. */
  /* Body size, like the rest of the running text. It was a step above while
     the body copy was smaller; at 18 there is nothing left to step over. */
  font-size: 18px;
  font-weight: 400;
  /* A long line is harder to pick up again at the start of the next one, so
     the gap between lines is opened a little to compensate. */
  line-height: 1.75;
  color: var(--ink-muted);
}

.reason-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 36px;
}

.reason {
  min-width: 0;
  padding-top: 20px;
  border-top: 1px solid var(--deep-muted);
}

.reason-num {
  margin-bottom: 12px;
  font-family: var(--font-mono);
  font-size: 18px;
  letter-spacing: 0.1em;
  color: var(--pink-pale);
}

.reason h3 {
  margin: 0 0 10px;
  font-size: 19px;
  font-weight: 600;
}

.reason p {
  margin: 0;
  font-size: 18px;
  color: var(--lilac-pale);
}

.tagged-list {
  margin: 0 0 24px;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 18px;
}

.tagged-list li {
  display: flex;
  gap: 12px;
  align-items: baseline;
}

.tagged-list .tag {
  flex-shrink: 0;
  min-width: 78px;
  font-family: var(--font-mono);
  font-size: 18px;
  color: var(--magenta);
}

.tagged-list .tag-text {
  color: var(--ink-muted);
}

.photo-pair {
  min-width: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.photo-pair img {
  aspect-ratio: 1/1;
  width: 100%;
  height: auto;
  object-fit: cover;
  border-radius: 6px;
  display: block;
}

/* --- program day switcher --------------------------------------------- */

.day-tabs {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 28px;
}

.day-tab {
  padding: 12px 18px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface);
  color: oklch(0.3 0.02 60);
  font-size: 18px;
  text-align: left;
  cursor: pointer;
}

.day-tab:hover {
  border-color: var(--purple-light);
  color: oklch(0.3 0.02 60);
}

.day-tab-label {
  display: block;
  margin-bottom: 3px;
  font-family: var(--font-mono);
  font-size: 18px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.day-tab-theme {
  font-weight: 500;
}

/* the selected day is filled, not just outlined, so which day is on screen
   reads at a glance */
.day-tab.is-active {
  border-color: var(--purple);
  background: var(--purple);
  color: #fff;
}

.day-tab.is-active .day-tab-label {
  color: var(--pink-pale);
}

.day-tab.is-active:hover {
  border-color: var(--purple-hover);
  background: var(--purple-hover);
  color: #fff;
}

.day-tab.is-active .day-tab-bar {
  display: block !important;
  height: 2px;
  margin-top: 8px;
  background: var(--pink-pale);
}

.day-tab:hover {
  background: var(--purple-tint);
}

.session-list {
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
}

.session-row {
  display: grid;
  grid-template-columns: minmax(92px, 110px) 1fr;
  gap: 20px;
  padding: 20px 22px;
  border-bottom: 1px solid var(--line-light);
  background: var(--surface);
  align-items: start;
}

.session-row:last-child {
  border-bottom: none;
}

.session-time {
  padding-top: 2px;
  font-family: var(--font-mono);
  font-size: 18px;
  color: var(--purple);
}

.session-meta {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 6px;
}

.session-kind {
  padding: 3px 7px;
  border-radius: 3px;
  background: oklch(0.94 0.04 350);
  color: var(--magenta-dark);
  font-family: var(--font-mono);
  font-size: 18px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.session-room {
  font-size: 18px;
  color: var(--ink-faint);
}

.session-title {
  margin-bottom: 4px;
  font-size: 17px;
  font-weight: 500;
}

.session-speaker {
  font-size: 18px;
  color: var(--ink-soft);
}

/* --- abstract tracker & pills ------------------------------------------- */

.tracker {
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
}

.tracker-row {
  display: flex;
  gap: 14px;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid var(--line-light);
  background: var(--surface);
}

.tracker-row:last-child {
  border-bottom: none;
}

.tracker-dot {
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--purple-light);
}

.tracker-step {
  font-size: 18px;
  font-weight: 500;
}

.tracker-detail {
  font-size: 18px;
  color: var(--ink-soft);
}

.tracker-state {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 18px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.pill {
  padding: 9px 15px;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: var(--surface);
  font-size: 18px;
  color: oklch(0.36 0.018 60);
}

/* --- footer ------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--line);
  background-color: oklch(0.28 0.06 340);
  background-image: url("../images/bg-footer.jpg");
  background-size: cover;
  background-position: center;
  color: oklch(0.97 0.01 340);
}

.footer-grid {
  max-width: var(--container);
  margin: 0 auto;
  padding: 56px var(--gutter);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 36px;
}

.footer-col {
  min-width: 0;
}

.footer-logo {
  height: 64px;
  width: auto;
  display: block;
  margin-bottom: 14px;
}

.footer-blurb {
  margin: 0;
  font-size: 18px;
  color: oklch(0.93 0.02 340);
}

.footer-head {
  margin-bottom: 12px;
  font-family: var(--font-mono);
  font-size: 18px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: oklch(0.82 0.06 340);
}

.footer-links {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 18px;
}

.footer-links a,
.site-footer a {
  color: oklch(0.96 0.02 340);
}

.footer-links a:hover,
.site-footer a:hover {
  color: #fff;
  text-decoration: underline;
}

.footer-legal-wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--gutter) 40px;
}

.footer-legal {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  padding-top: 20px;
  border-top: 1px solid oklch(0.45 0.06 340);
  font-family: var(--font-mono);
  font-size: 18px;
  letter-spacing: 0.06em;
  color: oklch(0.85 0.03 340);
}

.footer-legal a {
  color: inherit;
}

.admin-login-link {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 2px 10px;
  border: 1px solid oklch(0.6 0.05 340);
  border-radius: 3px;
  color: inherit;
}

.admin-login-link:hover {
  background: rgba(255, 255, 255, 0.12);
  text-decoration: none;
}

/* --- preview notice ----------------------------------------------------- */

.preview-bar {
  padding: 6px 12px;
  background: var(--banner-base);
  color: #fff;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 18px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

@media (max-width: 700px) {
  .section,
  .split,
  .footer-grid {
    padding-top: 48px;
    padding-bottom: 48px;
  }

  .photo-pair {
    grid-template-columns: 1fr 1fr;
  }
}


/* --- hamburger and submenu ---------------------------------------------- */

.hdr-burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 42px;
  height: 36px;
  padding: 0 7px;
  background: none;
  border: 1px solid var(--line);
  border-radius: 5px;
  cursor: pointer;
}

.hdr-burger span {
  display: block;
  height: 2px;
  background: oklch(0.3 0.02 60);
  transition: transform 0.22s ease, opacity 0.22s ease, background 0.22s ease;
}

.hdr-burger.is-open span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.hdr-burger.is-open span:nth-child(2) {
  opacity: 0;
}

.hdr-burger.is-open span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* the way out of the panel; there is no panel on desktop, so no button either */
.hdr-nav-close {
  display: none;
}

/* The dot separator is drawn by `.hdr-nav > *:not(:first-child)::before`, and
   the button is one of those children. */
.hdr-nav-close::before {
  content: none;
}

/* the page must not scroll under the open panel */
body.nav-open {
  overflow: hidden;
}

.hdr-sub {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.hdr-sub-toggle i {
  font-style: normal;
  /* Up from 0.85em. The glyph is U+25BE, a "small" triangle by name, and it is
     drawn well inside its own box -- so it reads smaller than whatever number
     is written here, and the label beside it does not grow by the difference.
     The row is measured from the text, not from this. It went 1.15 -> 2.3 ->
     1.73em over one evening; the line below is what keeps any of that free of
     consequence. */
  font-size: 1.73em;
  /* Without this the glyph sits on the baseline, which puts it low beside a
     line of capitals -- `middle` hangs it from the middle of the label
     instead. It needs the inline-block to be shifted at all, and the
     inline-block is also what the open-state rotation turns. */
  display: inline-block;
  vertical-align: middle;
  /* The caret is now taller than the label it sits beside, and a taller inline
     box makes its whole line taller -- at 1280px the menu grew from 85px to 93
     and took the header down with it. Zero here keeps the caret out of that
     sum: it still draws at its new size, but the row is measured from the
     words alone, which is where the header's height should come from. */
  line-height: 0;
}

.hdr-sub-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 30;
  min-width: 170px;
  padding: 6px 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 12px 30px rgba(27, 16, 70, 0.14);
}

.hdr-sub.is-open .hdr-sub-menu {
  display: block;
}

/* Hover belongs to the desktop row only. In the panel below 992px a submenu
   starts shut and opens when it is tapped, and a touch screen's sticky :hover
   would otherwise spring one open on the way past. */
@media (min-width: 992px) and (hover: hover) and (pointer: fine) {
  .hdr-sub:hover .hdr-sub-menu {
    display: block;
  }
}

.hdr-sub-menu a {
  display: block;
  padding: 8px 16px;
  color: oklch(0.3 0.02 60);
}

.hdr-sub-menu a:hover {
  background: var(--purple-tint);
  color: var(--magenta-hover);
}

/* below the desktop breakpoint the nav becomes a panel behind the burger,
   the same breakpoint theme v1 collapses at */
@media (max-width: 991px) {
  .hdr-inner {
    flex-wrap: nowrap;
  }

  .hdr-logo {
    margin-left: 0;
    /* height leads, width follows the picture's own proportions -- `width` and
       `max-width: 40vw` from the base rule would otherwise both still apply and
       fix both sides of the box at once. */
    width: auto;
    max-width: 60vw;
    height: clamp(34px, 12vw, 44px);
  }

  .hdr-burger {
    display: flex;
  }

  /* A full-screen panel rather than a strip under the bar: it covers the
     header, so the logo and the burger are out of the way while the menu is
     up, and a long list can scroll on its own without moving the page. */
  /* Pinned to the top three edges and left to find its own height, so the
     panel ends a row below the last item instead of running to the bottom of
     the screen. `inset: 0` used to stand here, which set a bottom of 0 and
     made the height the whole viewport.

     It still covers the header -- that is what takes the logo away while the
     menu is open, so the burger and the announcement strip go with it -- and
     `max-height` with the scroll below keeps a long menu inside the screen
     rather than running off the end of it. 100dvh, not 100vh, because on a
     phone 100vh is measured as though the browser's own bars were not there.

     The shadow is what tells the eye where the panel stops now that the page
     shows beneath it. */
  .hdr-nav {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    max-height: 100vh;
    max-height: 100dvh;
    z-index: 60;
    flex: 0 1 auto;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    flex-wrap: nowrap;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: #fff;
    /* 48px at the foot is one menu row, which is the gap the client asked
       for below the last item. */
    padding: 62px 22px 48px;
    box-shadow: 0 16px 34px rgba(45, 20, 80, 0.22);
  }

  .hdr-nav.is-open {
    display: flex;
  }

  .hdr-nav-close {
    display: flex;
    position: absolute;
    top: 12px;
    right: 16px;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    padding: 0;
    font-family: var(--font-sans);
    font-size: 30px;
    line-height: 1;
    color: oklch(0.3 0.02 60);
    background: none;
    border: 1px solid var(--line);
    border-radius: 5px;
    cursor: pointer;
  }

  .hdr-nav-close:hover {
    color: var(--magenta-hover);
  }

  /* The scrolled bar turns its links pale for a deep purple background. The
     panel is white, so it keeps the unscrolled colours whatever the bar is
     doing behind it. */
  .site-header[data-shrunk="1"] .hdr-nav a {
    color: oklch(0.3 0.02 60);
  }

  .site-header[data-shrunk="1"] .hdr-nav a.is-active {
    color: var(--pink);
  }

  .hdr-nav a {
    padding: 11px 4px;
    border-bottom: 1px solid var(--line-light);
  }

  .hdr-nav a.is-active::after {
    left: 0;
    right: auto;
    width: 22px;
  }

  .hdr-sub {
    display: block;
  }

  /* The dot between items belongs to the one-line desktop row. Stacked, it
     lands in the left margin and reads as a bullet, and on a parent it sits
     beside whichever entry of its open submenu happens to be halfway down. */
  .hdr-nav > *:not(:first-child)::before {
    content: none;
  }

  /* An inline <a> ignores its own vertical padding, so a parent sat tighter
     than the plain items either side of it. As a block it gets the same 11px
     top and bottom, and the whole list is evenly spaced. */
  .hdr-sub > .hdr-sub-toggle {
    display: block;
  }

  /* shut until its parent is tapped -- `display` is left to the shared
     `.hdr-sub.is-open` rule above */
  .hdr-sub-menu {
    position: static;
    min-width: 0;
    padding: 0 0 0 18px;
    border: none;
    border-radius: 0;
    box-shadow: none;
    background: none;
  }

  .hdr-sub-menu a {
    padding: 9px 4px;
    text-transform: uppercase;
  }

  /* the caret turns over when the list under it is open */
  .hdr-sub-toggle i {
    display: inline-block;
    transition: transform 0.18s ease;
  }

  .hdr-sub.is-open > .hdr-sub-toggle i {
    transform: rotate(180deg);
  }

  .site-header[data-shrunk="1"] .hdr-logo {
    height: 32px;
  }
}

/* On a phone this strip wrapped to three lines and pushed the logo and menu
   down before anything of the page was visible, for a deadline that is on the
   Abstracts page anyway. Hidden below the phone breakpoint; display:none also
   takes it out of the accessibility tree, so it is not read out either. */
@media (max-width: 767px) {
  .announce-bar {
    display: none;
  }
}

/* --- the lotus in the bottom-left corner --------------------------------
 *
 * A fixed watermark, faded to a tenth. The fade is baked into the PNG
 * rather than applied with CSS opacity: an element carrying opacity has to
 * sit somewhere in the stacking order, and every safe place for it is either
 * on top of the text or underneath an opaque band. A background image has
 * neither problem.
 *
 * The bands repeat it because they paint their own background over the page,
 * and background-attachment: fixed positions the image against the viewport,
 * so the one drawn on the band lines up exactly with the one on the page and
 * reads as a single flower. The dark band and the footer keep their own
 * colour and cover it, which is what they should do.
 */
body.app-body,
.band:not(.band-dark) {
  background-image: url("../images/logo-watermark.png");
  background-repeat: no-repeat;
  background-position: right bottom;
  background-attachment: fixed;
  background-size: min(32vw, 340px) auto;
}

@media (max-width: 700px) {
  body.app-body,
  .band:not(.band-dark) {
    background-size: min(52vw, 230px) auto;
  }
}

@media print {
  body.app-body,
  .band:not(.band-dark) {
    background-image: none;
  }
}

/* --- the travel photographs, as a staggered collage ----------------------
 *
 * Four pictures, one per line of the list beside them. They are deliberately
 * not the same size or on the same baseline, but they never overlap: the
 * stagger comes from the left column starting lower than the right one, not
 * from negative margins.
 */
.photo-collage {
  min-width: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
}

.photo-col {
  display: grid;
  gap: 16px;
  min-width: 0;
}

.photo-col-low {
  margin-top: 46px;
}

.photo-collage img {
  width: 100%;
  height: auto;
  object-fit: cover;
  border-radius: 10px;
  display: block;
  box-shadow: 0 6px 18px rgba(45, 20, 80, 0.10);
}

/* left column: a wide one, then a squarer one; right column the other way
   about, which is what gives the block its uneven edge */
.photo-col-low img:nth-child(1) { aspect-ratio: 4 / 3; }
.photo-col-low img:nth-child(2) { aspect-ratio: 1 / 1; }
.photo-col img:nth-child(1) { aspect-ratio: 4 / 3; }
.photo-col img:nth-child(2) { aspect-ratio: 5 / 4; }

@media (max-width: 700px) {
  .photo-col-low {
    margin-top: 0;
  }

  .photo-collage img {
    aspect-ratio: 4 / 3;
  }
}

/* --- the two controls over the video ------------------------------------
 *
 * The player itself shows no controls and ignores the pointer, so these are
 * the only things on it: play/pause and sound. They sit inside the frame so
 * they travel with it at any width.
 */
.video-controls {
  position: absolute;
  left: 12px;
  bottom: 12px;
  display: flex;
  gap: 8px;
  z-index: 2;
}

.video-btn {
  width: 38px;
  height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 50%;
  background: rgba(17, 8, 34, 0.55);
  color: #fff;
  cursor: pointer;
  backdrop-filter: blur(3px);
  transition: background 0.15s ease, transform 0.15s ease;
}

.video-btn:hover,
.video-btn:focus-visible {
  background: rgba(17, 8, 34, 0.78);
  transform: translateY(-1px);
}

.video-btn:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/* The three facts under the headline stay on one line, in the order the
   committee asked for: dates, then the countdown between them, then the venue.
   The copy column is narrower now that the video is half as wide again, so the
   countdown's units wrap inside their own cell rather than pushing the venue
   onto a second row. */
/* Two facts on the first line, the countdown on its own beneath them and
   centred, which is what the committee asked for. */
.intro-copy .metric-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 22px;
}

.metric-countdown {
  grid-column: 1 / -1;
  text-align: center;
}

.metric-countdown .countdown {
  justify-content: center;
  flex-wrap: wrap;
  gap: 12px 20px;
}

/* A phone keeps the two facts side by side.
 *
 * They used to drop to one per line here, which put four short lines -- two
 * labels and two values -- down the page for something that reads as one row.
 * "July 15-17, 2027" and "ICONSIAM, Bangkok" each need about 140px, and half
 * of a 350px column is 167px, so both fit; the gap comes in to buy the margin.
 * The countdown still has the row below to itself. */
@media (max-width: 560px) {
  .intro-copy .metric-grid {
    gap: 16px;
  }
}

/* The copy is centred once the video has dropped below it.
 *
 * Above this width the column has the player beside it and the text has a
 * shape to sit against on the left. On a phone it is the whole width, and
 * left-aligned it reads as a column missing its other half; the countdown
 * underneath is already centred, so centring brings the top of the block into
 * line with it rather than introducing something new. */
@media (max-width: 560px) {
  .intro-copy .eyebrow,
  .intro-block h1,
  .intro-lead {
    text-align: center;
  }

  /* the 52ch cap would otherwise hold the paragraph against the left edge */
  .intro-lead {
    margin-left: auto;
    margin-right: auto;
  }

  /* letter-spacing adds its gap after the last character too, which throws a
     centred line to the left by that much; this puts it back */
  .intro-copy .eyebrow {
    padding-left: 0.14em;
  }
}

/* --- blocks that arrive as you reach them --------------------------------
 *
 * The hiding is scoped to .reveal-ready, a class the script puts on <html>
 * once it knows it can run: without JavaScript, or with reduced motion asked
 * for, the rule never applies and the content is simply there. Nothing on this
 * page depends on an animation to become readable.
 */
.reveal-ready [data-reveal] > * {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.55s ease, transform 0.55s ease;
}

.reveal-ready [data-reveal].is-revealed > * {
  opacity: 1;
  transform: none;
}

.reveal-ready [data-reveal].is-revealed > *:nth-child(2) { transition-delay: 0.09s; }
.reveal-ready [data-reveal].is-revealed > *:nth-child(3) { transition-delay: 0.18s; }
.reveal-ready [data-reveal].is-revealed > *:nth-child(4) { transition-delay: 0.27s; }
.reveal-ready [data-reveal].is-revealed > *:nth-child(5) { transition-delay: 0.36s; }
.reveal-ready [data-reveal].is-revealed > *:nth-child(6) { transition-delay: 0.45s; }

@media (prefers-reduced-motion: reduce) {
  .reveal-ready [data-reveal] > * {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* --- the figures and the key dates share one frame ----------------------
 *
 * They used to be two sections, one banded and one on the page background,
 * with the band's bottom border running between them. They now sit in a
 * single band: the figures keep their own spacing, the dates follow inside
 * the same frame, and the rule that separated them is gone.
 */
.band-facts .stat-grid {
  padding-bottom: 8px;
}

.band-facts-dates {
  padding-top: 24px;
}

/* the portrait at the top of a committee card on the home page: larger than
   the 44px one in the committee list, and round, with the same click-to-enlarge
   behaviour */
.person-photo {
  margin-bottom: 14px;
}

.person-photo .avatar,
.avatar.person-photo {
  width: 72px;
  height: 72px;
  font-size: 22px;
}

/* the title over the video, sized to sit under the headline beside it rather
   than compete with it */
.video-heading {
  margin: 0 0 6px;
  /* Sized by the h2 rule in app.css, like every other section heading. */
  line-height: 1.2;
}

.video-intro {
  margin: 0 0 16px;
  /* Lead size -- see .page-lead. */
  font-size: 22px;
  line-height: 1.3;
  color: var(--ink-muted);
}

@media (max-width: 991px) {
  .video-intro {
    font-size: 20px;
  }
}

/* ---------------------------------------------------------------------------
   Home page: a background colour per section.

   The page ran on two tones — the page background and `--surface` — plus one
   dark band, so neighbouring sections with the same tone ran together: the
   committee flowed into the intro, and the organisers into the sponsors, with
   nothing to say where one ended. Each section now has its own.

   Two mechanisms, because the sections are built two ways. A `.band` is already
   full width, so it only needs its `background-color` changing — the shorthand
   is avoided so the watermark that `.band:not(.band-dark)` paints survives. A
   `.section` is a max-width container, so `.home-tint` spreads the colour to
   the window edges with a box-shadow trimmed by clip-path. `100vw` is not used
   anywhere here: it counts the scrollbar and would add a horizontal one.
   --------------------------------------------------------------------------- */
.home-tint { position: relative; }
.home-tint::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--sec-bg);
  box-shadow: 0 0 0 100vmax var(--sec-bg);
  clip-path: inset(0 -100vmax);
}

/* Warm and cool alternate down the page so no two touching sections are close
   enough in hue to read as one. `band-dark` keeps the deep purple it already
   had: it is the page's one strong contrast and does the same job. */
.home-welcome   { background-color: oklch(0.985 0.006 70); }
.home-committee { --sec-bg: oklch(0.965 0.014 300); }
.home-intro     { --sec-bg: oklch(0.975 0.012 200); }
.home-facts     { background-color: oklch(0.972 0.018 60); }
.home-register  { --sec-bg: oklch(0.968 0.016 150); }
.home-bangkok   { background-color: oklch(0.962 0.012 20); }
.home-organisers{ --sec-bg: oklch(0.975 0.014 260); }
.home-sponsors  { --sec-bg: oklch(0.982 0.010 100); }

/* ---------------------------------------------------------------------------
   The key-date bar: a Key dates button, then one date at a time.

   The slides are stacked on top of each other and only one is visible, so the
   bar keeps a single height and the page below never jumps as they change.
   `grid` does the stacking — every slide is placed in the same cell.
   --------------------------------------------------------------------------- */
.announce-key {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 12px;
  border: 1px solid #fff;
  border-radius: 999px;
  /* White on the dark bar: the one element here that is meant to be pressed,
     so it is the one element that inverts. The text and the hand go dark with
     it — white-on-white would leave a blank pill. */
  background: #fff;
  color: var(--deep);
  font-family: var(--font-mono);
  font-size: 16.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
}
.announce-bar a.announce-key,
.announce-bar a.announce-key:hover { text-decoration: none; }
.announce-bar a.announce-key { color: var(--deep); }
.announce-bar a.announce-key:hover {
  background: var(--purple-tint);
  color: var(--purple);
}

/* The button pulses to be noticed, the hand taps. Both are slow: a 1.6s cycle
   is well under the three-flashes-a-second that can trigger a seizure, and it
   is a nudge rather than an alarm. Hovering stops it — by then it has done its
   job and a moving target is harder to click.
*/
@keyframes announce-key-pulse {
  0%, 100% { box-shadow: 0 0 0 0 oklch(0.68 0.16 340 / 0.55); }
  50%      { box-shadow: 0 0 0 5px oklch(0.68 0.16 340 / 0); }
}
@keyframes announce-hand-tap {
  0%, 60%, 100% { transform: translateY(0); }
  75%           { transform: translateY(-3px); }
  88%           { transform: translateY(0); }
}
.announce-key { animation: announce-key-pulse 1.6s ease-out infinite; }
.announce-key:hover { animation: none; }
.announce-hand {
  flex: none;
  animation: announce-hand-tap 1.6s ease-in-out infinite;
}
.announce-key:hover .announce-hand { animation: none; }

.announce-rail {
  display: grid;
  min-width: 0;
  /* The slides now travel the full width of this rail, so without a clip they
     would pass over the Key dates button and the dots on their way in and out.
     Clipping here is also what makes a date appear to come from the end of the
     bar rather than fade up in place. */
  overflow: hidden;
  /* room for the clip not to shave the descenders off the text */
  padding: 3px 0;
}
.announce-slide {
  grid-area: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px 16px;
  opacity: 0;
  /* waiting its turn: parked to the right, ready to come in */
  transform: translateX(100%);
  /* `visibility` is what keeps the links of a hidden slide out of the tab
     order. It flips only after the movement has finished, so the slide going
     out is still visible while it travels. */
  visibility: hidden;
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1), visibility 0s linear 0.5s;
}
.announce-slide.is-on {
  opacity: 1;
  transform: none;
  visibility: visible;
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1), visibility 0s;
}
/* leaving: carries on to the left rather than reversing back the way it came,
   so the run reads as one direction of travel */
.announce-slide.is-out {
  opacity: 0;
  transform: translateX(-100%);
  visibility: visible;
}

/* Somebody who has asked for less movement gets the change without the travel.
   The dates still rotate — that is the point of the bar — they simply appear. */
@media (prefers-reduced-motion: reduce) {
  .announce-slide,
  .announce-slide.is-on,
  .announce-slide.is-out {
    transform: none;
    transition: opacity 0.2s ease, visibility 0s;
  }
  /* The pulse and the tap are decoration; a reader who has asked for less
     movement gets a plain button. */
  .announce-key,
  .announce-hand {
    animation: none;
  }
}

.announce-dots {
  flex: none;
  display: flex;
  gap: 6px;
}
.announce-dot {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: oklch(0.55 0.05 262);
  cursor: pointer;
}
.announce-dot.is-on { background: var(--off-white); }
.announce-dot:hover { background: #fff; }

/* On a phone the dots are the first thing to go: the bar is already two lines
   and the reader can wait the five seconds. */
@media (max-width: 640px) {
  .announce-dots { display: none; }
}

/* The strip sits under a fixed header, so an anchor landing on it would put
   its heading behind that header. */
#key-dates { scroll-margin-top: 90px; }
