:root {
  --red: #BC002D;
  --red-l: #D4344E;
  --red-d: #8B0022;
  --navy: #052151;
  --navy-l: #0A3478;
  --navy-d: #031430;
  --gold: #D4A017;
  --pink: #FFB7C5;
  --pink-l: #FFF0F3;
  --char: #1A1A2E;
  --slate: #6B7280;
  --soft: #F5F5F5;
  --w: #fff;
  --sh: 0 2px 15px rgba(0, 0, 0, .06);
  --sh-h: 0 10px 40px rgba(0, 0, 0, .12)
}

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0
}

html {
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
  font-size: 16px
}

body {
  font-family: 'Inter', 'Noto Sans JP', sans-serif;
  color: var(--char);
  background: var(--w)
}

/* Sideways scroll guard.
   ──────────────────────
   clip, not hidden. `overflow-x: hidden` on the root or body makes that element
   a scroll container, and a scroll container breaks `position: sticky` for
   everything inside it — this site has four (the site header, the dashboard
   header, the member portal header and the edit screen's anchor bar), and they
   would all have come unstuck. `clip` cuts the overflow off without creating a
   scroll container, so sticky keeps working. It is the same reasoning, and the
   same choice, as .sec further down this file.

   A guard, not a fix: it stops one stray wide element from making the whole
   page scroll sideways on a phone, which is disorienting and hard to trace. It
   does not make the element the right width, so anything found overflowing
   still wants fixing at the source. */
html,
body {
  overflow-x: clip
}

img {
  max-width: 100%;
  display: block
}

a {
  text-decoration: none;
  color: inherit
}

ul {
  list-style: none
}

button {
  cursor: pointer;
  font-family: inherit
}

.container {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 1.5rem
}

.flex {
  display: flex;
  gap: 1rem
}

.flex-b {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap
}

.g1 {
  gap: .25rem
}

.g2 {
  gap: .5rem
}

.g3 {
  gap: .75rem
}

.g4 {
  gap: 1rem
}

.g6 {
  gap: 1.5rem
}

.tc {
  text-align: center
}

.tw {
  color: var(--w)
}

.tr {
  color: var(--red)
}

.tn {
  color: var(--navy)
}

.ts {
  color: var(--slate)
}

.tg {
  color: var(--gold)
}

.txs {
  font-size: .75rem
}

.tsm {
  font-size: .875rem
}

.tlg {
  font-size: 1.125rem
}

.txl {
  font-size: 1.25rem
}

.t2xl {
  font-size: 1.5rem
}

.t3xl {
  font-size: 1.875rem
}

.t4xl {
  font-size: 2.25rem
}

.fw3 {
  font-weight: 300
}

.fw5 {
  font-weight: 500
}

.fw6 {
  font-weight: 600
}

.fw7 {
  font-weight: 700
}

.hide {
  display: none !important
}

.block {
  display: block
}

.ib {
  display: inline-block
}

.mx-a {
  margin-left: auto;
  margin-right: auto
}

.mt1 {
  margin-top: .5rem
}

.mt2 {
  margin-top: 1rem
}

.mt3 {
  margin-top: 1.5rem
}

.mt4 {
  margin-top: 2rem
}

.mb1 {
  margin-bottom: .5rem
}

.mb2 {
  margin-bottom: 1rem
}

.mb3 {
  margin-bottom: 1.5rem
}

.mb4 {
  margin-bottom: 2rem
}

.p2 {
  padding: 1rem
}

.p3 {
  padding: 1.5rem
}

.p4 {
  padding: 2rem
}

.py5 {
  padding: 4rem 0
}

.r {
  border-radius: 12px
}

.r-lg {
  border-radius: 16px
}

.r-xl {
  border-radius: 24px
}

.r-full {
  border-radius: 999px
}

.sh {
  box-shadow: var(--sh)
}

.sh-h {
  box-shadow: var(--sh-h)
}

.bg-w {
  background: var(--w)
}

/* Section divider. The page separates its sections by alternating background
   colour; two adjacent sections in the same colour therefore have no seam at
   all, which is what Study in Japan and Verified Members became when the
   former turned white. This is the hairline that stands in for the colour
   change. It goes on the lower section rather than between the two, so the
   rule travels with the section if the order ever changes, and so it inherits
   the .sec padding on both sides (4rem, 5rem above the tablet breakpoint) —
   the border lands halfway between the two blocks of content instead of
   crowding either one. */
.sec-bt {
  border-top: 1px solid rgba(226, 232, 240, .8)
}

.bg-n {
  background: var(--navy)
}

.bg-s {
  background: var(--soft)
}

.bg-pl {
  background: var(--pink-l)
}

.bg-r {
  background: var(--red)
}

.bg-r10 {
  background: rgba(188, 0, 45, .1)
}

.bg-g10 {
  background: rgba(22, 163, 74, .1)
}

.btn-p {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .75rem 1.5rem;
  background: var(--red);
  color: var(--w);
  font-weight: 600;
  border-radius: 12px;
  border: none;
  transition: all .3s
}

.btn-p:hover {
  background: var(--red-l);
  transform: translateY(-1px);
  box-shadow: var(--sh-h)
}

.btn-s {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .75rem 1.5rem;
  border: 2px solid var(--red);
  color: var(--red);
  font-weight: 600;
  border-radius: 12px;
  background: transparent;
  transition: all .3s
}

.btn-s:hover {
  background: var(--red);
  color: var(--w)
}

.btn-o {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .75rem 1.5rem;
  border: 2px solid var(--w);
  color: var(--w);
  font-weight: 600;
  border-radius: 12px;
  background: transparent;
  transition: all .3s
}

.btn-o:hover {
  background: var(--w);
  color: var(--red)
}

.btn-sm {
  padding: .5rem 1rem;
  font-size: .875rem
}

.btn-lg {
  padding: 1rem 2rem;
  font-size: 1.125rem
}

.badge {
  display: inline-block;
  padding: .25rem .75rem;
  border-radius: 999px;
  font-size: .75rem;
  font-weight: 600
}

/* Header */
/* Fixed 80px bar. `height`, not `min-height`, and the vertical padding is gone:
   the padding used to sit *outside* the row, so an 80px row inside .75rem of
   padding rendered a 104px header. Nothing inside can change this number now —
   whatever the logo or the nav do, they do it within 80px or they overflow,
   and the rules below make sure they do neither. */
#header {
  position: sticky;
  top: 0;
  z-index: 50;
  transition: all .3s;
  height: 5rem;
  padding: 0;
  background-color: #FFFFFF !important;
}

#header.scrolled {
  background-color: #FFFFFF !important;
  box-shadow: 0 2px 20px rgba(0, 0, 0, .06)
}

/* The header row is locked to one line at a fixed height.

   .flex-b, which this shares with a dozen other components, sets
   flex-wrap:wrap — so when the nav grew past the container the whole header
   row wrapped, dropping the nav onto a second line and leaving the logo
   floating in a header twice as tall. Overriding wrap here rather than on
   .flex-b keeps that change to the one place it is wrong.

   height:100% fills the bar exactly rather than setting it, so the row is
   centred in a height it cannot influence. The navbar is data-driven now — a
   superuser can add menu entries from Site Settings — so "however many items
   there are" has to be a case this layout survives, not one it is tuned for. */
#header>.container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
  gap: 1rem;
  height: 100%
}

/* The logo never shrinks, never moves and never grows: flex-shrink:0 stops the
   nav squeezing it, align-self:center pins it to the middle of the bar, and
   max-height:100% means the plate can never be taller than the bar it sits in
   however large an image an admin uploads. */
.logo-g {
  display: flex;
  align-items: center;
  align-self: center;
  gap: .75rem;
  flex-shrink: 0;
  max-height: 100%
}

.logo-svg {
  width: 44px;
  height: 44px
}

.logo-n {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-weight: 700;
  font-size: 1.25rem;
  color: var(--navy)
}

/* Nav */
/* The nav never wraps. It used to, below 1280px, on the reasoning that a
   second row kept every item clickable — but the row was being asked to hold
   ten items from 640px upwards, so in practice it wrapped to two and three
   lines across every tablet width, and the growing header is what pushed the
   logo out of place. The switch to the drawer now happens while the row still
   fits (see the 1100px block), which removes the situation rather than
   managing it.

   overflow-x is the safety net for the case that breakpoint cannot predict:
   the menu is editable from Site Settings, so a superuser can add entries
   until no width is enough. Scrolling the nav keeps the header one line tall
   and the logo where it is, which a wrap does not. */
#desk-nav {
  display: none;
  align-items: center;
  gap: .35rem;
  flex-wrap: nowrap;
  /* Centered in the space between the logo and the actions group, not
     clustered against the actions — flex:1 claims that whole middle span and
     justify-content:center centers the links within it, so "Become a Member"
     reads as its own destination on the right rather than the last item in
     the menu. min-width:0 still lets the row shrink below its content instead
     of pushing the logo or the actions out — see the overflow note below,
     which the shift to flex:1 does not change.

     overflow MUST stay visible. It was briefly `overflow-x: auto`, as a safety
     net for a menu long enough to outgrow the row — but per spec, when one axis
     is not `visible` the other computes to `auto`, which made this a scroll
     container, and a scroll container clips absolutely positioned descendants.
     Every .dd-m dropdown lives in here, so all three were being cut off at the
     height of the link row: the hover fired, the menu opened, and nothing was
     visible. A menu that opens beats a row that scrolls. */
  justify-content: center;
  flex: 1 1 auto;
  min-width: 0;
  overflow: visible
}

/* The account and call-to-action controls. Never shrinks: these are the two or
   three things on the bar a visitor is most likely to be reaching for, and a
   squeezed "Become a Member" that wraps to two lines is worse than a menu that
   scrolls. Hidden with the link row — below that width the drawer carries
   both. */
#nav-actions {
  display: none;
  align-items: center;
  gap: .5rem;
  flex-shrink: 0;
  white-space: nowrap
}

.nav-l {
  padding: .5rem .75rem;
  border-radius: 12px;
  font-size: .875rem;
  font-weight: 500;
  transition: all .2s;
  background: none;
  border: none;
  color: var(--char);
  /* A menu label must never break mid-word into two lines. */
  white-space: nowrap
}

/* Colour change only — no background pill. A filled box behind a menu item
   reads as a button rather than a link, and on the active item it made Home
   look permanently pressed. */
.nav-l:hover {
  color: var(--red)
}

.nav-l.ac {
  color: var(--red);
  font-weight: 600
}

.dd {
  position: relative
}

/* The panel is always laid out and only hidden — visibility+opacity rather than
   display:none, for two reasons. display cannot be transitioned, so the menu
   used to appear with a hard cut; and a display:none subtree is removed from
   the tab order, so :focus-within below could never have opened it.
   `visibility: hidden` still takes the panel out of the tab order and out of
   pointer events, so nothing is clickable while it is closed.

   z-index 60 sits above the rest of the header, which is itself a stacking
   context at z-index 50 — well clear of the hero, whose layers top out at 20.
   The panel is not clipped by anything: #desk-nav is explicitly overflow:visible
   for exactly this reason. */
.dd-m {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 220px;
  background: var(--w);
  border-radius: 16px;
  box-shadow: var(--sh-h);
  padding: .5rem 0;
  z-index: 60;
  border: 1px solid rgba(0, 0, 0, .06);
  visibility: hidden;
  opacity: 0;
  transform: translateY(-.35rem);
  transition: opacity .16s ease, transform .16s ease, visibility .16s
}

/* :focus-within is what makes the menu keyboard-operable — tab onto the parent
   and it opens, the same as hovering. `.show` is kept for anything that opens a
   menu by script. */
.dd:hover .dd-m,
.dd:focus-within .dd-m,
.dd-m.show {
  visibility: visible;
  opacity: 1;
  transform: none
}

.dd-m a {
  display: block;
  padding: .6rem 1rem;
  font-size: .875rem;
  color: var(--char);
  transition: all .2s
}

.dd-m a:hover {
  background: rgba(188, 0, 45, .05);
  color: var(--red)
}

/* {% empty %} placeholder — a dropdown whose group has no published pages.
   Deliberately not a link: there is nowhere for it to go. */
.dd-m .dd-empty,
#mob-menu .dd-empty {
  display: block;
  padding: .6rem 1rem;
  font-size: .875rem;
  font-style: italic;
  color: var(--slate)
}

.mob-tgl {
  display: block;
  padding: .5rem;
  font-size: 1.5rem;
  background: none;
  border: none;
  color: var(--char)
}

#mob-menu {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: var(--w);
  padding: 5rem 1.5rem 2rem;
  overflow-y: auto
}

#mob-menu a,
#mob-menu summary {
  display: block;
  padding: .75rem;
  font-size: 1.125rem;
  font-weight: 500;
  color: var(--char);
  border-radius: 12px;
  transition: all .2s
}

#mob-menu a:hover {
  color: var(--red)
}

#mob-menu summary {
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  cursor: pointer
}

#mob-menu summary::after {
  content: '▾';
  font-size: .75rem
}

#mob-menu details[open] summary::after {
  content: '▴'
}

#mob-menu .sub {
  padding-left: 1.5rem;
  border-left: 2px solid rgba(188, 0, 45, .2);
  margin: .25rem 0
}

#mob-menu .sub a {
  font-size: 1rem;
  padding: .5rem .75rem
}

/* Footer */
footer {
  background: var(--navy);
  color: var(--w);
  padding: 4rem 0 0
}

/* One column on a phone, and it always was — the footer stacks here rather than
   scrolling sideways. */
.f-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem
}

/* min-width:0 is the guard a grid needs and does not have by default: a grid
   item's automatic minimum size is its content's intrinsic width, so one long
   unbroken string — a pasted URL in a footer link, an address typed without
   spaces, a long email — makes its column wider than the screen and takes the
   whole page sideways with it. Nothing in the footer is that long today; this
   is what stops the next thing an editor types from being. */
.f-grid>* {
  min-width: 0
}

footer .f-links a,
footer .tsm,
footer .f-h {
  overflow-wrap: anywhere
}

/* A middle step. The footer went straight from one column to four at 1024px,
   so every tablet got the phone layout: four stacked blocks and a very tall
   footer to scroll past. Two columns from 640px up uses the width that is
   there without cramping four link lists into it. */
@media (min-width: 640px) and (max-width: 1023.98px) {
  .f-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2rem
  }
}

.f-h {
  font-weight: 600;
  margin-bottom: 1rem;
  font-size: .8125rem;
  text-transform: uppercase;
  letter-spacing: .05em
}

.f-links a {
  display: block;
  color: rgba(255, 255, 255, .6);
  font-size: .875rem;
  margin-bottom: .5rem;
  transition: color .2s
}

.f-links a:hover {
  color: var(--gold)
}

/* wrap, because the row's width is not ours to predict: the icons are built
   from whatever social links Site Settings holds, and seven 36px circles plus
   their gaps are wider than a 320px phone's content column. Without this they
   ran off the side of the footer instead of moving to a second line. */
.soc {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem
}

.soc-i {
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .2);
  color: var(--w);
  font-size: .75rem;
  font-weight: 700;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .3);
  transition: transform .25s, background .25s, border-color .25s, box-shadow .25s
}

.soc-svg {
  width: 18px;
  height: 18px
}

.soc-i:hover {
  color: var(--w);
  transform: scale(1.1);
  box-shadow: 0 8px 20px rgba(0, 0, 0, .38)
}

/* Official brand colors. Each network keeps its own mark on hover rather than
   turning red — a Facebook button that goes crimson reads as a broken link. */
.soc-facebook {
  background: #1877F2;
  border-color: #1877F2
}

.soc-whatsapp {
  background: #25D366;
  border-color: #25D366
}

.soc-instagram {
  background: radial-gradient(circle at 30% 107%, #fdf497 0%, #fdf497 5%, #fd5949 45%, #d6249f 60%, #285AEB 90%);
  border-color: #d6249f
}

.soc-youtube {
  background: #FF0000;
  border-color: #FF0000
}

.soc-twitter {
  background: #000;
  border-color: #000
}

.soc-tiktok {
  background: #000;
  border-color: #000
}

.soc-viber {
  background: #7360F2;
  border-color: #7360F2
}

.f-bot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
  padding: 1.5rem 0;
  margin-top: 2rem;
  border-top: 1px solid rgba(255, 255, 255, .1);
  font-size: .8125rem;
  color: rgba(255, 255, 255, .4);
  /* The rights line carries the full association name — 60-odd characters
     that have to be allowed to break on a phone rather than set the footer's
     width. */
  text-align: center;
  overflow-wrap: anywhere
}

/* Hero */
/* Column, not row: the hero stacks its copy (or the rotating slide deck) above
   the stat band, and both have to stay centred as one group. */
.hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  overflow: hidden;
  ;
}

.hero-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover
}

.hero-ol {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(5, 33, 81, .85), rgba(5, 33, 81, .7), rgba(5, 33, 81, .9))
}

.hero-c {
  position: relative;
  z-index: 10;
  padding: 8rem 0 0
}

/* Stat band. Its own layer below the copy so it survives a slide change —
   re-rendering it per slide would restart the count-up on every transition. */
.hero-foot {
  position: relative;
  z-index: 10;
  padding-bottom: 4rem
}

/* ---------------------------------------------------------------------------
   Hero slider
   ---------------------------------------------------------------------------
   Slides are stacked in one grid cell and cross-faded, so the deck is as tall
   as its longest slide and nothing jumps when it advances.

   Neither .hero-slider nor .hero-slide is positioned, on purpose: each slide's
   .hero-bg and .hero-ol are position:absolute and resolve against .hero, so the
   artwork covers the full viewport height rather than only the copy block.

   NOTE: the arrow and dot rules below were rebuilt by measuring a screenshot of
   the original after they were deleted in error — 44px discs at a 16px inset,
   navy at 35%, an 8px dot row whose active pill is 28px of --gold. The deck's
   own behaviour (grid stacking, the .8s cross-fade) is the original code.
--------------------------------------------------------------------------- */
.hero-slides {
  display: grid;
  /* align-items:end so every slide's copy block shares a bottom edge. Slides
     stack in one grid cell and their copy differs in height, so top-aligning
     them moved the CTA row between slides — a click target that shifts under
     the cursor. The headline shifts instead, which is not clickable. */
  align-items: end
}

.hero-slide {
  grid-area: 1 / 1
}

/* The three layers fade individually rather than the slide as a whole. An
   opacity on .hero-slide would make it a stacking context and trap .hero-c
   inside it — and #sakura-c (z-index 5) has to sit *between* the artwork and
   the headline, which is impossible once the two are in one context.
   visibility keeps hidden slides out of the tab order and off the pointer,
   while still holding their box so the grid cell height never jumps. */
.hero-slide>* {
  opacity: 0;
  visibility: hidden;
  transition: opacity .8s ease, visibility 0s linear .8s
}

.hero-slide.is-active>* {
  opacity: 1;
  visibility: visible;
  transition: opacity .8s ease
}

.hero-slider .hero-bg {
  z-index: 1
}

.hero-slider .hero-ol {
  z-index: 2
}

.hero-slider .hero-c {
  z-index: 10
}

/* Arrows. Hidden by default — on a phone they would sit on top of the copy,
   and swipe plus the dots cover that case. Shown from 640px up, below. */
.hero-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 20;
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  font-size: 1.5rem;
  line-height: 1;
  color: #fff;
  cursor: pointer;
  background: rgba(5, 33, 81, .35);
  border: 1px solid rgba(255, 255, 255, .25);
  border-radius: 50%;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background .25s ease, border-color .25s ease
}

.hero-nav:hover {
  background: rgba(188, 0, 45, .8);
  border-color: rgba(255, 255, 255, .5)
}

.hero-nav:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px
}

.hero-prev {
  left: 16px
}

.hero-next {
  right: 16px
}

.hero-dots {
  position: relative;
  z-index: 20;
  display: flex;
  justify-content: center;
  gap: .5rem;
  margin-top: 2rem
}

.hero-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  cursor: pointer;
  background: rgba(255, 255, 255, .35);
  border: 0;
  border-radius: 999px;
  transition: width .3s ease, background .3s ease
}

.hero-dot.is-active {
  width: 28px;
  background: var(--gold)
}

.hero-dot:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px
}

/* Honour a reduced-motion preference: the deck still advances, it just cuts
   rather than fades. */
@media(prefers-reduced-motion:reduce) {

  .hero-slide>*,
  .hero-slide.is-active>* {
    transition: none
  }

  .hero-dot,
  .hero-nav {
    transition: none
  }
}


.hero-t {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 2.25rem;
  font-weight: 700;
  color: var(--w);
  line-height: 1.2
}

.hero-sub {
  color: rgba(255, 255, 255, .7);
  font-size: 1rem;
  max-width: 42rem;
  margin: 1.5rem auto 0;
  line-height: 1.6
}

.hero-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  margin-top: 2rem
}

.hero-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem;
  margin-top: 4rem;
  max-width: 48rem;
  margin-left: auto;
  margin-right: auto
}

.stat-i {
  font-size: 1.25rem;
  margin-bottom: .5rem;
  opacity: .7
}

.stat-n {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.5rem;
  font-weight: 300;
  color: var(--gold)
}

.stat-l {
  font-size: .75rem;
  color: rgba(255, 255, 255, .6);
  margin-top: .25rem
}

.scroll-ind {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  color: rgba(255, 255, 255, .4);
  font-size: 1.5rem;
  animation: bounce 2s infinite
}

@keyframes bounce {

  0%,
  100% {
    transform: translateX(-50%) translateY(0)
  }

  50% {
    transform: translateX(-50%) translateY(10px)
  }
}

/* Sections */
/* overflow-x:clip, not hidden: the .anim entrance transforms park their
   elements off the left/right edge until the IntersectionObserver adds .vis,
   which was adding a horizontal scrollbar to the whole page below ~1024px.
   (The partners marquee used to be the other offender here; it is a grid now
   and no longer overflows anything.) `clip` contains them without making the
   section a scroll container, so overflow-y stays visible and the hover lifts
   on cards are not cut off — which plain `hidden` would do. */
.sec {
  padding: 4rem 0;
  overflow-x: clip
}

/* The section tag: a short red rule, then the label.
 *
 * One definition for every section kicker on the site, so "WHAT WE OFFER",
 * "EXECUTIVE LEADERSHIP" and "ABOUT JEPAN" cannot drift apart in size, weight
 * or tracking — which is what they had done, across four separate rules.
 *
 * inline-flex, not a flex row wrapper: the tag then centres or left-aligns
 * from whatever its parent already does, so the same markup serves the centred
 * headings and the left-aligned About block with no alignment modifier.
 *
 * .evt-head-badge shares the definition rather than restating it. It was a
 * rounded pill; a second rule that had to be kept in step by hand is the
 * problem this consolidation exists to remove.
 */
.sec-label,
.evt-head-badge {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--red);
  margin-bottom: .75rem
}

.sec-label::before,
.evt-head-badge::before {
  content: "";
  flex: none;
  width: 2rem;
  height: 2px;
  background: var(--red)
}

/* Dark grounds. The brand red is ~1.9:1 on the navy sections, which is
 * unreadable, so these lift only the two colours and leave the structure,
 * size, weight and tracking identical.
 */
.sec-label.on-dark {
  color: #ff8d96
}

.sec-label.on-dark::before {
  background: #e63946
}

.sec-h {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 2rem;
  font-weight: 700;
  color: var(--navy);
  line-height: 1.25
}

.sec-sub {
  font-size: 1.0625rem;
  max-width: 36rem;
  margin: .75rem auto 0;
  color: var(--slate)
}

/* Hero Pages */
.pg-hero {
  position: relative;
  padding: 3.5rem 0 2.5rem;
  /* less vertical space for inner pages */
  background: linear-gradient(180deg, rgba(250, 250, 250, 1), rgba(245, 247, 250, 1));
  overflow: hidden;
  color: var(--char);
}

/* disable the dark dotted overlay used by full-screen hero */
.pg-hero::before {
  content: none;
}

.pg-hero .container {
  position: relative;
  z-index: 1
}

/* make page hero headings use the site text colors (dark on light background) */
.pg-hero .hero-t {
  color: var(--navy);
}

.pg-hero .hero-sub,
.pg-hero p {
  color: var(--slate);
}

.pg-hero .sec-label {
  color: var(--red);
}


/* Split */
.splt {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  align-items: center
}

.splt-img {
  position: relative
}

.splt-img img {
  border-radius: 24px;
  width: 100%;
  height: 350px;
  object-fit: cover
}

.float-c {
  position: absolute;
  bottom: -1rem;
  left: -1rem;
  background: var(--w);
  padding: 1rem 1.25rem;
  border-radius: 16px;
  box-shadow: var(--sh);
  max-width: 200px
}

.fact-g {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .75rem;
  margin: 1.5rem 0
}

.fact-c {
  background: var(--soft);
  padding: 1rem;
  border-radius: 12px
}

.fact-n {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-weight: 700;
  font-size: 1.25rem;
  color: var(--red)
}

.fact-l {
  font-size: .75rem;
  color: var(--slate);
  margin-top: .25rem
}

/* Pillars */
.pil-g {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  position: relative;
  z-index: 1
}

.pil-c {
  padding: 1.5rem;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 24px;
  transition: all .5s;
  cursor: pointer
}

.pil-c:hover {
  background: var(--red);
  border-color: var(--red)
}

.pil-n {
  font-family: monospace;
  font-size: .75rem;
  color: rgba(255, 255, 255, .3);
  letter-spacing: .1em;
  margin-bottom: .5rem
}

.pil-ic {
  font-size: 1.5rem;
  margin-bottom: .5rem
}

.pil-c h3 {
  color: var(--w);
  font-weight: 700;
  font-size: 1.125rem;
  margin-bottom: .5rem
}

.pil-c p {
  color: rgba(255, 255, 255, .6);
  font-size: .875rem;
  line-height: 1.6
}

/* Tabs */
.tab-btns {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem;
  margin-bottom: 2rem
}

/* The border is what makes an inactive pill visible. These sat on the pink
   Study in Japan panel and on the white blog listing, where a white pill with
   `border:none` had nothing to separate it from the page — the blog filters
   were already invisible before that section turned white too. The border is
   kept (recoloured, not removed) in the active and hover states so the pill
   does not change size when it lights up. */
.tab-b {
  padding: .5rem 1rem;
  border-radius: 999px;
  font-size: .8125rem;
  font-weight: 500;
  background: var(--w);
  color: var(--slate);
  border: 1px solid rgba(226, 232, 240, .8);
  box-shadow: 0 1px 2px rgba(2, 6, 23, .05);
  transition: all .3s
}

.tab-b.ac,
.tab-b:hover {
  background: var(--red);
  color: var(--w);
  border-color: var(--red);
  box-shadow: 0 4px 12px rgba(188, 0, 45, .3)
}

.tab-p {
  animation: fadeIn .3s
}

.tab-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .75rem;
  margin: 1.5rem 0
}

/* Same reason as .tab-b: a white tile on a white section needs an edge, and a
   .04 alpha shadow is not one. */
.tab-stat {
  display: flex;
  align-items: center;
  gap: .5rem;
  background: var(--w);
  padding: .75rem;
  border-radius: 12px;
  border: 1px solid rgba(226, 232, 240, .8);
  font-size: .8125rem;
  font-weight: 500;
  box-shadow: 0 1px 2px rgba(2, 6, 23, .05)
}

@keyframes fadeIn {
  from {
    opacity: 0
  }

  to {
    opacity: 1
  }
}

/* Cards */
.mem-g {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem
}

/* Column, not a block: the card stretches to fill its grid cell so a row of
   cards shares one bottom edge no matter how long the names are. Padding moved
   off the card and onto .mem-c-body — the logo frame is full-bleed. */
.mem-c {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--w);
  border: 1px solid rgba(226, 232, 240, .8);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(2, 6, 23, .05);
  transition: all .3s
}

/* The lift and the deeper shadow are restated further down the file, where the
   shared grid-card hover lives — see the note there. */
.mem-c:hover {
  box-shadow: var(--sh-h)
}

/* Fixed-ratio frame. Without it the <img> renders at its intrinsic size and
   overflows the card, which is what pushed the name into the next row.

   The top corners are rounded here as well as clipped by .mem-c's own
   overflow:hidden. That is deliberate belt-and-braces: the media box is the
   only full-bleed element in the card, so it is the one that breaks the card's
   outline if the overflow rule is ever relaxed to let something (a tooltip, a
   dropdown) escape the card. */
.mem-c-media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  flex: none;
  background: #f8fafc;
  border-radius: 16px 16px 0 0;
  overflow: hidden
}

/* cover, full-bleed, no padding — the image fills the frame edge to edge.
   TRADE-OFF, chosen deliberately: ImageFallbackMixin.image is the consultancy
   *logo* (`cover` on the model is the separate profile banner), and cover crops
   whatever does not fit the 16/10 frame, so a tall or very wide wordmark loses
   its edges. Accepted because the frame reads as a photograph in the card
   design and most uploads are photographic. If cropped logos become a problem,
   the fix is `object-fit: contain` plus padding here — not a change to the
   frame or the card. */
.mem-c-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  padding: 0
}

/* Verified tag, floated over the logo frame. The blur is what keeps it legible
   over a logo of any colour; the solid-ish white behind it is the fallback for
   browsers without backdrop-filter, so it never becomes red-on-red. */
.mem-c-tag {
  position: absolute;
  top: .75rem;
  left: .75rem;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .25rem .55rem;
  border-radius: 8px;
  background: rgba(255, 255, 255, .9);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, .5);
  box-shadow: 0 1px 2px rgba(2, 6, 23, .08);
  color: var(--red);
  font-size: .625rem;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  line-height: 1.5
}

.mem-c-tag::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--red)
}

/* space-between, so the "View Details" row sits on the card's bottom edge
   whether or not the member has a location line above it. */
.mem-c-body {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  flex: 1 1 auto;
  padding: 1.25rem;
  min-width: 0
}

.mem-c .mem-c-meta {
  display: flex;
  align-items: center;
  gap: .375rem;
  margin: 0 0 .5rem;
  min-width: 0;
  font-size: .75rem;
  font-weight: 500;
  color: var(--slate)
}

.mem-c .mem-c-meta svg {
  flex: none;
  width: 14px;
  height: 14px;
  color: #ef4444
}

/* min-width:0 on the parents plus the ellipsis here is what stops a long
   unbroken name or district from widening the grid cell and colliding with its
   neighbour. */
.mem-c .mem-c-meta span,
.mem-c .mem-c-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

.mem-c .mem-c-name {
  margin: 0;
  font-weight: 700;
  color: var(--navy);
  font-size: 1rem;
  line-height: 1.35;
  transition: color .3s
}

.mem-c:hover .mem-c-name {
  color: var(--red)
}

.mem-c-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid #f1f5f9;
  font-size: .75rem;
  font-weight: 600;
  color: #475569;
  transition: color .3s
}

.mem-c:hover .mem-c-foot {
  color: var(--red)
}

.mem-c-foot .arw {
  transition: transform .3s
}

.mem-c:hover .mem-c-foot .arw {
  transform: translateX(4px)
}

.mem-logo {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  overflow: hidden;
  background: var(--soft)
}

.mem-logo img {
  width: 100%;
  height: 100%;
  object-fit: cover
}

.mem-st {
  display: inline-block;
  margin-top: .5rem;
  font-size: .6875rem;
  font-weight: 600;
  padding: .2rem .5rem;
  border-radius: 999px
}

.st-a {
  background: rgba(22, 163, 74, .1);
  color: #16a34a
}

.st-p {
  background: rgba(217, 119, 6, .1);
  color: #d97706
}

/* Mid-workflow state — a translation request that has been picked up but not
   yet delivered. Blue reads as "moving" beside the amber pending pill. */
.st-i {
  background: rgba(37, 99, 235, .1);
  color: #2563eb
}

/* Closed unfavourably — rejected or suspended. Distinct from amber "pending",
   which would wrongly suggest the application is still in the queue. */
.st-x {
  background: rgba(188, 0, 45, .1);
  color: #bc002d
}

.st-inactive {
  background: rgba(239, 68, 68, .12);
  color: #dc2626;
  border: 1px solid rgba(220, 38, 38, .2);
}

.evt-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 42rem;
  margin: 0 auto
}

.evt-c {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1rem;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .06);
  border-radius: 24px;
  padding: 1.25rem;
  transition: all .3s
}

.evt-c:hover {
  transform: translateY(-2px);
  box-shadow: var(--sh-h)
}

.evt-c h3 {
  font-weight: 700;
  color: var(--navy);
  font-size: 1.0625rem
}

.evt-c:hover h3 {
  color: var(--red)
}

.evt-date {
  width: 64px;
  height: 64px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--red);
  color: var(--w);
  border-radius: 16px;
  flex-shrink: 0
}

.evt-date span {
  font-size: .6875rem;
  text-transform: uppercase;
  font-weight: 500
}

.evt-date strong {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1
}

/* ---------------------------------------------------------------------------
   Featured event banner — the headline card above the compact .evt-list.
   Single column on phones; the media and the detail column sit side by side
   from 1024px, which is where there is room for a 380px image beside text.
--------------------------------------------------------------------------- */
.evt-f {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.75rem;
  align-items: center;
  max-width: 72rem;
  margin: 0 auto 2.5rem;
  padding: 1.5rem;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .06);
  border-radius: 28px;
  box-shadow: 0 18px 45px rgba(5, 33, 81, .09);
  transition: box-shadow .3s, transform .3s
}

.evt-f:hover {
  transform: translateY(-3px);
  box-shadow: 0 26px 60px rgba(5, 33, 81, .14)
}

.evt-f-media {
  position: relative;
  border-radius: 20px;
  overflow: hidden;
  background: var(--soft);
  aspect-ratio: 4 / 3
}

.evt-f-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .7s ease
}

.evt-f:hover .evt-f-media img {
  transform: scale(1.05)
}

.evt-f-badge {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 1;
  padding: .3rem .75rem;
  border-radius: 999px;
  background: var(--red);
  color: var(--w);
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .18)
}

.evt-f-badge-past {
  background: var(--slate)
}

.evt-f-body {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1.25rem;
  min-width: 0
}

.evt-f-date {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin: 0 0 .5rem;
  color: var(--red);
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase
}

.evt-f-date svg {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0
}

.evt-f-t {
  margin: 0 0 .75rem;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1.25;
  color: var(--navy);
  overflow-wrap: anywhere
}

.evt-f-sum {
  margin: 0 0 1.25rem;
  color: var(--slate);
  font-size: .9375rem;
  line-height: 1.6;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden
}

.evt-f-loc {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .85rem;
  border: 1px solid rgba(0, 0, 0, .06);
  border-radius: 18px;
  background: var(--soft)
}

.evt-f-loc-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  flex-shrink: 0;
  border-radius: 14px;
  background: rgba(188, 0, 45, .1);
  font-size: 1.1rem
}

.evt-f-loc-tx {
  min-width: 0
}

.evt-f-loc-k {
  display: block;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #94a3b8
}

.evt-f-loc-v {
  display: block;
  font-size: .875rem;
  font-weight: 700;
  color: var(--char, var(--navy));
  overflow-wrap: anywhere
}

.evt-f-act {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  padding-top: 1.1rem;
  border-top: 1px solid rgba(0, 0, 0, .07)
}

.evt-f-btn {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .8rem 1.5rem;
  border-radius: 14px;
  background: var(--navy);
  color: var(--w);
  font-size: .875rem;
  font-weight: 700;
  text-decoration: none;
  box-shadow: 0 4px 14px rgba(5, 33, 81, .18);
  transition: background .25s, transform .25s
}

.evt-f-btn:hover {
  background: var(--red);
  color: var(--w);
  transform: translateY(-2px)
}

.evt-f-stat {
  text-align: right
}

.evt-f-stat-v {
  margin: 0;
  font-size: 1rem;
  font-weight: 800;
  color: var(--navy)
}

.evt-f-stat-k {
  margin: 0;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #94a3b8
}

/* ---------------------------------------------------------------------------
   Two-up event grid — the homepage strip. One card per row on phones, two from
   1024px; inside each card the image sits beside the text from 640px up.
--------------------------------------------------------------------------- */
.evtg-g {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.75rem;
  max-width: 72rem;
  margin: 0 auto
}

/* The AOS wrapper around each card is the real grid item, so it has to pass
   the cell's full height through — otherwise two cards in a row only match
   heights when their text happens to match. */
.evtg-g>div {
  display: flex;
  min-width: 0
}

.evtg-c {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 1.15rem;
  padding: 1.15rem;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .06);
  border-radius: 24px;
  box-shadow: 0 6px 20px rgba(5, 33, 81, .06);
  text-decoration: none;
  transition: box-shadow .3s, transform .3s
}

.evtg-c:hover {
  transform: translateY(-3px);
  box-shadow: 0 18px 40px rgba(5, 33, 81, .13)
}

.evtg-media {
  position: relative;
  flex: none;
  border-radius: 18px;
  overflow: hidden;
  background: var(--soft);
  aspect-ratio: 16 / 10
}

.evtg-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s ease
}

.evtg-c:hover .evtg-media img {
  transform: scale(1.05)
}

.evtg-chip {
  position: absolute;
  top: .75rem;
  left: .75rem;
  padding: .25rem .6rem;
  border-radius: 10px;
  background: var(--red);
  color: var(--w);
  font-size: .75rem;
  font-weight: 800;
  letter-spacing: .02em;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .18)
}

.evtg-body {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: .9rem;
  min-width: 0
}

.evtg-t {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--navy);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  transition: color .25s
}

.evtg-c:hover .evtg-t {
  color: var(--red)
}

.evtg-sum {
  margin: .5rem 0 0;
  font-size: .8125rem;
  line-height: 1.6;
  color: var(--slate);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden
}

.evtg-loc {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin: .65rem 0 0;
  font-size: .8125rem;
  color: var(--slate);
  min-width: 0
}

.evtg-loc-v {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

.evtg-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .5rem;
  padding-top: .75rem;
  border-top: 1px solid rgba(0, 0, 0, .07)
}

.evtg-more {
  font-size: .8125rem;
  font-weight: 700;
  color: var(--navy);
  transition: color .25s
}

.evtg-c:hover .evtg-more {
  color: var(--red)
}

.evtg-time {
  font-size: .75rem;
  color: #94a3b8;
  font-weight: 600
}

/* Empty state spans the full grid rather than sitting in column one. */
.evtg-empty {
  grid-column: 1 / -1;
  padding: 2.5rem 1rem;
  text-align: center;
  border: 1px dashed rgba(0, 0, 0, .14);
  border-radius: 24px;
  background: var(--w);
  color: var(--slate);
  font-size: .9375rem
}

@media(min-width:640px) {
  .evtg-c {
    flex-direction: row
  }

  .evtg-media {
    width: 40%;
    aspect-ratio: auto;
    align-self: stretch
  }
}

@media(min-width:1024px) {
  .evtg-g {
    grid-template-columns: repeat(2, 1fr)
  }
}

@media(prefers-reduced-motion:reduce) {

  .evtg-c,
  .evtg-media img {
    transition: none
  }

  .evtg-c:hover,
  .evtg-c:hover .evtg-media img {
    transform: none
  }
}

/* ---------------------------------------------------------------------------
   Events listing hero — centred navy band with a dot field.
--------------------------------------------------------------------------- */
.hero-band {
  position: relative;
  padding: 3.5rem 0 3rem;
  background: var(--navy);
  color: var(--w);
  overflow: hidden
}

.hero-band-dots {
  position: absolute;
  inset: 0;
  opacity: .15;
  background-image: radial-gradient(#fff 1px, transparent 1px);
  background-size: 16px 16px
}

.hero-band-in {
  position: relative;
  z-index: 1;
  text-align: center
}

.hero-band-badge {
  display: inline-block;
  margin-bottom: .9rem;
  padding: .4rem 1rem;
  border-radius: 999px;
  background: rgba(188, 0, 45, .22);
  border: 1px solid rgba(188, 0, 45, .45);
  color: #ff8ba3;
  font-size: .6875rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase
}

.hero-band-t {
  margin: 0;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 2rem;
  font-weight: 800;
  letter-spacing: -.01em;
  line-height: 1.15;
  color: var(--w)
}

.hero-band-sub {
  max-width: 40rem;
  margin: .85rem auto 0;
  color: rgba(255, 255, 255, .78);
  font-size: .9375rem;
  line-height: 1.7
}

@media(min-width:640px) {
  .hero-band {
    padding: 4.5rem 0 3.75rem
  }

  .hero-band-t {
    font-size: 3rem
  }
}

/* Date tag on the featured banner's image, matching the tile grid's badge. */
.evt-f-daytag {
  position: absolute;
  top: 1rem;
  right: 1rem;
  z-index: 1;
  min-width: 3.1rem;
  padding: .35rem .5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  border-radius: 14px;
  background: rgba(255, 255, 255, .92);
  border: 1px solid rgba(255, 255, 255, .5);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px)
}

.evt-f-daytag span {
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--red)
}

.evt-f-daytag strong {
  font-size: 1.25rem;
  font-weight: 800;
  line-height: 1;
  color: var(--navy)
}

/* ---------------------------------------------------------------------------
   Event detail page — hero, two-column body, sticky sidebar.
--------------------------------------------------------------------------- */
.evd-hero {
  position: relative;
  padding: 4rem 0 3rem;
  background-color: var(--navy);
  background-size: cover;
  background-position: center;
  color: var(--w);
  overflow: hidden
}

/* Fixed scrim rather than a translucent tint on the image: the headline has to
   stay readable over a photograph nobody has previewed. */
.evd-hero-scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(5, 33, 81, .82), rgba(5, 33, 81, .94)),
    radial-gradient(rgba(255, 255, 255, .10) 1px, transparent 1px);
  background-size: auto, 16px 16px;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px)
}

.evd-hero-in {
  position: relative;
  z-index: 1
}

.evd-back {
  display: inline-block;
  margin-bottom: 1.5rem;
  color: rgba(255, 255, 255, .72);
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  transition: color .2s
}

.evd-back:hover {
  color: var(--w)
}

.evd-hero-badge {
  display: inline-block;
  padding: .3rem .85rem;
  border-radius: 999px;
  background: var(--red);
  color: var(--w);
  font-size: .625rem;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .25)
}

.evd-hero-badge-done {
  background: rgba(255, 255, 255, .2)
}

.evd-hero-t {
  max-width: 48rem;
  margin: 1rem 0 .75rem;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.85rem;
  font-weight: 800;
  line-height: 1.15;
  color: var(--w);
  overflow-wrap: anywhere
}

.evd-hero-sub {
  max-width: 44rem;
  margin: 0;
  color: rgba(255, 255, 255, .8);
  font-size: .9375rem;
  line-height: 1.7
}

.evd-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  align-items: start
}

.evd-main {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
  min-width: 0
}

.evd-cover {
  aspect-ratio: 16 / 9;
  border-radius: 24px;
  overflow: hidden;
  background: var(--soft);
  box-shadow: 0 20px 50px rgba(5, 33, 81, .16)
}

.evd-cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover
}

.evd-panel {
  padding: 1.75rem;
  border-radius: 24px;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .06);
  box-shadow: 0 4px 18px rgba(5, 33, 81, .05)
}

.evd-panel-t {
  margin: 0 0 1.15rem;
  padding-bottom: .85rem;
  border-bottom: 1px solid rgba(0, 0, 0, .07);
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.35rem;
  font-weight: 800;
  color: var(--navy)
}

.evd-panel-sub {
  margin: -.5rem 0 1.25rem;
  font-size: .8125rem;
  color: var(--slate)
}

.evd-prose {
  color: #334155;
  font-size: .9375rem;
  line-height: 1.85
}

.evd-prose p {
  margin: 0 0 1rem
}

.evd-prose p:last-child {
  margin-bottom: 0
}

.evd-prose ul,
.evd-prose ol {
  margin: 0 0 1rem;
  padding-left: 1.25rem
}

.evd-prose li {
  margin-bottom: .35rem
}

.evd-prose h2,
.evd-prose h3 {
  margin: 1.5rem 0 .6rem;
  color: var(--navy);
  font-weight: 700
}

.evd-prose img {
  max-width: 100%;
  height: auto;
  border-radius: 14px
}

/* Reserve-a-seat form. */
.evd-form {
  display: flex;
  flex-direction: column;
  gap: 1rem
}

.evd-form-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem
}

.evd-field {
  display: flex;
  flex-direction: column;
  min-width: 0
}

.evd-lb {
  margin-bottom: .35rem;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #475569
}

.evd-opt {
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: #94a3b8
}

.evd-form .errorlist {
  list-style: none;
  margin: 0 0 .35rem;
  padding: 0;
  font-size: .75rem;
  font-weight: 600;
  color: var(--red)
}

.evd-submit {
  align-self: flex-start;
  margin-top: .25rem;
  padding: .9rem 1.75rem;
  border: 0;
  border-radius: 14px;
  cursor: pointer;
  background: var(--navy);
  color: var(--w);
  font-family: inherit;
  font-size: .875rem;
  font-weight: 700;
  box-shadow: 0 8px 20px rgba(5, 33, 81, .25);
  transition: background .25s, transform .25s
}

.evd-submit:hover {
  background: var(--red);
  transform: translateY(-2px)
}

/* Share row. */
.evd-share {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem
}

.evd-share-lb {
  margin-right: .35rem;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--slate)
}

.evd-share-b {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border-radius: 999px;
  border: 1px solid rgba(0, 0, 0, .1);
  background: var(--w);
  color: var(--slate);
  font-family: inherit;
  font-size: .8125rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  transition: background .2s, color .2s, border-color .2s
}

.evd-share-b:hover {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--w)
}

/* Sidebar. */
.evd-side {
  position: sticky;
  top: 7.5rem;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1.25rem
}

.evd-card {
  padding: 1.5rem;
  border-radius: 24px;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .06);
  box-shadow: 0 14px 40px rgba(5, 33, 81, .1)
}

.evd-date {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: .9rem;
  margin-bottom: 1.25rem;
  border-radius: 18px;
  background: rgba(188, 0, 45, .06);
  border: 1px solid rgba(188, 0, 45, .16)
}

.evd-date-b {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 3.4rem;
  height: 3.4rem;
  flex: none;
  border-radius: 16px;
  background: var(--red);
  color: var(--w);
  box-shadow: 0 6px 16px rgba(188, 0, 45, .3)
}

.evd-date-b span {
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  line-height: 1
}

.evd-date-b strong {
  font-size: 1.4rem;
  font-weight: 800;
  line-height: 1.1
}

.evd-date-x {
  min-width: 0
}

.evd-k {
  display: block;
  margin: 0;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #94a3b8
}

.evd-v {
  display: block;
  margin: .15rem 0 0;
  font-size: .875rem;
  font-weight: 700;
  color: var(--navy);
  overflow-wrap: anywhere
}

.evd-v-open {
  color: #16a34a
}

.evd-vs {
  margin: .2rem 0 0;
  font-size: .75rem;
  color: var(--slate)
}

.evd-facts {
  list-style: none;
  margin: 0 0 1.25rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1rem
}

.evd-facts li {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  min-width: 0
}

.evd-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  flex: none;
  border-radius: 12px;
  background: var(--soft);
  font-size: .9375rem
}

.evd-cta {
  display: block;
  width: 100%;
  padding: .95rem 1rem;
  border-radius: 16px;
  text-align: center;
  background: var(--navy);
  color: var(--w);
  font-size: .875rem;
  font-weight: 700;
  box-shadow: 0 8px 20px rgba(5, 33, 81, .25);
  transition: background .25s, transform .25s
}

.evd-cta:hover {
  background: var(--red);
  color: var(--w);
  transform: translateY(-2px)
}

.evd-cta-ghost {
  margin-top: .65rem;
  background: transparent;
  color: var(--navy);
  border: 1px solid rgba(0, 0, 0, .12);
  box-shadow: none
}

.evd-cta-ghost:hover {
  background: var(--soft);
  color: var(--navy)
}

@media(min-width:640px) {
  .evd-hero {
    padding: 5rem 0 3.5rem
  }

  .evd-hero-t {
    font-size: 2.5rem
  }

  .evd-panel {
    padding: 2.25rem
  }

  .evd-form-row {
    grid-template-columns: 1fr 1fr
  }
}

@media(min-width:1024px) {
  .evd-grid {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 2.5rem
  }

  
  
/* Sticky only where there is a second column for it to sit beside. Stacked
     on narrow screens a sticky card pins itself over the content below it. */
  }

@media(prefers-reduced-motion:reduce) {

  .evd-cta,
  .evd-submit {
    transition: none
  }

  .evd-cta:hover,
  .evd-submit:hover {
    transform: none
  }
}

/* ---------------------------------------------------------------------------
   Event tiles — the three-up grid on the Events page.
   One column on phones, two from 768px, three from 1024px.
--------------------------------------------------------------------------- */
.evt-tg {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  max-width: 76rem;
  margin: 0 auto
}

/* The AOS wrapper around each tile is the real grid item, so it has to pass
   the cell's full height through or tiles only match heights by accident. */
.evt-tg>div {
  display: flex;
  min-width: 0
}

.evt-tile {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  height: 100%;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .07);
  border-radius: 20px;
  overflow: hidden;
  text-decoration: none;
  box-shadow: 0 4px 16px rgba(5, 33, 81, .06);
  transition: box-shadow .3s, transform .3s
}

.evt-tile:hover {
  transform: translateY(-6px);
  box-shadow: 0 22px 48px rgba(5, 33, 81, .16)
}

.evt-tile-media {
  position: relative;
  flex: none;
  aspect-ratio: 16 / 10;
  background: var(--soft);
  overflow: hidden
}

.evt-tile-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s ease
}

.evt-tile:hover .evt-tile-media img {
  transform: scale(1.05)
}

.evt-tile-status {
  position: absolute;
  top: 1rem;
  left: 1rem;
  padding: .3rem .7rem;
  border-radius: 999px;
  background: var(--navy);
  color: var(--w);
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .22)
}

/* Today is the one worth interrupting for; a finished event is muted so the
   archive does not shout as loudly as the live calendar. */
.evt-tile-status-now {
  background: var(--red)
}

.evt-tile-status-done {
  background: rgba(15, 23, 42, .62)
}

/* Glassy date block. backdrop-filter is progressive — where it is unsupported
   the 92% white behind it still reads cleanly over a photograph. */
.evt-tile-date {
  position: absolute;
  top: 1rem;
  right: 1rem;
  min-width: 3.1rem;
  padding: .35rem .5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  border-radius: 14px;
  background: rgba(255, 255, 255, .92);
  border: 1px solid rgba(255, 255, 255, .5);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px)
}

.evt-tile-date-m {
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--red)
}

.evt-tile-date-d {
  font-size: 1.25rem;
  font-weight: 800;
  line-height: 1;
  color: var(--navy)
}

.evt-tile-body {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1.1rem;
  flex: 1 1 auto;
  padding: 1.4rem;
  min-width: 0
}

.evt-tile-meta {
  list-style: none;
  margin: 0 0 .7rem;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .4rem 1rem;
  min-width: 0
}

.evt-tile-meta li {
  display: flex;
  align-items: center;
  gap: .35rem;
  min-width: 0;
  font-size: .75rem;
  color: var(--slate)
}

.evt-tile-meta svg {
  width: .9rem;
  height: .9rem;
  flex-shrink: 0;
  color: var(--red)
}

.evt-tile-meta-v {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

.evt-tile-t {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--navy);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  transition: color .25s
}

.evt-tile:hover .evt-tile-t {
  color: var(--red)
}

.evt-tile-sum {
  margin: .5rem 0 0;
  font-size: .8125rem;
  line-height: 1.65;
  color: var(--slate);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden
}

.evt-tile-act {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding-top: .9rem;
  border-top: 1px solid rgba(0, 0, 0, .07);
  font-size: .8125rem;
  font-weight: 700;
  color: var(--navy);
  transition: color .25s, gap .25s
}

.evt-tile:hover .evt-tile-act {
  color: var(--red);
  gap: .65rem
}

/* Centred variant of the events header, used above the tile grid.
   Compound selectors throughout: .evt-head is a grid whose base rule and 1024px
   rule are both declared *after* this block, so a single-class selector here
   would lose to them on order and the badge would stretch across the row as a
   grid item instead of hugging its text. */
.evt-head.evt-head-c {
  display: block;
  max-width: 40rem;
  margin: 0 auto 3rem;
  text-align: center
}

.evt-head.evt-head-c .evt-head-t {
  margin: .85rem 0 0
}

.evt-head.evt-head-c .evt-head-note {
  margin: .6rem 0 0;
  /* The two-column layout gives the note a red rule down its left edge. On a
     centred header that reads as a stray line beside the text. */
  padding-left: 0;
  border-left: 0
}

@media(min-width:768px) {
  .evt-tg {
    grid-template-columns: repeat(2, 1fr)
  }
}

@media(min-width:1024px) {
  .evt-tg {
    grid-template-columns: repeat(3, 1fr)
  }
}

@media(prefers-reduced-motion:reduce) {

  .evt-tile,
  .evt-tile-media img,
  .evt-tile-act {
    transition: none
  }

  .evt-tile:hover,
  .evt-tile:hover .evt-tile-media img {
    transform: none
  }
}

/* Section header for the events band: badge, two-tone title, and the aside
   that only earns its column once there is width for it (see the 1024 rule). */
.evt-head {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  align-items: end;
  max-width: 72rem;
  margin: 0 auto 2rem
}

/* .evt-head-badge ("JEPAN Calendar") was a rounded red pill here. It now takes
 * the shared section-tag definition further up this file, with .sec-label. */

.evt-head-t {
  margin: .75rem 0 0;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.875rem;
  font-weight: 800;
  line-height: 1.2;
  color: var(--navy)
}

.evt-head-t em {
  font-style: normal;
  color: var(--red)
}

.evt-head-note {
  margin: 0;
  color: var(--slate);
  font-size: .9375rem;
  line-height: 1.6
}

/* Homepage variant: the aside column holds a link to the full calendar rather
   than descriptive copy, so it hugs the right edge instead of filling a share
   of the width. Written as a compound selector on purpose — the plain
   .evt-head rule inside the 1024 block below would otherwise win on order. */
.evt-head.evt-head--split .evt-head-act {
  display: flex;
  align-items: center
}

.evt-head-link {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  font-size: .875rem;
  font-weight: 700;
  color: var(--red);
  text-decoration: none;
  transition: gap .25s, color .25s
}

.evt-head-link:hover {
  color: var(--red);
  gap: .6rem;
  text-decoration: underline
}

@media(min-width:768px) {
  .evt-head.evt-head--split {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    gap: 1.5rem
  }

  .evt-head.evt-head--split .evt-head-act {
    justify-content: flex-end;
    padding-bottom: .35rem
  }
}

@media(min-width:640px) {
  .evt-f {
    padding: 2rem
  }

  .evt-f-t {
    font-size: 1.75rem
  }

  .evt-head-t {
    font-size: 2.25rem
  }
}

@media(min-width:1024px) {
  .evt-f {
    grid-template-columns: 1fr 1fr;
    gap: 2.5rem
  }

  .evt-f-media {
    aspect-ratio: auto;
    height: 380px
  }

  /* The aside sits beside the title only here; stacked under it on narrow
     screens it would read as a caption on the heading. */
  .evt-head {
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    gap: 2.5rem
  }

  .evt-head-note {
    padding-left: 1.5rem;
    border-left: 3px solid var(--red)
  }
}

@media(prefers-reduced-motion:reduce) {

  .evt-f,
  .evt-f-media img,
  .evt-f-btn {
    transition: none
  }

  .evt-f:hover,
  .evt-f:hover .evt-f-media img,
  .evt-f-btn:hover {
    transform: none
  }
}

.gal-g {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  /* Was .75rem. Photographs need room to read as separate images rather than
     one mosaic, and the album page is the one screen that is only photographs. */
  gap: 1.5rem
}

.gal-i {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  cursor: pointer;
  /* Back to 4/3 — 1/1 cropped noticeably more off the sides of a typical
     landscape event photo than the "bigger" ask wanted. The grid topping out
     at 3 columns instead of 4 (see .gal-g) is what makes each card bigger now
     — it does not need a taller crop on top of that. */
  aspect-ratio: 4/3
}

.gal-i img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s
}

.gal-i:hover img {
  transform: scale(1.05)
}

.gal-ol {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(5, 33, 81, .8), transparent);
  display: flex;
  align-items: flex-end;
  padding: .75rem;
  opacity: 0;
  transition: opacity .3s
}

.gal-i:hover .gal-ol {
  opacity: 1
}

/* Photo captions only. Unscoped, this is `.gal-ol span` at (0,1,1), which
   quietly outranks every (0,1,0) `.gal-alb-*` class in the album overlay below
   — it was already flattening the album's date to full white, and it swallowed
   the eyebrow's colour and the title's size the moment those were added. */
.gal-ol:not(.gal-ol-alb) span {
  color: var(--w);
  font-size: .75rem;
  font-weight: 500
}

/* Album card: the same tile as a photo, but it is an <a> and its caption is
   the gallery's identity.

   The overlay is revealed on hover — but only inside the `@media (hover:hover)`
   block below. This base state is what a touch screen gets, and it is the old
   always-visible overlay, unchanged: a phone has no hover to trade the title
   for, so hiding it there would leave a grid of unlabelled photographs with no
   way to tell one album from another. Desktop gets the reveal; touch keeps the
   caption. */
.gal-alb {
  display: block;
  text-decoration: none
}

.gal-ol-alb {
  opacity: 1;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: .15rem;
  background: linear-gradient(to top, rgba(5, 33, 81, .92), rgba(5, 33, 81, .35) 55%, transparent);
  padding: 1.25rem
}

/* Eyebrow above the album name. */
.gal-alb-k {
  color: #f87171;
  font-size: .625rem;
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  line-height: 1.4
}

.gal-alb-t {
  color: var(--w);
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.35
}

.gal-alb-c {
  color: rgba(255, 255, 255, .75);
  font-size: .7rem;
  font-weight: 500;
  letter-spacing: .02em
}

.gal-alb:hover .gal-ol-alb {
  background: linear-gradient(to top, rgba(5, 33, 81, .95), rgba(5, 33, 81, .55) 65%, rgba(5, 33, 81, .15))
}

/* Doubled class (0,2,1) on purpose: the shared grid-card zoom near the end of
   this file sets `.gal-i img { transition: transform .7s ease }` at the same
   specificity but later in the source, so a plain `.gal-alb img` would lose to
   it. This wins wherever it sits. */
.gal-i.gal-alb img {
  transition: transform .5s cubic-bezier(0, 0, .2, 1)
}

/* ---------------------------------------------------------------------------
   Album overlay, hover-capable pointers only
   ---------------------------------------------------------------------------
   Hidden and slightly shrunk at rest, fading and scaling up under the pointer,
   with the two text lines sliding the last few pixels on a stagger. Everything
   here is inside the media query, so a device that cannot hover never enters
   the hidden state — see the note on .gal-alb above.
--------------------------------------------------------------------------- */
@media (hover: hover) {
  .gal-ol-alb {
    opacity: 0;
    transform: scale(.95);
    transition: opacity .3s, transform .3s cubic-bezier(0, 0, .2, 1), background .3s;
    /* The card is the link; the overlay must never be the thing clicked. */
    pointer-events: none
  }

  .gal-alb:hover .gal-ol-alb,
  .gal-alb:focus-visible .gal-ol-alb {
    opacity: 1;
    transform: scale(1)
  }

  .gal-ol-alb>* {
    transform: translateY(8px);
    transition: transform .3s cubic-bezier(0, 0, .2, 1)
  }

  .gal-alb:hover .gal-ol-alb>*,
  .gal-alb:focus-visible .gal-ol-alb>* {
    transform: translateY(0)
  }

  /* The title trails the eyebrow, and the date trails the title. */
  .gal-ol-alb .gal-alb-t {
    transition-delay: .075s
  }

  .gal-ol-alb .gal-alb-c {
    transition-delay: .12s
  }
}

/* Gallery detail: photo count on the left, "all galleries" on the right. */
/* Album action bar: the date on the left, "All Galleries" on the right, ruled
   off from the photographs below it. The empty <p> is kept when an album has no
   date so space-between still pushes the button right — dropping the element
   would leave the button on the left with nothing beside it. */
.gal-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 2rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid rgba(0, 0, 0, .09)
}

.gal-meta p:empty {
  margin: 0
}

.ldr-g {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem
}

/* Column that fills its grid cell, so every card in a row ends level even when
   one person's designation runs to two lines and the next has contact icons. */
.ldr-c {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--w);
  border-radius: 24px;
  overflow: hidden;
  border: 1px solid rgba(0, 0, 0, .06);
  transition: all .3s
}

.ldr-c:hover {
  transform: translateY(-2px);
  box-shadow: var(--sh-h)
}

/* The ratio belongs on the frame, not the <img>. A portrait that fails to load
   leaves the image with no intrinsic size, and aspect-ratio on the img alone
   then collapses the box and drags the name up over the photo area. */
.ldr-c-media {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  flex: none;
  background: var(--soft);
  overflow: hidden
}

.ldr-c-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center
}

.ldr-c-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  padding: .75rem;
  min-width: 0
}

.ldr-c .ldr-c-name {
  margin: 0;
  font-weight: 700;
  color: var(--navy);
  font-size: .9375rem;
  line-height: 1.35;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden
}

.ldr-c .ldr-c-role {
  margin: .15rem 0 0;
  padding: 0;
  font-size: .8125rem;
  color: var(--red);
  line-height: 1.35;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden
}

/* Contact row. Only rendered when the record actually carries an email or a
   LinkedIn URL, so cards without either keep their original bottom padding. */
/* margin-top:auto pins the icon row to the bottom of the card body, so cards
   with and without contact details still line their photos and names up. The
   horizontal padding moved to .ldr-c-body — repeating it here double-indented
   the row once the body became a padded flex column. */
.ldr-links {
  display: flex;
  gap: .4rem;
  margin-top: auto;
  padding-top: .6rem
}

.ldr-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 999px;
  border: 1px solid rgba(0, 0, 0, .1);
  background: var(--s);
  color: var(--slate);
  font-size: .75rem;
  font-weight: 700;
  line-height: 1;
  transition: background .25s, color .25s, border-color .25s
}

.ldr-link:hover {
  background: var(--red);
  border-color: var(--red);
  color: var(--w)
}

.ldr-link:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px
}

.blog-g {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem
}

.blog-c {
  display: block;
  background: var(--w);
  border-radius: 24px;
  overflow: hidden;
  border: 1px solid rgba(0, 0, 0, .06);
  transition: all .3s
}

.blog-c:hover {
  transform: translateY(-2px);
  box-shadow: var(--sh-h)
}

.blog-c img {
  width: 100%;
  aspect-ratio: 16/9;
  object-fit: cover;
  transition: transform .5s
}

.blog-c:hover img {
  transform: scale(1.03)
}

.blog-c h3 {
  font-weight: 700;
  color: var(--navy);
  font-size: 1rem;
  padding: .75rem 1rem .25rem
}

.blog-c:hover h3 {
  color: var(--red)
}

.blog-c p {
  padding: .25rem 1rem;
  color: var(--slate);
  font-size: .875rem
}

.blog-c small {
  display: block;
  padding: 0 1rem 1rem;
  color: var(--slate);
  font-size: .8125rem
}

.blog-tag {
  display: inline-block;
  padding: .25rem .75rem;
  background: var(--red-bg);
  color: var(--red);
  border-radius: 999px;
  font-size: .6875rem;
  font-weight: 600;
  margin: 1rem 1rem 0
}

/* Partners & Stakeholders — infinite slider
   ─────────────────────────────────────────
   The old .marq-* marquee scrolled bare names and translated the track by a
   fixed -50%, which only loops seamlessly when the track holds exactly two
   copies of the content. This one is driven by js/partners.js: it clones the
   set to fill the viewport and sets --pt-shift to the width of ONE copy, so the
   distance travelled per lap always matches the content rather than the other
   way round.

   Nothing animates until that script adds .is-live. Before then — and with no
   JS at all — the strip is a plain horizontally scrollable row, which is
   readable rather than a broken animation or a track the visitor cannot reach. */
.pt-marq {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* Vertical room for the 8px hover lift and the 25px shadow under it — the
     card has to have somewhere to rise into that is not the heading above. */
  padding: 1.25rem 1.25rem 1.75rem
}

.pt-marq.is-live {
  /* clip, not hidden: hidden on one axis forces the other to `auto`, which
     would re-introduce the vertical scroll container this padding exists to
     avoid. Same reasoning as .sec above. */
  overflow-x: clip;
  /* Cards fade out at both edges instead of being sliced mid-logo. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent)
}

.pt-track {
  display: flex;
  gap: 1.25rem;
  width: max-content
}

.pt-marq.is-live .pt-track {
  animation: pt-scroll var(--pt-dur, 40s) linear infinite
}

/* Pause on hover, as a slider that cannot be read is decoration — and on
   focus-within too, or tabbing to a partner's link drags it out from under the
   keyboard. */
.pt-marq.is-live:hover .pt-track,
.pt-marq.is-live:focus-within .pt-track {
  animation-play-state: paused
}

@keyframes pt-scroll {
  from {
    transform: translateX(0)
  }

  to {
    transform: translateX(calc(-1 * var(--pt-shift, 50%)))
  }
}

/* One card. Renders as <a> when the partner has a website and <div> when not,
   so every property here has to hold for both — hence the explicit color and
   text-decoration rather than inheriting whatever an anchor brings.

   flex:none because a flex item in the track must keep its width; left to
   shrink, twenty partners would each be squeezed to a sliver. Column layout
   with space-between is what gives every card the same height and pins the
   link to the bottom edge whatever length the name above it runs to. */
.pt-c {
  display: flex;
  flex: none;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  gap: .45rem;
  width: 232px;
  padding: 1.5rem 1.25rem;
  background: rgba(255, 255, 255, .85);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(226, 232, 240, .8);
  /* The accent line is declared transparent here and only coloured on hover.
     Adding a 2px border on hover alone would make the card 2px taller at the
     moment the pointer arrives, nudging every neighbour in the track — the one
     thing a hover effect must not do. */
  border-top: 2px solid transparent;
  border-radius: 16px;
  box-shadow: 0 4px 20px -2px rgba(0, 0, 0, .05);
  color: inherit;
  text-align: center;
  text-decoration: none;
  transition: transform .3s ease, box-shadow .3s ease, border-color .3s ease
}

a.pt-c:hover {
  transform: translateY(-8px);
  border-top-color: #dc2626;
  box-shadow: 0 20px 25px -5px rgba(220, 38, 38, .12), 0 8px 10px -6px rgba(0, 0, 0, .05)
}

/* One fixed box for every logo, whatever shape the file is.
   ─────────────────────────────────────────────────────────
   Fixed height so every logo sits on one baseline: a tall crest and a wide
   wordmark otherwise start their captions at different heights, and in a moving
   strip that reads as jitter.

   object-fit:contain on a 100%-wide, 80px-tall box is what keeps an odd upload
   honest — a screenshot, a banner, a square PNG all scale to fit *inside* the
   box with their aspect ratio intact. `cover` would fill the same box by
   cropping into the middle of the image, which on a wide screenshot shows a
   slice of somebody's browser chrome and nothing else.

   Transparent, not tinted: logos are supplied on transparent or white grounds,
   and a coloured plate behind them fights whatever ground the file already has. */
.pt-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 75px;
  padding: 8px;
  margin-bottom: .4rem;
  background: transparent;
  /* The logo scales on hover; without this the enlarged image would spill past
     the slot and over the name underneath it. */
  overflow: hidden
}

/* max-height/max-width rather than 100%/100%: the image is sized by its own
   proportions up to the slot, so a small logo is not stretched to fill a box it
   was never drawn for — contain then keeps a large one inside it. */
.pt-logo img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  transition: transform .3s ease
}

a.pt-c:hover .pt-logo img {
  transform: scale(1.08)
}

/* The no-logo fallback. It is the card's <h3> standing in for the artwork, not
   a second copy of the name, so it carries its own margin reset rather than
   inheriting the heading defaults. */
.pt-mark {
  margin: 0;
  font-size: .9375rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--navy, #0f172a)
}

.pt-n {
  margin: 0;
  font-size: .95rem;
  font-weight: 600;
  line-height: 1.35;
  color: #0f172a
}

/* The description as a pill badge.
   ────────────────────────────────
   inline-block with a wrapping max-width, not a nowrap chip: these are written
   by staff and run to a sentence — "Student support and scholarship
   administration" — and a chip that refuses to wrap would push straight through
   the side of the card. It keeps the pill's radius and padding at any length,
   and the clamp stops one long entry from setting the height of every card in
   the strip. */
.pt-d {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-width: 100%;
  margin: 0;
  padding: 2px 10px;
  background: #f1f5f9;
  border-radius: 9999px;
  font-size: .75rem;
  line-height: 1.5;
  color: #475569
}

.pt-l {
  margin-top: auto;
  padding-top: .45rem;
  font-size: .75rem;
  font-weight: 600;
  color: var(--red, #bc002d)
}

@media (max-width: 640px) {
  .pt-c {
    width: 200px;
    padding: 1.15rem 1rem;
    /* Dropped on phones, and nothing is lost by it: the strip sits on a solid
       white section, so there is no texture behind the card for a blur to
       reveal — but the browser still composites one per card, on twenty-odd
       cards, every frame of a continuous animation. That is where the jank
       shows up. The translucent fill stays. */
    -webkit-backdrop-filter: none;
    backdrop-filter: none
  }

  /* Shorter, but the slot keeps its shape and its padding — the image inside
     is sized from the slot, so nothing else needs a mobile override. */
  .pt-logo {
    height: 62px
  }
}

/* Motion off: the strip stays a scrollable row (js/partners.js never adds
   .is-live), so the same cards are still reachable by dragging or swiping.
   The hover lift and the logo's zoom go with it — the colour and shadow
   changes stay, so hover still reads as hover. */
@media (prefers-reduced-motion: reduce) {

  .pt-c,
  .pt-logo img {
    transition: none
  }

  a.pt-c:hover {
    transform: none
  }

  a.pt-c:hover .pt-logo img {
    transform: none
  }
}

/* App */
.phone-mock {
  display: flex;
  justify-content: center
}

.phone-f {
  width: 240px;
  height: 460px;
  background: var(--navy-d);
  border-radius: 2.5rem;
  border: 4px solid var(--navy-l);
  overflow: hidden;
  position: relative;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .3)
}

.phone-notch {
  width: 60px;
  height: 6px;
  background: var(--navy-d);
  border-radius: 0 0 1rem 1rem;
  margin: .75rem auto
}

.phone-screen {
  background: linear-gradient(to bottom, rgba(188, 0, 45, .15), var(--navy));
  padding: 1rem .75rem;
  height: calc(100% - 24px);
  overflow-y: auto
}

.phone-h {
  text-align: center;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-weight: 700;
  font-size: 1.125rem;
  color: var(--w);
  margin-bottom: .75rem
}

.phone-mi {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .75rem;
  background: rgba(255, 255, 255, .1);
  border-radius: 12px;
  color: rgba(255, 255, 255, .8);
  font-size: .75rem;
  margin-bottom: .5rem
}

.phone-mi span {
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(188, 0, 45, .3);
  border-radius: 6px;
  font-size: .6875rem;
  flex-shrink: 0
}

/* Forms */
.f-in {
  width: 100%;
  padding: .75rem 1rem;
  border: 1px solid rgba(0, 0, 0, .1);
  border-radius: 16px;
  font-size: .875rem;
  font-family: inherit;
  transition: all .3s;
  outline: none;
  background: var(--w)
}

.f-in:focus {
  border-color: var(--red);
  box-shadow: 0 0 0 3px rgba(188, 0, 45, .1)
}

textarea.f-in {
  resize: vertical
}

/* A field the inline validator has flagged. */
.f-in.is-invalid {
  border-color: var(--red);
  box-shadow: 0 0 0 3px rgba(188, 0, 45, .08)
}

/* Visible field label. Most public forms on the site label their inputs with
   a placeholder, but a file input has no placeholder to explain itself with,
   so the translation form labels every field for consistency. */
.f-lbl {
  display: block;
  margin-bottom: .4rem;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--char)
}

.f-lbl em {
  color: var(--red);
  font-style: normal
}

/* File input: the native button is left alone (it is the only reliable way to
   open a picker) but padded to sit at the same height as the text inputs. */
.f-file {
  padding: .6rem 1rem;
  cursor: pointer
}

.f-file::file-selector-button {
  margin-right: .75rem;
  padding: .4rem .8rem;
  border: 1px solid rgba(0, 0, 0, .1);
  border-radius: 999px;
  background: var(--soft);
  font: inherit;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--char);
  cursor: pointer;
  transition: background .2s, border-color .2s
}

.f-file::file-selector-button:hover {
  background: var(--w);
  border-color: var(--red);
  color: var(--red)
}

.f-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem
}

/* Timeline */
.tl {
  position: relative;
  padding-left: 2.5rem
}

.tl-line {
  position: absolute;
  left: 22px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: rgba(188, 0, 45, .2)
}

.tl-i {
  position: relative;
  padding-bottom: 2rem
}

.tl-i:last-child {
  padding-bottom: 0
}

.tl-dot {
  position: absolute;
  left: -2.05rem;
  top: .3rem;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--red);
  border: 3px solid var(--w);
  box-shadow: 0 0 0 2px rgba(188, 0, 45, .2)
}

.tl-dot-n {
  position: absolute;
  left: -2.4rem;
  top: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--red);
  color: var(--w);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1rem;
  box-shadow: 0 4px 12px rgba(188, 0, 45, .3)
}

/* Cards */
.card-g {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem
}

.ucard {
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .06);
  border-radius: 16px;
  padding: 1.25rem;
  transition: all .3s
}

.ucard:hover {
  transform: translateY(-2px);
  box-shadow: var(--sh-h)
}

.ucard h3 {
  font-weight: 700;
  color: var(--navy);
  font-size: 1.0625rem
}

.uc-d {
  font-size: .8125rem;
  color: var(--slate);
  margin-top: .5rem
}

/* FAQ */
.faq summary {
  font-weight: 500;
  font-size: .9375rem;
  color: var(--char);
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
  cursor: pointer;
  border: 1px solid rgba(0, 0, 0, .06);
  border-radius: 16px
}

.faq summary::after {
  content: '▾';
  transition: transform .3s
}

.faq[open] summary::after {
  transform: rotate(180deg)
}

.faq p {
  padding: 0 1rem 1rem;
  color: var(--slate);
  font-size: .875rem
}

/* Dashboard */
.dash-l {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 80vh;
  background: var(--soft)
}

.dash-sb {
  background: var(--w);
  border-right: 1px solid rgba(0, 0, 0, .06);
  padding: 1.5rem
}

.dash-nav a {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .625rem 1rem;
  border-radius: 12px;
  font-size: .875rem;
  font-weight: 500;
  color: var(--slate);
  transition: all .2s;
  margin-bottom: .25rem
}

.dash-nav a:hover,
.dash-nav a.ac {
  background: rgba(188, 0, 45, .1);
  color: var(--red)
}

.dash-main {
  padding: 1.5rem
}

.dash-stat {
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .06);
  border-radius: 16px;
  padding: 1rem
}

.dash-stat strong {
  font-size: 1.25rem;
  color: var(--navy)
}

/* Lightbox */
#lb {
  position: fixed;
  inset: 0;
  /* Above everything, including the dashboard's fixed sidebar (200) and sticky
     header (100) — a fullscreen viewer that something else paints over is
     worse than no viewer at all. */
  z-index: 300;
  background: rgba(5, 33, 81, .95);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  padding: 2rem
}

#lb img {
  max-width: 100%;
  max-height: 80vh;
  border-radius: 12px;
  object-fit: contain
}

#lb-cap {
  color: rgba(255, 255, 255, .8);
  margin-top: 1rem;
  font-size: 1.0625rem;
  text-align: center;
  max-width: 44rem
}

.lb-x {
  position: absolute;
  top: 1.5rem;
  right: 1.5rem;
  font-size: 2rem;
  line-height: 1;
  padding: .25rem .6rem;
  color: rgba(255, 255, 255, .6);
  background: none;
  border: 0;
  font-family: inherit;
  cursor: pointer;
  transition: color .2s
}

.lb-x:hover {
  color: var(--w)
}

/* Previous / next. Hidden by the script when an album holds a single photo. */
.lb-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .12);
  color: var(--w);
  font-size: 2rem;
  line-height: 1;
  font-family: inherit;
  cursor: pointer;
  transition: background .2s
}

.lb-nav:hover {
  background: rgba(255, 255, 255, .25)
}

.lb-prev {
  left: 1rem
}

.lb-next {
  right: 1rem
}

.lb-count {
  position: absolute;
  top: 1.75rem;
  left: 1.5rem;
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: rgba(255, 255, 255, .55)
}

/* The gallery tile's anchor fills it, so the whole card is the click target
   and the hover zoom still applies to the image inside. */
.gal-i>a {
  display: block;
  width: 100%;
  height: 100%
}

@media(max-width:640px) {
  .lb-nav {
    width: 40px;
    height: 40px;
    font-size: 1.5rem
  }

  .lb-prev {
    left: .35rem
  }

  .lb-next {
    right: .35rem
  }
}

/* Scroll Top */
#st {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  z-index: 50;
  width: 44px;
  height: 44px;
  background: var(--red);
  color: var(--w);
  border: none;
  border-radius: 50%;
  font-size: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 16px rgba(188, 0, 45, .3);
  transition: all .3s
}

#st:hover {
  background: var(--red-l);
  transform: translateY(-2px)
}

/* Sakura */
#sakura-c {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 5
}

.s-petal {
  position: absolute;
  opacity: .25;
  animation: sakFloat linear infinite
}

@keyframes sakFloat {
  0% {
    transform: translate(0, -10vh) rotate(0deg)
  }

  25% {
    transform: translate(15vw, 25vh) rotate(90deg)
  }

  50% {
    transform: translate(5vw, 50vh) rotate(180deg)
  }

  75% {
    transform: translate(20vw, 75vh) rotate(270deg)
  }

  100% {
    transform: translate(0, 110vh) rotate(360deg)
  }
}

/* Animations */
.anim {
  opacity: 0;
  transition: opacity .6s, transform .6s
}

.anim.vis {
  opacity: 1
}

.anim.up {
  transform: translateY(30px)
}

.anim.up.vis {
  transform: translateY(0)
}

.anim.left {
  transform: translateX(40px)
}

.anim.left.vis {
  transform: translateX(0)
}

.anim.right {
  transform: translateX(-40px)
}

.anim.right.vis {
  transform: translateX(0)
}

.anim.scale {
  transform: scale(.9)
}

.anim.scale.vis {
  transform: scale(1)
}

/* Responsive */
@media(min-width:640px) {
  .hero-t {
    font-size: 3rem
  }

  .hero-cta {
    flex-direction: row
  }

  .hero-stats {
    grid-template-columns: repeat(4, 1fr)
  }

  /* Arrows on tablet and up. On a phone they would sit on top of the copy;
     swipe and the dots cover that case. */
  .hero-nav {
    display: flex
  }

  .stat-n {
    font-size: 2rem
  }

  .sec-h {
    font-size: 2.5rem
  }

  .sec {
    padding: 5rem 0
  }

  .pil-g {
    grid-template-columns: 1fr 1fr
  }

  .mem-g {
    grid-template-columns: 1fr 1fr
  }

  .ldr-g {
    grid-template-columns: repeat(3, 1fr)
  }

  .blog-g {
    grid-template-columns: 1fr 1fr
  }

  .card-g {
    grid-template-columns: 1fr 1fr
  }

  .gal-g {
    grid-template-columns: repeat(3, 1fr)
  }

  .evt-c {
    flex-direction: row;
    align-items: center
  }

  .dash-stat {
    flex: 1
  }

  .f-row {
    grid-template-columns: 1fr 1fr
  }

}

/* Desktop nav on, drawer off — at 1280px, not 640px.

   This is the fix for the wrapping header. The row carries eight links plus
   two or three right-hand controls: measured at roughly 1056px signed out and
   1180px signed in as staff, against 1232px of usable container at the 1280px
   cap. Both fit on one line there, and only there — .container is capped at
   1280px, so no wider screen gives the row any more room, and every narrower
   one gives it less.

   Turning it on at 640px asked that same row to fit in 592px of container. It
   could not, so from tablet width upward it wrapped to two and three lines,
   the header grew with it, and the logo — vertically centred against a stack
   whose height kept changing — appeared to drift upward. Wrapping was the
   mechanism; the breakpoint was the cause.

   1280px was then correct but blunt: it hid the whole menu on every laptop
   narrower than that, which is most of them — Home and About included.

   1024px is right now that the header is three groups rather than two. The
   links are the only group that can shrink, and past shrinking they scroll
   inside themselves; the logo and the account controls are fixed. So a width
   the links do not quite fit costs a little scrolling in the middle of the
   bar — not a wrapped header, and not a "Become a Member" pushed off screen.
   The failure mode is what makes the lower breakpoint safe, not extra room. */
@media(min-width:1024px) {

  #desk-nav,
  #nav-actions {
    display: flex
  }

  .mob-tgl {
    display: none
  }

  #mob-menu.hide {
    display: none !important
  }

  /* Compact sizing from 1024 up. Horizontal padding is what costs the row its
     width, so that is what tightens; the vertical stays for hit area. */
  .nav-l {
    padding: .5rem .4rem;
    font-size: .8125rem
  }

  /* Compact right-hand buttons, so the action pair costs the row as little
     width as the text links do. flex-shrink:0 keeps a button at its own size
     rather than being squeezed until its label wraps mid-word — the logout
     control carries the username, so its width is not something this
     stylesheet can know in advance. */
  #nav-actions .btn-dashboard.btn-sm,
  #nav-actions .btn-login.btn-sm,
  #nav-actions .btn-p.btn-sm,
  #nav-actions .btn-s.btn-sm,
  #nav-actions .btn-a.btn-sm,
  #nav-actions .btn-logout,
  #nav-actions .nav-admin {
    flex-shrink: 0;
    /* A CTA's label is written in Site Settings and can be any length, so
       nowrap is what keeps "Become a Member" one line rather than two — a
       two-line button is the other way a row grows taller than its bar. */
    white-space: nowrap;
    padding: .4rem .75rem;
    font-size: .75rem;
    border-radius: 10px
  }

  #nav-actions .nav-admin {
    padding: .4rem .55rem
  }

  /* The logout form is itself a flex item in the actions group, so it needs
     the same no-shrink treatment as the buttons — otherwise the group's one
     wrapper element is the thing that gives. */
  #nav-actions .nav-logout {
    flex-shrink: 0
  }
}

/* Roomier links once .container reaches its 1280px cap and the row has space
   to spare. This is the last width that changes anything — a wider screen
   gives the header no extra room, because the container stops growing. */
@media(min-width:1280px) {
  .nav-l {
    padding: .5rem .55rem;
    font-size: .875rem
  }
}

@media(min-width:1024px) {
  .hero-t {
    font-size: 4rem
  }

  .splt {
    grid-template-columns: 1fr 1fr
  }

  .mem-g {
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem
  }

  .ldr-g {
    grid-template-columns: repeat(4, 1fr)
  }

  .blog-g {
    grid-template-columns: repeat(3, 1fr)
  }

  .gal-g {
    /* Was 4 — cards read as very small at that width, and every other card
       grid on the site (blog, member directory) tops out at 3. */
    grid-template-columns: repeat(3, 1fr)
  }

  .card-g {
    grid-template-columns: repeat(3, 1fr)
  }

  .f-grid {
    /* Was a fixed 4 — brand, Quick Links, Study in Japan, Contact. With the
       Study in Japan column off (see footer.html) there are three blocks now
       — brand, Quick Links, Contact — so the row is three explicit, evenly
       sized columns rather than four with the last one standing empty. */
    grid-template-columns: repeat(3, 1fr)
  }

  .f-bot {
    flex-direction: row;
    justify-content: space-between
  }

  .sec-h {
    font-size: 3rem
  }

  .dash-l {
    grid-template-columns: 240px 1fr
  }

  .dash-stats {
    display: flex;
    gap: 1rem
  }

  .pg-hero {
    padding: 8rem 0
  }
}

/* ── Hero on phones and small tablets ─────────────────────────────────────
   Deliberately a max-width block, and deliberately placed after the mobile-up
   ladder above: .hero-t steps 2.25 → 3rem at 640px → 4rem at 1024px, so a
   700px tablet was already taking the 3rem step. Same specificity, later in the
   file, so these win below 768px and nothing above it is touched — which is why
   this is not done by moving the 640px breakpoint, a block that also carries
   the stat grid, the section padding and four unrelated grids. */
@media (max-width: 767.98px) {

  /* clamp so the heading tracks the viewport instead of jumping at one
     breakpoint. The ceiling is 2.75rem, which only ever applies to the top of
     this range — the 3rem and 4rem steps above still own tablet and desktop. */
  .hero-t {
    font-size: clamp(1.75rem, 5vw, 2.75rem);
    line-height: 1.2;
    /* A long headline with no spaces cannot be broken by the clamp alone. */
    overflow-wrap: anywhere
  }

  .hero-sub {
    font-size: .9375rem
  }

  /* Full-width buttons, stacked. .hero-cta is already a column at this size;
     what was missing is the width — two differently-sized pills centred under a
     heading read as a mistake, and a thumb aims at a full-width target more
     easily than at a 9rem one. */
  .hero-cta {
    flex-direction: column;
    align-items: stretch;
    width: 100%
  }

  .hero-cta>* {
    width: 100%;
    justify-content: center;
    text-align: center
  }

  /* Breathing room. .hero centres its content in a 100vh box with no padding of
     its own, so on a short phone screen the copy ran to the edges. */
  .hero .container {
    padding: 3rem 1rem
  }

  .hero-stats {
    margin-top: 2.5rem;
    gap: 1rem
  }
}

/* ============================================================
   ADDITIONS AFTER THE ORIGINAL index.html MIGRATION
   Everything above this line is the original <style> block,
   unmodified. Keep new rules below so the two stay separable.
   ============================================================ */

/* Real JEPAN logo in the navbar (replaces the placeholder SVG + wordmark). */
/* The logo is bounded, not merely sized.

   `height` alone is a request: an <img> whose file fails to load, or one whose
   intrinsic size wins a specificity fight, can still report a taller box and
   push the bar open. max-height is the bound that cannot be argued with, and
   the two are set together so the mark renders at its intended size and can
   never exceed it. 48px against the 80px bar leaves room for the white plate's
   padding either side.

   object-fit:contain fits any aspect ratio into that box rather than letting
   the artwork set it; flex-shrink:0 stops a crowded row squeezing the image
   narrower than the space its height needs. */
.logo-img {
  height: 40px;
  max-height: 3rem;
  width: auto;
  display: block;
  object-fit: contain;
  flex-shrink: 0
}

.logo-g {
  background: #fff;
  padding: .3rem .6rem;
  border-radius: 12px;
  transition: background .3s, padding .3s
}

#header.scrolled .logo-g {
  background: transparent;
  padding: .3rem 0
}

@media(min-width:640px) {
  .logo-img {
    height: 48px
  }
}

/* Footer logo. Default is the knockout variant, so it sits directly on the
   navy with no plate. `.plated` is added only when an admin has uploaded a
   custom logo, which may be dark and unreadable on --navy. */
.footer-logo-g {
  display: inline-block;
  transition: opacity .3s
}

.footer-logo-g:hover {
  opacity: .82
}

.footer-logo {
  height: 52px;
  width: auto;
  display: block
}

.footer-logo-g.plated {
  background: #fff;
  padding: .4rem .65rem;
  border-radius: 12px
}

@media(min-width:640px) {
  .footer-logo {
    height: 58px
  }
}

/* Logout is a POST form (a GET link lets any site force a sign-out via
   <img src=".../logout/">), so the button is neutralised to look like the
   other nav buttons. */
.nav-logout {
  display: inline-flex;
  margin: 0
}

.btn-logout {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  padding: .45rem 1rem;
  font-family: inherit;
  font-size: .875rem;
  font-weight: 600;
  border-radius: 12px;
  white-space: nowrap;
  cursor: pointer;
  transition: all .3s;
  background: transparent;
  color: var(--red);
  border: 2px solid rgba(188, 0, 45, .35)
}

.btn-logout:hover {
  background: var(--red);
  border-color: var(--red);
  color: var(--w);
  transform: translateY(-1px);
  box-shadow: var(--sh-h)
}

#mob-menu .nav-logout {
  display: block;
  width: 100%
}

#mob-menu .btn-logout {
  width: 100%;
  margin-top: .35rem;
  font-size: 1rem;
  padding: .6rem
}

/* Navbar auth buttons (Dashboard / Member Login / Admin) */
.btn-dashboard,
.btn-login {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  padding: .75rem 1.5rem;
  font-family: inherit;
  font-weight: 600;
  border-radius: 12px;
  white-space: nowrap;
  cursor: pointer;
  transition: all .3s
}

.btn-dashboard {
  background: var(--navy);
  color: var(--w);
  border: 2px solid var(--navy)
}

.btn-dashboard:hover {
  background: var(--red);
  border-color: var(--red);
  color: var(--w);
  transform: translateY(-1px);
  box-shadow: var(--sh-h)
}

.btn-login {
  background: transparent;
  color: var(--navy);
  border: 2px solid var(--navy)
}

.btn-login:hover {
  background: var(--navy);
  color: var(--w);
  transform: translateY(-1px);
  box-shadow: var(--sh-h)
}

/* .btn-sm is declared ABOVE these rules, so on equal specificity it would lose.
   Re-assert it here at two-class specificity so the compact size still wins. */
.btn-dashboard.btn-sm,
.btn-login.btn-sm {
  padding: .45rem 1rem;
  font-size: .875rem
}

/* Staff-only shortcut into /admin/ */
.nav-admin {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  padding: .45rem .7rem;
  border-radius: 12px;
  font-size: .875rem;
  font-weight: 600;
  color: var(--slate);
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .12);
  white-space: nowrap;
  transition: all .3s
}

.nav-admin:hover {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--navy);
  transform: translateY(-1px)
}

/* Mobile menu: full width, and `#mob-menu a` (id specificity) would otherwise
   override the button colours, so they are re-declared under that selector. */
#mob-menu .btn-dashboard,
#mob-menu .btn-login,
#mob-menu .nav-admin,
#mob-menu .mob-signout {
  width: 100%;
  text-align: center;
  margin-top: .35rem;
  font-size: 1rem
}

#mob-menu .btn-dashboard {
  color: var(--w)
}

#mob-menu .btn-dashboard:hover {
  color: var(--w)
}

#mob-menu .btn-login {
  color: var(--navy)
}

#mob-menu .btn-login:hover {
  color: var(--w)
}

#mob-menu .nav-admin {
  color: var(--slate)
}

#mob-menu .nav-admin:hover {
  color: var(--navy)
}

#mob-menu .mob-signout {
  display: block;
  padding: .6rem;
  border-radius: 12px;
  font-weight: 600;
  color: var(--red)
}

#mob-menu .mob-signout:hover {
  background: rgba(188, 0, 45, .08)
}

/* ==================================================================
   JEPAN DIGITAL SERVICES HUB
   Fully namespaced `hub-*`; adds no rules to existing selectors.
   ================================================================== */
.hub {
  position: relative;
  overflow: hidden;
  padding: 4.5rem 0;
  background: radial-gradient(120% 90% at 15% 0%, #0a3478 0%, #052151 45%, #031430 100%)
}

.hub .container {
  position: relative;
  z-index: 2
}

.hub-bg-grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: .5;
  background-image: linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: radial-gradient(70% 60% at 50% 40%, #000 30%, transparent 100%);
  -webkit-mask-image: radial-gradient(70% 60% at 50% 40%, #000 30%, transparent 100%)
}

.hub-glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  pointer-events: none;
  z-index: 1
}

.hub-glow--red {
  width: 520px;
  height: 520px;
  right: -90px;
  top: 4%;
  background: rgba(188, 0, 45, .42)
}

.hub-glow--navy {
  width: 420px;
  height: 420px;
  left: -140px;
  bottom: -90px;
  background: rgba(10, 52, 120, .55)
}

/* One centred column. Was a two-column grid with a browser mockup on the
   right; with that gone a grid would just leave the copy hugging the left
   edge of a full-width container. */
.hub-inner {
  max-width: 52rem;
  margin-inline: auto;
  text-align: center
}

/* copy */
.hub-badge {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem .85rem;
  border-radius: 999px;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #ff8fa5;
  background: rgba(188, 0, 45, .16);
  border: 1px solid rgba(188, 0, 45, .42);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px)
}

.hub-title {
  margin-top: 1rem;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.18;
  color: #fff;
  letter-spacing: -.01em
}

.hub-title-accent {
  background: linear-gradient(100deg, #fff 0%, #ffb7c5 40%, #BC002D 95%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent
}

.hub-sub {
  /* Auto side margins, not just the max-width: the measure is deliberately
     narrower than the column, so without them it would sit off to one side. */
  margin: 1.1rem auto 0;
  max-width: 34rem;
  font-size: 1rem;
  line-height: 1.7;
  color: rgba(255, 255, 255, .62)
}

.hub-cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .75rem;
  margin-top: 2rem
}

.hub-btn {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .8rem 1.4rem;
  border-radius: 14px;
  font-weight: 600;
  font-size: .9375rem;
  white-space: nowrap;
  transition: transform .3s, box-shadow .3s, background .3s, border-color .3s
}

.hub-btn--primary {
  background: var(--red);
  color: #fff;
  border: 1px solid var(--red);
  box-shadow: 0 10px 26px rgba(188, 0, 45, .34)
}

.hub-btn--primary:hover {
  background: var(--red-l);
  border-color: var(--red-l);
  transform: translateY(-4px);
  box-shadow: 0 18px 38px rgba(188, 0, 45, .46)
}

.hub-btn--ghost {
  background: rgba(255, 255, 255, .07);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, .24);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px)
}

.hub-btn--ghost:hover {
  background: rgba(255, 255, 255, .14);
  border-color: rgba(255, 255, 255, .5);
  transform: translateY(-4px)
}

.hub-btn::after {
  content: '';
  position: absolute;
  top: 0;
  left: -120%;
  width: 70%;
  height: 100%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .26), transparent);
  transform: skewX(-18deg);
  transition: left .75s ease
}

.hub-btn:hover::after {
  left: 130%
}

/* Three equal columns rather than a wrapping flex row: with the content
   centred, an odd number of flex items wraps into a lopsided last line on
   narrow screens. A fixed 3-up grid stays symmetrical at every width. */
.hub-trust {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  max-width: 34rem;
  margin: 2.25rem auto 0;
  list-style: none
}

.hub-trust strong {
  display: block;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--gold)
}

.hub-trust span {
  display: block;
  font-size: .75rem;
  color: rgba(255, 255, 255, .5);
  margin-top: .15rem
}

@media(prefers-reduced-motion:reduce) {
  .hub-btn::after {
    display: none
  }

  .hub-btn:hover {
    transform: none
  }
}

@media(min-width:640px) {
  .hub {
    padding: 5.5rem 0
  }

  .hub-title {
    font-size: 2.5rem
  }
}

@media(min-width:1024px) {

  /* The section lost its right-hand column, so it earns back the height in
     breathing room rather than sitting as a short band. */
  .hub {
    padding: 7rem 0
  }

  .hub-title {
    font-size: 3rem
  }
}

/* ==================================================================
   FOUR PILLARS: pressable cards
   Specificity note: .anim.up.vis (0,3,0) already sets `transform` on these
   cards for the scroll reveal. A plain `.pillar-card:hover` (0,2,0) would
   lose to it and the lift would never apply, so the interactive states are
   written as `.pil-c.pillar-card:...` (0,3,0) and declared after it.
   ================================================================== */
.pil-c.pillar-card {
  cursor: pointer;
  position: relative;
  background: rgba(255, 255, 255, .06);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: transform .35s cubic-bezier(.2, .7, .3, 1), box-shadow .35s, background .35s, border-color .35s;
  outline: none
}

.pil-c.pillar-card:hover {
  transform: translateY(-8px) scale(1.02);
  border-color: var(--red);
  box-shadow: 0 12px 24px rgba(0, 0, 0, .12), 0 18px 45px rgba(188, 0, 45, .22)
}

.pil-c.pillar-card:active {
  transform: translateY(-2px) scale(1.005);
  box-shadow: 0 6px 14px rgba(0, 0, 0, .18);
  transition-duration: .08s
}

.pil-c.pillar-card:focus-visible {
  transform: translateY(-8px) scale(1.02);
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(212, 160, 23, .55), 0 12px 24px rgba(0, 0, 0, .12)
}

.pil-more {
  display: inline-block;
  margin-top: .85rem;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--gold);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity .3s, transform .3s
}

.pil-c.pillar-card:hover .pil-more,
.pil-c.pillar-card:focus-visible .pil-more {
  opacity: 1;
  transform: translateX(0)
}

@media(prefers-reduced-motion:reduce) {

  .pil-c.pillar-card,
  .pil-more {
    transition: none
  }

  .pil-c.pillar-card:hover,
  .pil-c.pillar-card:focus-visible {
    transform: none
  }
}

/* Pillar detail dialog */
.pmodal {
  position: fixed;
  inset: 0;
  z-index: 110;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem
}

.pmodal.hide {
  display: none !important
}

.pmodal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(3, 20, 48, .72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px)
}

.pmodal-card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 34rem;
  max-height: 88vh;
  overflow-y: auto;
  background: var(--w);
  border-radius: 24px;
  padding: 2rem 1.5rem 1.5rem;
  box-shadow: 0 30px 80px rgba(0, 0, 0, .4);
  animation: pmodalIn .3s cubic-bezier(.2, .7, .3, 1);
  outline: none
}

@keyframes pmodalIn {
  from {
    opacity: 0;
    transform: translateY(18px) scale(.97)
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1)
  }
}

.pmodal-x {
  position: absolute;
  top: .85rem;
  right: .95rem;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: var(--soft);
  color: var(--slate);
  border-radius: 50%;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  transition: all .2s
}

.pmodal-x:hover {
  background: var(--red);
  color: var(--w)
}

.pmodal-num {
  font-family: monospace;
  font-size: .75rem;
  letter-spacing: .1em;
  color: var(--slate)
}

.pmodal-ic {
  font-size: 2.25rem;
  margin: .35rem 0 .5rem
}

.pmodal-title {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--navy);
  line-height: 1.25
}

.pmodal-lead {
  margin-top: .6rem;
  font-size: .9375rem;
  font-weight: 600;
  color: var(--red);
  line-height: 1.55
}

.pmodal-text {
  margin-top: .75rem;
  font-size: .9375rem;
  color: var(--slate);
  line-height: 1.7
}

.pmodal-list {
  margin-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: .5rem
}

.pmodal-list li {
  position: relative;
  padding-left: 1.5rem;
  font-size: .875rem;
  color: var(--char);
  line-height: 1.55
}

.pmodal-list li::before {
  content: '\2726';
  position: absolute;
  left: 0;
  top: 0;
  color: var(--red);
  font-size: .8125rem
}

.pmodal-foot {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid rgba(0, 0, 0, .08)
}

@media(min-width:640px) {
  .pmodal-card {
    padding: 2.25rem
  }

  .pmodal-title {
    font-size: 1.75rem
  }
}

/* ==================================================================
   STAFF DASHBOARD (glassmorphic control panel)
   ================================================================== */
.dash-shell {
  background: linear-gradient(160deg, #eef1f7 0%, #f7f8fa 40%, #fdf2f4 100%);
  min-height: 90vh;
  overflow-x: hidden
}

/* Wrapper: full width, capped, centred, border-box so padding never adds width. */
.dash-shell .dash-l {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  background: transparent;
  gap: 0;
  box-sizing: border-box
}

.dash-shell .dash-sb {
  background: rgba(255, 255, 255, .62);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-right: 1px solid rgba(255, 255, 255, .7);
  box-shadow: 1px 0 30px rgba(5, 33, 81, .05);
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  min-width: 0
}

.dash-shell .dash-main {
  padding: 20px;
  min-width: 0;
  box-sizing: border-box
}

/* min-width:0 on both grid children: grid items default to min-width:auto, so a
   wide table or long word forces the track open and scrolls the whole page. */

/* Brand: stacked, so the wide logo lockup never collides with the title. */
.dash-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .5rem;
  text-decoration: none
}

.dash-brand-logo {
  display: block;
  width: 100%;
  max-width: 150px;
  height: auto
}

.dash-brand-txt {
  display: block;
  line-height: 1.25
}

.dash-brand-mark {
  width: 38px;
  height: 38px;
  border-radius: 11px;
  background: var(--red);
  color: var(--w);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: .8125rem;
  flex-shrink: 0
}

.dash-brand strong {
  display: block;
  font-size: .875rem;
  font-weight: 700;
  color: var(--navy)
}

.dash-brand small {
  display: block;
  font-size: .75rem;
  color: var(--slate)
}

.dash-sb-foot {
  margin-top: auto;
  padding-top: 1rem;
  border-top: 1px solid rgba(0, 0, 0, .07);
  display: flex;
  flex-direction: column;
  gap: .15rem
}

.dash-mini {
  display: block;
  padding: .45rem .6rem;
  border-radius: 10px;
  font-size: .8125rem;
  color: var(--slate);
  transition: all .2s
}

.dash-mini:hover {
  background: rgba(188, 0, 45, .07);
  color: var(--red)
}

.dash-mini.danger:hover {
  background: rgba(220, 38, 38, .1);
  color: #dc2626
}

.dash-topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .6rem .9rem;
  margin-bottom: 1.25rem;
  border-radius: 14px;
  background: rgba(255, 255, 255, .6);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, .8)
}

.dash-topbar form {
  margin: 0
}

.dash-who {
  font-size: .8125rem;
  color: var(--slate)
}

.dash-who strong {
  color: var(--navy)
}

.dash-signout {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  font-family: inherit;
  cursor: pointer
}

.dash-sb-foot form {
  margin: 0
}

.dash-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem
}

.dash-h1 {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--navy)
}

.dash-sub {
  font-size: .875rem;
  color: var(--slate);
  margin-top: .15rem
}

.dash-card {
  background: rgba(255, 255, 255, .72);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, .85);
  border-radius: 20px;
  padding: 1.25rem;
  box-shadow: 0 8px 32px rgba(5, 33, 81, .07)
}

.dash-card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1rem
}

.dash-card-head h2 {
  font-size: 1rem;
  font-weight: 700;
  color: var(--navy)
}

.dash-link {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--red)
}

/* auto-fit + minmax: cards reflow to fill the row at any width instead of
   being locked to a fixed column count that overflows on small screens. */
.dash-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 16px;
  margin-bottom: 1.25rem
}

.dash-stat-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  gap: .35rem;
  padding: 1.15rem 1.25rem;
  min-width: 0
}

.dash-stat-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 40px rgba(5, 33, 81, .13)
}

.dash-stat-icon {
  font-size: 1.35rem;
  line-height: 1
}

.dash-stat-num {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.875rem;
  font-weight: 700;
  color: var(--navy);
  line-height: 1.05
}

.dash-stat-lbl {
  font-size: .75rem;
  color: var(--slate);
  font-weight: 500;
  line-height: 1.35
}

.dash-stat-card {
  transition: transform .25s, box-shadow .25s
}

.dash-two {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem
}

.dash-feed {
  display: flex;
  flex-direction: column
}

.dash-feed-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .75rem;
  padding: .7rem 0;
  border-bottom: 1px solid rgba(0, 0, 0, .06)
}

.dash-feed-row:last-child {
  border-bottom: none
}

.dash-feed-main strong {
  display: block;
  font-size: .875rem;
  color: var(--navy);
  font-weight: 600
}

.dash-feed-main small {
  display: block;
  font-size: .75rem;
  color: var(--slate);
  margin-top: .1rem
}

.dash-feed-side {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-shrink: 0
}

.dash-feed-side small {
  font-size: .75rem;
  color: var(--slate)
}

.dash-quick {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: .5rem
}

.dash-quick-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .7rem .85rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, .7);
  border: 1px solid rgba(0, 0, 0, .05);
  font-size: .8125rem;
  font-weight: 500;
  color: var(--char);
  transition: all .2s
}

.dash-quick-item:hover {
  background: var(--red);
  color: var(--w);
  border-color: var(--red);
  transform: translateY(-2px)
}

.dash-filters {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  margin-bottom: 1rem
}

.dash-filters .f-in {
  flex: 1;
  min-width: 170px;
  background: rgba(255, 255, 255, .8)
}

.dash-table-card {
  padding: .5rem
}

.dash-table-scroll {
  overflow-x: auto
}

.dash-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .8125rem
}

.dash-table th {
  text-align: left;
  padding: .7rem .75rem;
  font-size: .6875rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--slate);
  font-weight: 700;
  border-bottom: 1px solid rgba(0, 0, 0, .08);
  white-space: nowrap
}

.dash-table td {
  padding: .7rem .75rem;
  border-bottom: 1px solid rgba(0, 0, 0, .05);
  color: var(--char);
  vertical-align: middle
}

.dash-table tbody tr:last-child td {
  border-bottom: none
}

.dash-table tbody tr:hover {
  background: rgba(188, 0, 45, .035)
}

.dash-thumb {
  width: 38px;
  height: 38px;
  border-radius: 9px;
  object-fit: cover;
  border: 1px solid rgba(0, 0, 0, .08)
}

/* ── Dashboard notification bell ──────────────────────────────────────── */
.dsh-bell {
  position: relative
}

.dsh-bell>summary {
  list-style: none;
  cursor: pointer;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  font-size: 1.05rem;
  border: 1px solid rgba(0, 0, 0, .1);
  background: #fff;
  transition: background .18s, border-color .18s
}

.dsh-bell>summary::-webkit-details-marker {
  display: none
}

.dsh-bell>summary:hover {
  background: var(--soft);
  border-color: rgba(0, 0, 0, .18)
}

/* ---- account (kebab) menu ----
   Same <details> mechanics as the bell beside it. It carries an avatar and the
   username now rather than a lone glyph, so it is a pill that grows with its
   label instead of the bell's 36px square — but it keeps that 36px height, so
   the two still sit as one pair of controls on a shared baseline.

   The width MUST stay auto. This trigger was a fixed 36px box when it held one
   icon; leaving that in place while the content grew to an avatar plus a name
   made the content overflow a 36px box that was still centring it, so the
   avatar spilled leftwards over the bell. */
.dsh-kebab {
  position: relative
}

.dsh-kebab>summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  gap: .5rem;
  width: auto;
  height: 36px;
  padding: 0 .625rem 0 .125rem;
  border-radius: 999px;
  color: var(--dsh-mut);
  border: 1px solid rgba(0, 0, 0, .1);
  background: #fff;
  transition: background .18s, border-color .18s, color .18s
}

/* The username, not the avatar, is what gives up room when the header is tight:
   a truncated name is still a name, and the avatar stops being a recognisable
   marker the moment it is squeezed out of round. */
.dsh-kebab>summary .dsh-kebab-name {
  max-width: 10rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

.dsh-kebab>summary::-webkit-details-marker {
  display: none
}

.dsh-kebab>summary:hover,
.dsh-kebab[open]>summary {
  background: var(--soft);
  border-color: rgba(0, 0, 0, .18);
  color: var(--dsh-ink)
}

.dsh-kebab>summary:focus-visible {
  outline: 2px solid var(--dsh-red);
  outline-offset: 2px
}

/* Above the bell panel's 120: whichever was opened last should be the one on
   top, and only one of them can be open at a time anyway. */
.dsh-kebab-panel {
  position: absolute;
  top: calc(100% + .5rem);
  right: 0;
  z-index: 130;
  width: min(230px, calc(100vw - 2rem));
  padding: .35rem;
  background: #fff;
  border: 1px solid #e2e8f0;
  border-radius: 14px;
  box-shadow: 0 18px 40px -16px rgba(15, 23, 42, .3)
}

.dsh-kebab-who {
  padding: .5rem .65rem .6rem;
  margin-bottom: .25rem;
  border-bottom: 1px solid #f1f5f9
}

.dsh-kebab-who strong {
  display: block;
  font-size: .8125rem;
  font-weight: 700;
  color: var(--dsh-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

.dsh-kebab-who small {
  display: block;
  font-size: .6875rem;
  color: #94a3b8;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

/* One rule for both the links and the logout <button>, so the submit button
   does not need a second set of resets to sit level with them. */
.dsh-kebab-i {
  display: flex;
  align-items: center;
  gap: .6rem;
  width: 100%;
  padding: .55rem .65rem;
  border: 0;
  border-radius: 9px;
  background: none;
  font: inherit;
  font-size: .78125rem;
  font-weight: 600;
  text-align: left;
  color: #334155;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s, color .15s
}

.dsh-kebab-i svg {
  flex: none;
  color: #94a3b8;
  transition: color .15s
}

.dsh-kebab-i:hover {
  background: #f8fafc;
  color: var(--dsh-red)
}

.dsh-kebab-i:hover svg {
  color: var(--dsh-red)
}

.dsh-kebab-i:focus-visible {
  outline: 2px solid var(--dsh-red);
  outline-offset: -2px
}

.dsh-kebab-i.is-danger {
  color: var(--dsh-red)
}

.dsh-kebab-i.is-danger svg {
  color: var(--dsh-red)
}

.dsh-kebab-i.is-danger:hover {
  background: #fef2f2
}

.dsh-kebab-sep {
  height: 1px;
  margin: .25rem .3rem;
  background: #f1f5f9
}

.dsh-bell-count {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--red);
  color: #fff;
  font-size: .6875rem;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  box-shadow: 0 0 0 2px #fff
}

.dsh-bell-panel {
  position: absolute;
  top: calc(100% + .5rem);
  right: 0;
  z-index: 120;
  width: min(360px, calc(100vw - 2rem));
  max-height: 26rem;
  overflow-y: auto;
  background: #fff;
  border: 1px solid #e2e8f0;
  border-radius: 14px;
  box-shadow: 0 18px 40px -16px rgba(15, 23, 42, .3)
}

.dsh-bell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .75rem 1rem;
  border-bottom: 1px solid #e2e8f0;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #0f172a;
  position: sticky;
  top: 0;
  background: #fff
}

/* One preview row, and the whole row is the link — it goes to the Notification
   Center, which is where anything can actually be done about it. The panel
   carries no buttons of its own. */
.dsh-bell-i {
  display: flex;
  gap: .6rem;
  align-items: flex-start;
  padding: .75rem 1rem;
  border-bottom: 1px solid #f1f5f9;
  color: inherit;
  text-decoration: none
}

.dsh-bell-i:last-child {
  border-bottom: 0
}

.dsh-bell-i:hover {
  background: #f8fafc
}

/* Unread: tinted row plus a heavier sender line. Read notifications stay in
   the list — the bell is history as well as an inbox — so the two states have
   to be tellable apart at a glance. */
.dsh-bell-i.is-unread {
  background: rgba(37, 99, 235, .06)
}

.dsh-bell-i.is-unread:hover {
  background: rgba(37, 99, 235, .1)
}

.dsh-bell-i.is-unread .dsh-bell-b strong {
  font-weight: 700
}

/* Read state, shown and not actioned: blue for unread, grey once it has been
   opened. Both states occupy the same 24px column so the text does not reflow
   when a row is read. */
.dsh-bell-dot {
  flex: none;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center
}

.dsh-bell-dot::after {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: #2563eb
}

.dsh-bell-dot.is-read::after {
  background: #cbd5e1
}

.dsh-bell-all {
  display: block;
  padding: .7rem 1rem;
  border-top: 1px solid #e2e8f0;
  background: #f8fafc;
  text-align: center;
  font-size: .75rem;
  font-weight: 700;
  color: var(--navy)
}

.dsh-bell-all:hover {
  background: #eef2f7;
  color: var(--red)
}

.dsh-bell-ic {
  flex: none;
  font-size: 1rem;
  line-height: 1.3
}

.dsh-bell-b {
  flex: 1;
  min-width: 0
}

.dsh-bell-t {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem;
  font-size: .8125rem;
  color: #0f172a;
  line-height: 1.35
}

.dsh-bell-t strong {
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

.dsh-bell-i:hover .dsh-bell-t strong {
  color: var(--red)
}

/* Request type, kept quiet so the sender's name leads the row. */
.dsh-bell-kind {
  flex: none;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--red);
  background: rgba(188, 0, 45, .08);
  border-radius: 999px;
  padding: .1rem .45rem
}

.dsh-bell-msg {
  display: block;
  margin: .15rem 0 0;
  font-size: .75rem;
  line-height: 1.5;
  color: var(--slate)
}

.dsh-bell-b small {
  display: block;
  margin-top: .25rem;
  font-size: .6875rem;
  color: #94a3b8
}

.dsh-bell-empty {
  margin: 0;
  padding: 1.5rem 1rem;
  text-align: center;
  font-size: .8125rem;
  color: #94a3b8
}

/* Table thumbnails open full size in the shared lightbox. */
.dash-zoom {
  display: inline-block;
  line-height: 0;
  cursor: zoom-in
}

.dash-zoom img {
  transition: opacity .18s
}

.dash-zoom:hover img {
  opacity: .8
}

.dash-muted {
  color: var(--slate)
}

.dash-dot {
  font-size: .8rem
}

.dash-dot.on {
  color: #16a34a
}

.dash-dot.off {
  color: #dc2626
}

.dash-actions-col {
  text-align: right
}

.dash-actions {
  display: flex;
  gap: .3rem;
  justify-content: flex-end;
  align-items: center
}

.dash-actions form {
  display: inline
}

.dash-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .3rem;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  border: 1px solid rgba(0, 0, 0, .1);
  background: var(--w);
  color: var(--char);
  font-size: .8125rem;
  cursor: pointer;
  transition: all .2s;
  padding: 0
}

.dash-btn:hover {
  background: var(--navy);
  color: var(--w);
  border-color: var(--navy)
}

.dash-btn.danger:hover {
  background: #dc2626;
  border-color: #dc2626;
  color: var(--w)
}

.dash-btn.ok {
  width: auto;
  padding: 0 .7rem;
  font-size: .75rem;
  font-weight: 600
}

.dash-btn.ok:hover {
  background: #16a34a;
  border-color: #16a34a
}

.dash-btn.lg {
  width: auto;
  height: auto;
  padding: .6rem 1.1rem;
  font-size: .875rem;
  font-weight: 600
}

.dash-pager {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: .75rem;
  padding: 1rem;
  flex-wrap: wrap
}

.dash-form-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem
}

.dash-field {
  display: flex;
  flex-direction: column;
  gap: .35rem
}

.dash-field>label {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--navy)
}

.dash-field>label em {
  color: var(--red);
  font-style: normal
}

.dash-field .f-in {
  background: rgba(255, 255, 255, .9)
}

.dash-check-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .875rem;
  font-weight: 500;
  cursor: pointer;
  padding: .6rem .75rem;
  background: rgba(255, 255, 255, .7);
  border: 1px solid rgba(0, 0, 0, .08);
  border-radius: 12px
}

.dash-check {
  width: 17px;
  height: 17px;
  accent-color: var(--red);
  cursor: pointer
}

.dash-help {
  font-size: .75rem;
  color: var(--slate)
}

.dash-err {
  font-size: .75rem;
  color: var(--red);
  font-weight: 600
}

.dash-form-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid rgba(0, 0, 0, .08);
  flex-wrap: wrap
}

.dash-alert {
  padding: .8rem 1rem;
  border-radius: 12px;
  font-size: .875rem;
  margin-bottom: 1rem
}

.dash-alert.error {
  background: rgba(188, 0, 45, .09);
  color: var(--red);
  font-weight: 500
}

.dash-empty {
  text-align: center;
  padding: 2.5rem 1rem;
  color: var(--slate)
}

.dash-empty-icon {
  font-size: 2.25rem;
  display: block;
  margin-bottom: .5rem;
  opacity: .55
}

.dash-empty-icon svg {
  width: 2.25rem;
  height: 2.25rem;
}

.dash-empty strong {
  display: block;
  color: var(--navy);
  font-size: 1rem;
  margin-bottom: .25rem
}

.dash-empty p {
  font-size: .8125rem;
  max-width: 24rem;
  margin: 0 auto
}

/* Long values (emails, org names, slugs) must not push the layout wider. */
.dash-feed-main strong,
.dash-feed-main small,
.dash-who {
  overflow-wrap: anywhere
}

.dash-table-scroll {
  max-width: 100%;
  -webkit-overflow-scrolling: touch
}

.dash-quick {
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr))
}

@media(min-width:640px) {
  .dash-form-grid {
    grid-template-columns: 1fr 1fr
  }

  .dash-field.span-2 {
    grid-column: 1/-1
  }

  .dash-shell .dash-main {
    padding: 2rem
  }
}

@media(min-width:1024px) {
  .dash-two {
    grid-template-columns: 1fr 1fr
  }

  .dash-brand {
    flex-direction: row;
    align-items: center;
    gap: .6rem
  }

  .dash-brand-logo {
    max-width: 104px
  }
}

/* ==================================================================
   JEPAN CONTROL PANEL
   Every rule is scoped under `.dsh`, the outermost dashboard element.
   `.dsh` exists only on dashboard pages, so nothing here can affect the
   public site — while still reaching the sidebar and header, which live
   in dashboard_base.html (a PARENT of the per-page content wrapper).
   ================================================================== */
.dsh {
  --dsh-navy: #052151;
  --dsh-panel: #0A1836;
  --dsh-red: #BC002D;
  --dsh-canvas: #F8FAFC;
  --dsh-line: #E2E8F0;
  --dsh-ink: #0F172A;
  --dsh-mut: #64748B;
  --dsh-rail: 264px;
  /* Not a flex row any more: the sidebar is taken out of flow by position:
     fixed, so there is nothing left for the parent to lay out beside it. The
     content column is inset by --dsh-rail instead. */
  display: block;
  min-height: 100vh;
  background: var(--dsh-canvas);
  font-family: 'Plus Jakarta Sans', 'Inter', system-ui, sans-serif;
  color: var(--dsh-ink)
}

/* ---- sidebar ----
   Fixed to the left edge at every width and never collapsible. It used to be
   sticky inside the flex row on desktop and slide off-canvas below 1024px
   behind a checkbox toggle; the toggle, its scrim and the ☰ button are gone. */
/* The panel sits a shade deeper than the public site's navy. That is deliberate:
   the two are never on screen together, and the darker ground lets the red of
   the active row and the white of the headings carry the whole hierarchy
   without a second accent colour. The hairline on the right edge separates the
   panel from the light canvas instead of leaving the two colours to butt. */
.dsh .dsh-sidebar {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  /* Above the sticky header (100) and the form action bar (90). They do not
     overlap it horizontally, but a fixed panel that anything can cover is one
     bug away from being invisible. */
  z-index: 120;
  width: var(--dsh-rail);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--dsh-panel);
  border-right: 1px solid rgba(255, 255, 255, .08);
  display: flex;
  flex-direction: column;
  gap: .25rem;
  padding: 1rem 0;
  /* The menu is a navigation surface, not a document — drag-selecting it while
     reaching for a link only ever produces a blue smear. */
  user-select: none
}

/* A default scrollbar renders as a light gutter down the dark panel. Thin and
   tinted so a long menu scrolls without a white stripe beside it. */
.dsh .dsh-sidebar {
  scrollbar-width: thin;
  scrollbar-color: rgba(148, 163, 184, .35) transparent
}

.dsh .dsh-sidebar::-webkit-scrollbar {
  width: 6px
}

.dsh .dsh-sidebar::-webkit-scrollbar-track {
  background: transparent
}

.dsh .dsh-sidebar::-webkit-scrollbar-thumb {
  background: rgba(148, 163, 184, .35);
  border-radius: 3px
}

.dsh .dsh-sidebar::-webkit-scrollbar-thumb:hover {
  background: rgba(148, 163, 184, .55)
}

/* Brand: the logo alone, as one link back to the live site. */
.dsh .dsh-brand {
  display: block;
  padding: .25rem 1.15rem 1rem;
  margin-bottom: .5rem;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  text-decoration: none
}

.dsh .dsh-brand-logo {
  display: block;
  width: 100%;
  max-width: 168px;
  height: auto
}

.dsh .dsh-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0 .75rem;
  overflow-y: auto;
  flex: 1
}

/* Sidebar accordion. Each menu group is a <details>, so opening and closing is
   native browser behaviour — the control panel keeps working with no JS, the
   same bet the notification bell and the public mobile menu make. */
.dsh .dsh-grp {
  border-radius: 9px
}

.dsh .dsh-grp-body {
  display: flex;
  flex-direction: column;
  gap: 2px
}

/* Group headings. These once sat at 34% white — about 2.5:1 on the panel, well
   under the 4.5:1 WCAG AA floor. They are a fixed slate now rather than a white
   alpha: #94A3B8 on the #0A1836 ground measures ~6.8:1, so the label can drop
   back to 10px and still clear AA with room to spare. The tracking stays a
   notch under the .09em it used to carry, because wide letter spacing at this
   size is what made the old headings read as faint as much as the colour did. */
.dsh .dsh-nav-lbl {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .9rem .6rem .35rem;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: #94A3B8;
  cursor: pointer;
  /* The default disclosure triangle sits before the text and cannot be styled
     consistently across browsers; ::after below draws our own on the right. */
  list-style: none;
  transition: color .18s
}

.dsh .dsh-nav-lbl::-webkit-details-marker {
  display: none
}

.dsh .dsh-nav-lbl:hover {
  color: #fff
}

.dsh .dsh-nav-lbl::after {
  content: '▾';
  font-size: .7rem;
  letter-spacing: 0;
  opacity: .7;
  transition: transform .18s
}

/* An open group's heading is not dimmed — the caret already says which state it
   is in, and fading the label of the group you are working in was the single
   worst offender for legibility. */
.dsh .dsh-grp[open]>.dsh-nav-lbl {
  color: #CBD5E1
}

.dsh .dsh-grp[open]>.dsh-nav-lbl::after {
  transform: rotate(180deg)
}

/* A collapsed group holding the current screen would hide where you are, so the
   heading carries the marker instead. sidebar_tree() opens that group anyway;
   this covers the case where it has been clicked shut. */
.dsh .dsh-grp:not([open]):has(.dsh-nav-i.is-active)>.dsh-nav-lbl {
  color: #fff
}

.dsh .dsh-grp:not([open]):has(.dsh-nav-i.is-active)>.dsh-nav-lbl::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--red);
  flex: none
}

/* Menu rows. 68% white on the navy panel is roughly 4:1 — just under AA, and
   the rows that carry the whole menu are the last place to be saving contrast.
   88% clears AA comfortably while staying a clear step below the white of the
   active row, so "where I am" still reads at a glance. */
.dsh .dsh-nav-i {
  position: relative;
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .5rem .7rem;
  border-radius: 8px;
  font-size: .78125rem;
  font-weight: 500;
  color: #CBD5E1;
  transition: background .18s, color .18s
}

.dsh .dsh-nav-i:hover {
  background: rgba(148, 163, 184, .14);
  color: #fff
}

/* The overview link, pinned above the groups and set apart from them: a larger
   radius and a full row of breathing space below, so it reads as the panel's
   home rather than the first entry of the first category. */
.dsh .dsh-nav-i--top {
  margin: .25rem 0 1.1rem;
  padding: .65rem .7rem;
  border-radius: 11px;
  font-size: .8125rem;
  font-weight: 600;
  color: #fff
}

/* A destination that sits among the groups without being one of them (Global
   Settings). Same weight as the overview row above, and a rule above it so it
   does not read as the last orphaned entry of the group it follows. */
.dsh .dsh-nav-i--pin {
  margin: .8rem 0 .25rem;
  padding: .6rem .7rem;
  border-radius: 11px;
  font-size: .8125rem;
  font-weight: 600;
  color: #fff
}

.dsh .dsh-nav-i--pin::after {
  content: '';
  position: absolute;
  left: .7rem;
  right: .7rem;
  top: -.45rem;
  height: 1px;
  background: rgba(255, 255, 255, .08)
}

/* The divider belongs between the groups and this row, not above a row that
   already has the panel's own top edge above it. */
.dsh .dsh-nav-i--pin:first-child::after {
  display: none
}

/* Active row: subtle highlight with primary red text, no bolding to prevent 
   horizontal sliding, and a flat slate-like background to match hover. */
.dsh .dsh-nav-i.is-active {
  background: rgba(148, 163, 184, .14);
  color: var(--red);
  font-weight: 500;
  box-shadow: none;
}

/* Icons are emoji, supplied by the section registry. Held a touch back from
   full saturation so a row reads label-first and the column of glyphs does not
   compete with the one red row that marks where you are. The active row and
   hover restore them, since there the icon is meant to be part of the accent. */
.dsh .dsh-nav-ic {
  width: 18px;
  text-align: center;
  font-size: .8125rem;
  flex-shrink: 0;
  opacity: .78;
  transition: opacity .18s
}

.dsh .dsh-nav-i:hover .dsh-nav-ic,
.dsh .dsh-nav-i.is-active .dsh-nav-ic,
.dsh .dsh-nav-i--top .dsh-nav-ic {
  opacity: 1
}

.dsh .dsh-nav-t {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

/* Unread counter on a sidebar entry (Member Requests). margin-left:auto pins
   it to the right edge whatever the label's length.

   A tinted pill with a red rim rather than a solid red dot: solid red is what
   the active row is made of, and two saturated reds in one column left "you are
   here" and "there is work waiting" fighting for the same signal. The rim keeps
   the count legible against the panel without claiming that weight. */
.dsh .dsh-nav-badge {
  margin-left: auto;
  flex-shrink: 0;
  min-width: 20px;
  height: 19px;
  padding: 0 6px;
  border-radius: 999px;
  background: rgba(188, 0, 45, .22);
  border: 1px solid rgba(239, 68, 68, .38);
  color: #FCA5A5;
  font-size: .625rem;
  font-weight: 700;
  line-height: 17px;
  text-align: center
}

/* The tinted pill keeps its normal styling on the active row since it is no longer solid red. */

.dsh .dsh-sidebar-foot {
  margin-top: auto;
  padding: .75rem .75rem .25rem;
  border-top: 1px solid rgba(255, 255, 255, .08)
}

/* Account card: the profile chip and the Django Admin gear on one row. The
   chip is the flexible half so a long username truncates instead of pushing
   the gear off the panel. */
.dsh .dsh-user-card {
  display: flex;
  align-items: center;
  gap: .35rem
}

/* An <a> to the profile screen: kill the default link look, keep the chip. */
.dsh .dsh-user {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .5rem .55rem;
  border-radius: 10px;
  background: transparent;
  color: inherit;
  text-decoration: none;
  transition: background .15s ease
}

.dsh a.dsh-user:hover,
.dsh a.dsh-user:focus-visible {
  background: rgba(148, 163, 184, .14)
}

.dsh a.dsh-user:focus-visible,
.dsh a.dsh-cog:focus-visible {
  outline: 2px solid var(--dsh-red);
  outline-offset: 2px
}

/* Tinted rather than solid: the avatar is an identifier, not a control, and a
   filled red disc at the foot of the panel pulled the eye away from the active
   nav row it is supposed to sit quietly beneath. */
.dsh .dsh-avatar {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(188, 0, 45, .2);
  border: 1px solid rgba(239, 68, 68, .42);
  color: #F87171;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: .78125rem
}

/* Django Admin, as an icon button on the card's right edge. */
.dsh .dsh-cog {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  color: #94A3B8;
  transition: background .15s ease, color .15s ease
}

.dsh .dsh-cog:hover {
  background: rgba(148, 163, 184, .16);
  color: #fff
}

.dsh .dsh-cog svg {
  width: 16px;
  height: 16px;
  display: block
}

.dsh .dsh-user-txt {
  min-width: 0
}

.dsh .dsh-user-txt strong {
  display: block;
  font-size: .8125rem;
  color: #fff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

.dsh .dsh-user-txt small {
  display: block;
  font-size: .625rem;
  color: #94A3B8;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

/* ==================================================================
   Shared dashboard form components.

   These live here rather than in core/partials/dash_cms_styles.html because
   they travel with a *widget*, not with a layout. Any screen that renders a
   FileField gets the dropzone markup whether or not it includes that partial —
   Site Settings does exactly that — and a component whose appearance depends
   on the host template remembering an include is a component that will
   eventually render raw. Scoped to .dsh, which every dashboard page has and
   no public page does.
   ================================================================== */

/* ---- upload dropzone (core/templates/dash/file_input.html) ----
   Replaces Django's "Currently: … ☐ Clear … Change: [Choose File]" line. */
.dsh .dash-drop {
  display: flex;
  flex-direction: column;
  gap: .6rem
}

/* The file already on the server: a small thumbnail, not a preview. Screens
   that want a large one draw their own — two full-size copies of the same
   picture in one card only makes the card long. */
.dsh .dash-drop-cur {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .6rem .75rem;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: 11px
}

.dsh .dash-drop-thumb {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 8px;
  object-fit: cover;
  background: #fff;
  border: 1px solid #e2e8f0
}

.dsh .dash-drop-thumb.is-doc {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem
}

.dsh .dash-drop-meta {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .1rem
}

.dsh .dash-drop-meta a {
  font-size: .75rem;
  font-weight: 600;
  color: #334155;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

.dsh .dash-drop-meta a:hover {
  color: var(--dsh-red);
  text-decoration: underline
}

.dsh .dash-drop-live {
  font-size: .6875rem;
  font-weight: 600;
  color: #059669
}

/* "Remove" reads as the action; the checkbox stays the control that carries
   it, so the POST is the same one the stock widget would have sent. */
.dsh .dash-drop-clear {
  flex: none;
  display: flex;
  align-items: center;
  gap: .35rem;
  cursor: pointer;
  font-size: .75rem;
  font-weight: 600;
  color: #94a3b8;
  transition: color .18s
}

.dsh .dash-drop-clear:hover {
  color: var(--dsh-red)
}

.dsh .dash-drop-clear input {
  accent-color: var(--dsh-red);
  cursor: pointer
}

.dsh .dash-drop-zone {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .15rem;
  padding: 1.15rem 1rem;
  text-align: center;
  cursor: pointer;
  background: #fcfdfe;
  border: 2px dashed #e2e8f0;
  border-radius: 12px;
  color: #94a3b8;
  transition: border-color .18s, background .18s, color .18s
}

.dsh .dash-drop-zone:hover,
.dsh .dash-drop-zone.is-over {
  border-color: var(--dsh-red);
  background: #fff7f8;
  color: var(--dsh-red)
}

/* Keyboard focus lands on the input inside, which is off-screen — so the ring
   is drawn on the zone around it instead. */
.dsh .dash-drop-zone:focus-within {
  border-color: var(--dsh-red);
  box-shadow: 0 0 0 3px rgba(188, 0, 45, .12)
}

/* The widget also carries width/height as attributes. This is the size that
   should apply; those are the floor that stops an unstyled render blowing up
   to the 300×150 an <svg> defaults to. */
.dsh .dash-drop-zone svg {
  width: 22px;
  height: 22px;
  margin-bottom: .15rem
}

.dsh .dash-drop-cta {
  font-size: .8125rem;
  font-weight: 600;
  color: #334155
}

.dsh .dash-drop-hint {
  font-size: .6875rem;
  color: #94a3b8
}

/* Off-screen rather than display:none, which would drop it out of the tab
   order and make the field unreachable by keyboard. */
.dsh .dash-drop-zone input[type=file] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none
}

/* The chosen filename, written by the dropzone script in main.js. */
.dsh .dash-drop-name {
  margin: 0;
  font-size: .75rem;
  font-weight: 600;
  color: #059669;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

/* ---- fixed action bar ----
   Save used to ride the CMS edit screen's sticky settings column; with that
   column gone, this is what keeps it reachable from anywhere in a long form.
   Fixed to the viewport and inset from the left by the sidebar's width, so it
   spans the content column only — below 1024px the sidebar is off-canvas and
   the inset drops to 0. z-index sits under the dashboard header's 100. */
.dsh .dash-form,
.dsh .dash-has-bar {
  padding-bottom: 5.5rem
}

.dsh .dash-bar {
  position: fixed;
  bottom: 0;
  /* Matches the content column's inset at every width — the sidebar no longer
     goes off-canvas, so this no longer drops to 0 on narrow screens. */
  left: var(--dsh-rail);
  right: 0;
  z-index: 90;
  background: rgba(255, 255, 255, .92);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--dsh-line);
  box-shadow: 0 -4px 16px rgba(15, 23, 42, .06)
}

.dsh .dash-bar-in {
  max-width: 64rem;
  margin: 0 auto;
  padding: .85rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem
}

/* Screens whose content column is wider than the CMS editor's 64rem line the
   bar up with their own measure instead. */
.dsh .dash-bar-in--wide {
  max-width: 72rem
}

.dsh .dash-bar-l {
  min-width: 0
}

.dsh .dash-bar-r {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex: none
}

.dsh .dash-bar-note {
  font-size: .75rem;
  color: #94a3b8
}

/* Used as an <a> on the CMS edit screens (Delete) and as a <button> on the
   profile screen (Sign out, which must POST), so it carries the button resets
   rather than needing a second class to sit level with the link form. */
.dsh .dash-bar-del {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: .75rem;
  color: #94a3b8;
  text-decoration: none;
  cursor: pointer;
  transition: color .18s
}

.dsh .dash-bar-del:hover {
  color: var(--dsh-red);
  text-decoration: underline
}

.dsh .dash-bar-save {
  display: inline-flex;
  align-items: center;
  gap: .4rem
}

.dsh .dash-bar-save svg {
  width: 14px;
  height: 14px;
  flex: none
}

.dsh .dash-bar-save:active {
  transform: scale(.97)
}

/* Two lines of controls in the bar is worse than a taller bar; on narrow
   screens the note is the half that can go. */
@media(max-width:560px) {
  .dsh .dash-bar-in {
    padding: .7rem 1rem
  }

  .dsh .dash-bar-note {
    display: none
  }
}

/* ---- content column ---- */
.dsh .dsh-content {
  /* Inset by the sidebar's width. The sidebar is fixed, so it occupies no
     space in flow and would otherwise sit on top of this column. */
  margin-left: var(--dsh-rail);
  min-width: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column
}

/* ---- sticky header ---- */
.dsh .dsh-header {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .9rem 1.5rem;
  background: #fff;
  border-bottom: 1px solid var(--dsh-line)
}

.dsh .dsh-header-l {
  display: flex;
  align-items: center;
  gap: .85rem;
  min-width: 0
}

.dsh .dsh-header-r {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap
}

.dsh .dsh-h1 {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--dsh-ink);
  line-height: 1.2
}

.dsh .dsh-crumb {
  font-size: .8125rem;
  color: var(--dsh-mut);
  margin-top: .1rem
}

.dsh .dsh-logout-form {
  margin: 0
}

.dsh .dsh-pill {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .3rem .7rem;
  border-radius: 999px;
  font-size: .6875rem;
  font-weight: 600;
  white-space: nowrap
}

.dsh .dsh-pill--ok {
  background: #ECFDF5;
  color: #047857;
  border: 1px solid #A7F3D0
}

.dsh .dsh-pill--ok i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #10B981
}

.dsh .dsh-pill--role {
  background: #EEF2FF;
  color: #3730A3;
  border: 1px solid #C7D2FE;
  text-decoration: none;
  transition: background .15s ease, border-color .15s ease
}

/* Also a link to the profile — same target as the sidebar chip. */
.dsh a.dsh-pill--role:hover,
.dsh a.dsh-pill--role:focus-visible {
  background: #E0E7FF;
  border-color: #A5B4FC
}

/* ---- dashboard buttons ----
   Two tiers, and only two:

     .btn-p    solid red — the one thing this screen is for. The back/nav
               button in a page header, and the submit in a form or bar.
     .btn-quiet neutral — Cancel, and every utility that sits beside a red one
               (Export, Reset, pagination, View live).

   Everything used to be .btn-s, the public site's red *outline* button: Back
   to Dashboard, Cancel, Export CSV and Previous/Next were all the same red
   hollow pill, so the header's primary action looked exactly like the thing
   that discards your edits. .btn-s itself is untouched — eighteen public
   templates use it, and it is still the right button out there.

   Scoped under .dsh so none of this reaches the marketing site. */
.dsh .btn-p {
  box-shadow: 0 2px 6px rgba(188, 0, 45, .22)
}

.dsh .btn-p:active,
.dsh .btn-quiet:active {
  transform: scale(.97)
}

.dsh .btn-quiet {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .5rem 1rem;
  font-family: inherit;
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.4;
  border-radius: 12px;
  border: 1px solid var(--dsh-line);
  background: #fff;
  color: #334155;
  cursor: pointer;
  text-decoration: none;
  transition: background .2s, border-color .2s, color .2s, transform .12s
}

.dsh .btn-quiet:hover {
  background: #F1F5F9;
  border-color: #CBD5E1;
  color: var(--dsh-ink)
}

.dsh .btn-quiet:focus-visible {
  outline: 2px solid var(--dsh-red);
  outline-offset: 2px
}

.dsh .btn-quiet[disabled],
.dsh .btn-quiet.is-off {
  opacity: .5;
  pointer-events: none
}

/* The back arrow, sized here so the seven call sites do not each repeat it. */
.dsh .btn-p svg,
.dsh .btn-quiet svg {
  width: 15px;
  height: 15px;
  flex: none
}

/* The .dsh-btn family lived here for the header's "View Live Website" and
   "Logout" buttons. Both moved into the account kebab menu, which styles its
   own rows, and no template references any of these class names now — so the
   rules are gone rather than left as three dead modifiers waiting to be
   copied onto something by mistake. */

/* ---- canvas ---- */
.dsh .dsh-canvas {
  flex: 1;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  min-width: 0
}

/* ---- KPI cards ---- */
.dsh .dsh-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 20px
}

.dsh .dsh-kpi {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .4rem;
  padding: 1.25rem;
  min-width: 0;
  background: #fff;
  border: 1px solid var(--dsh-line);
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, .03);
  transition: transform .22s, box-shadow .22s, border-color .22s
}

.dsh .dsh-kpi:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 30px rgba(5, 33, 81, .1);
  border-color: #CBD5E1
}

.dsh .dsh-kpi-ic {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: #F1F5F9;
  font-size: 1.05rem;
  margin-bottom: .15rem
}

.dsh .dsh-kpi-num {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.8rem;
  font-weight: 700;
  line-height: 1.05;
  color: var(--dsh-ink)
}

.dsh .dsh-kpi-lbl {
  font-size: .75rem;
  font-weight: 500;
  color: var(--dsh-mut);
  line-height: 1.35
}

/* ---- panels ---- */
.dsh .dsh-cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem
}

.dsh .dsh-panel {
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid var(--dsh-line);
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, .03);
  overflow: hidden
}

.dsh .dsh-panel-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--dsh-line)
}

.dsh .dsh-panel-head h2 {
  display: flex;
  align-items: center;
  gap: .55rem;
  font-size: .9375rem;
  font-weight: 700;
  color: var(--dsh-ink)
}

.dsh .dsh-panel-ic {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  font-size: .8125rem
}

.dsh .dsh-panel-ic--blue {
  background: #EFF6FF
}

.dsh .dsh-panel-ic--amber {
  background: #FFFBEB
}

.dsh .dsh-panel-ic--red {
  background: #FEF2F2
}

.dsh .dsh-viewall {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--dsh-red);
  white-space: nowrap
}

.dsh .dsh-viewall:hover {
  text-decoration: underline
}

.dsh .dsh-list {
  display: flex;
  flex-direction: column;
  list-style: none;
  margin: 0;
  padding: 0
}

.dsh .dsh-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .85rem 1.25rem;
  border-bottom: 1px solid #F1F5F9;
  transition: background .18s
}

.dsh .dsh-row:last-child {
  border-bottom: none
}

.dsh .dsh-row:hover {
  background: #F8FAFC
}

.dsh .dsh-row-main {
  min-width: 0;
  flex: 1
}

.dsh .dsh-row-main strong {
  display: block;
  font-size: .875rem;
  font-weight: 600;
  color: var(--dsh-ink);
  overflow-wrap: anywhere
}

.dsh .dsh-row-main small {
  display: block;
  font-size: .75rem;
  color: var(--dsh-mut);
  margin-top: .15rem;
  overflow-wrap: anywhere
}

.dsh .dsh-row-side {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-shrink: 0
}

.dsh .dsh-row-side form {
  margin: 0
}

.dsh .dsh-badge {
  display: inline-flex;
  align-items: center;
  padding: .22rem .6rem;
  border-radius: 999px;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .02em;
  white-space: nowrap
}

.dsh .dsh-badge--new {
  background: #EFF6FF;
  color: #1D4ED8;
  border: 1px solid #BFDBFE
}

.dsh .dsh-badge--pending {
  background: #FFFBEB;
  color: #B45309;
  border: 1px solid #FDE68A
}

.dsh .dsh-muted {
  color: var(--dsh-mut);
  font-size: .75rem;
  white-space: nowrap
}

.dsh .dsh-approve {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .4rem .85rem;
  border-radius: 999px;
  font-family: inherit;
  font-size: .75rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  background: #fff;
  color: #047857;
  border: 1.5px solid #6EE7B7;
  transition: all .2s
}

.dsh .dsh-approve:hover {
  background: #047857;
  border-color: #047857;
  color: #fff;
  box-shadow: 0 0 0 4px rgba(16, 185, 129, .16);
  transform: translateY(-1px)
}

/* ---- quick actions ---- */
.dsh .dsh-quick {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: .75rem;
  padding: 1.25rem
}

.dsh .dsh-quick-i {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .8rem .9rem;
  border-radius: 10px;
  background: #F8FAFC;
  border: 1px solid var(--dsh-line);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--dsh-ink);
  transition: transform .2s, background .2s, border-color .2s, box-shadow .2s
}

.dsh .dsh-quick-i:hover {
  transform: translateY(-2px);
  background: #fff;
  border-color: var(--dsh-red);
  box-shadow: 0 8px 20px rgba(5, 33, 81, .08)
}

.dsh .dsh-quick-ic {
  font-size: 1rem;
  flex-shrink: 0
}

.dsh .dsh-quick-t {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

/* ---- empty state ---- */
.dsh .dash-empty {
  text-align: center;
  padding: 2.5rem 1.25rem;
  color: var(--dsh-mut)
}

.dsh .dash-empty-icon {
  font-size: 2rem;
  display: block;
  margin-bottom: .5rem;
  opacity: .5
}

.dsh .dash-empty-icon svg {
  width: 2rem;
  height: 2rem;
}

.dsh .dash-empty strong {
  display: block;
  color: var(--dsh-ink);
  font-size: .9375rem;
  margin-bottom: .25rem
}

.dsh .dash-empty p {
  font-size: .8125rem;
  max-width: 22rem;
  margin: 0 auto
}

/* ---- inner pages (list / form / delete) reuse the panel shell ---- */
.dsh .dash-card {
  background: #fff;
  border: 1px solid var(--dsh-line);
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, .03);
  padding: 1.25rem
}

.dsh .dash-table-card {
  padding: .25rem
}

.dsh .dash-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap
}

.dsh .dash-h1 {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--dsh-ink)
}

.dsh .dash-sub {
  font-size: .8125rem;
  color: var(--dsh-mut);
  margin-top: .15rem
}

.dsh .dash-table th {
  color: var(--dsh-mut);
  border-bottom: 1px solid var(--dsh-line)
}

.dsh .dash-table td {
  border-bottom: 1px solid #F1F5F9
}

.dsh .dash-table tbody tr:hover {
  background: #F8FAFC
}

@media(min-width:1024px) {
  .dsh .dsh-cols {
    grid-template-columns: 1fr 1fr
  }

  .dsh .dsh-canvas {
    padding: 1.75rem
  }

  .dsh .dsh-header {
    padding: .9rem 1.75rem
  }
}

/* ---- narrow screens ----
   The sidebar no longer moves or hides here: it is fixed at --dsh-rail at
   every width, so what is left is trimming the header controls to fit the
   column beside it. */
@media(max-width:1023px) {
  .dsh .dsh-header-r {
    gap: .4rem
  }

  /* The account trigger is the one control with a label left to shed, so it
     drops back to a 36px square holding just the avatar — the same shape as
     the bell, which is all that fits beside the heading at this width. */
  .dsh .dsh-kebab>summary .dsh-kebab-name {
    display: none
  }

  .dsh .dsh-kebab>summary {
    width: 36px;
    justify-content: center;
    padding: 0
  }
}

@media(prefers-reduced-motion:reduce) {
  .dsh .dsh-kpi:hover,
  .dsh .dsh-quick-i:hover,
  .dsh .dsh-approve:hover {
    transform: none
  }
}

/* ===========================================================================
   FEATURED CAROUSEL  (homepage #featured)

   Multi-item slider built on a flex track. The per-view count is expressed
   once, here, as the flex-basis of .car-i:

     mobile  (<640px)   1 card
     tablet  (>=640px)  2 cards
     desktop (>=1024px) 3 cards

   with a 20px gutter throughout. main.js measures the rendered card width off
   the DOM rather than being told the counts, so these breakpoints are the only
   place the layout is defined and the two can never disagree.
   =========================================================================== */

.car-sec {
  overflow: hidden
}

.car-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 2rem
}

.car-nav {
  display: flex;
  gap: .5rem
}

.car-btn {
  width: 42px;
  height: 42px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.35rem;
  line-height: 1;
  color: var(--navy);
  cursor: pointer;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .08);
  border-radius: 50%;
  box-shadow: var(--sh);
  transition: all .3s ease-in-out
}

.car-btn:hover:not(:disabled) {
  color: #fff;
  background: var(--red);
  border-color: var(--red);
  transform: translateY(-2px)
}

.car-btn:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px
}

/* Disabled rather than hidden when the deck cannot move: the control keeps its
   place in the layout and in the tab order, so the row does not reflow every
   time the viewport crosses a breakpoint. */
.car-btn:disabled {
  opacity: .35;
  cursor: default
}

/* ---- track ---- */
.car-vp {
  overflow: hidden
}

.car-track {
  display: flex;
  gap: 20px;
  list-style: none;
  margin: 0;
  padding: 0;
  transition: transform .5s cubic-bezier(.4, 0, .2, 1);
  will-change: transform
}

/* 1 / 2 / 3 up. The gap is subtracted so N cards plus (N-1) gutters fill the
   viewport exactly rather than overflowing it. */
.car-i {
  flex: 0 0 100%;
  min-width: 0
}

@media(min-width:640px) {
  .car-i {
    flex-basis: calc((100% - 20px) / 2)
  }
}

@media(min-width:1024px) {
  .car-i {
    flex-basis: calc((100% - 40px) / 3)
  }
}

/* ---- card ---- */
.car-c {
  display: flex;
  flex-direction: column;
  height: 100%;
  border-radius: 16px;
  overflow: hidden;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .06);
  box-shadow: var(--sh);
  text-decoration: none;
  color: inherit;
  transition: all .3s ease-in-out
}

a.car-c:hover {
  transform: translateY(-4px);
  box-shadow: var(--sh-h)
}

a.car-c:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 3px
}

/* ---- media: fixed 16:9 box, image cropped to fill it ---- */
.car-media {
  position: relative;
  aspect-ratio: 16/9;
  overflow: hidden;
  background: var(--soft)
}

@supports not (aspect-ratio: 16/9) {
  .car-media {
    height: 280px
  }
}

.car-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .45s ease-in-out
}

a.car-c:hover .car-img {
  transform: scale(1.05)
}

/* Gradient rather than a flat tint: the title sits on the lower third, and a
   uniform overlay would grey out the whole photograph to protect two lines. */
.car-shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
      rgba(5, 20, 48, .88) 0%,
      rgba(5, 20, 48, .45) 38%,
      rgba(5, 20, 48, 0) 68%)
}

.car-overlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 1rem 1.1rem
}

.car-t {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.35;
  color: #fff;
  overflow-wrap: anywhere
}

.car-sub {
  margin-top: .3rem;
  font-size: .8125rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, .82);
  /* Two lines maximum: slides carry subtitles of wildly different lengths and
     a long one would push the headline off its own photograph. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden
}

.car-more {
  display: block;
  padding: .85rem 1.1rem;
  font-size: .8125rem;
  font-weight: 700;
  color: var(--red);
  transition: color .3s ease-in-out
}

a.car-c:hover .car-more {
  color: var(--navy)
}

/* ---- dots (built by main.js, one per page of cards) ---- */
.car-dots {
  display: flex;
  justify-content: center;
  gap: .4rem;
  margin-top: 1.5rem
}

.car-dots:empty {
  display: none
}

.car-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  cursor: pointer;
  background: rgba(5, 33, 81, .22);
  border: 0;
  border-radius: 999px;
  transition: all .3s ease-in-out
}

.car-dot.is-active {
  width: 22px;
  background: var(--red)
}

.car-dot:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px
}

@media(prefers-reduced-motion:reduce) {

  .car-track,
  .car-img,
  .car-c,
  .car-btn,
  .car-dot {
    transition: none
  }

  a.car-c:hover {
    transform: none
  }

  a.car-c:hover .car-img {
    transform: none
  }
}

/* ===========================================================================
   MOTION UPGRADE — scroll reveal, card depth, ambient float

   Appended last so it overrides the per-component rules above without those
   having to be hunted down and edited in five places.

   No animation library is loaded for this. The site already ships a working
   reveal engine (.anim + an IntersectionObserver in main.js) and a count-up;
   this retunes them to the requested curve and adds the stagger, rather than
   putting a second, competing engine on the page over a CDN.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. Scroll reveal
   ---------------------------------------------------------------------------
   duration 1000ms, distance 40px, easing cubic-bezier(.2,.8,.2,1).

   --anim-d is the stagger, set per element by main.js from its position among
   its siblings, so a grid streams in rather than snapping in as one block. It
   defaults to 0ms, which is what every standalone .anim block gets.
--------------------------------------------------------------------------- */
/* Longhands, not the `transition` shorthand: a var() sitting in the delay slot
   of the shorthand does not substitute in Chromium — the duration and easing
   apply and the delay silently computes to 0s, which quietly kills the whole
   stagger. As its own declaration it resolves correctly. */
.anim {
  opacity: 0;
  transition-property: opacity, transform;
  transition-duration: 1s;
  transition-timing-function: cubic-bezier(.2, .8, .2, 1);
  transition-delay: var(--anim-d, 0ms)
}

.anim.up {
  transform: translateY(40px)
}

.anim.left {
  transform: translateX(40px)
}

.anim.right {
  transform: translateX(-40px)
}

.anim.scale {
  transform: scale(.94)
}

/* ---------------------------------------------------------------------------
   2. Card lift + image zoom
   ---------------------------------------------------------------------------
   The brief named .card / .news-card / .member-card; none of those exist in
   this codebase. These are the real roots of the five card grids:

     .mem-c   Member Consultancies      .ldr-c   Leadership
     .evt-c   Events                    .blog-c  News / Insights
     .gal-i   Gallery albums            .car-c   Featured carousel

   .hero-slide is deliberately NOT in that list. It is the full-bleed banner,
   not a card, and a transform on it would create a stacking context that traps
   .hero-c — which is exactly what the note above .hero-slide > * warns about,
   since #sakura-c has to layer between the artwork and the headline.
--------------------------------------------------------------------------- */
/* Longhands again, and for a sharper reason than above. These cards are also
   .anim elements, so they carry the reveal transition. Writing the lift as a
   `transition:` shorthand here reset two things the reveal owns — it dropped
   `opacity` from the property list, so cards popped in instead of fading, and
   it reset transition-delay to 0s, which silently deleted the entire stagger.
   Listing all three properties keeps the reveal and the lift on one element
   without either erasing the other.

   The delay applies to the reveal only: main.js drops --anim-d once a card has
   revealed, so a card three along in the grid does not answer the pointer
   450ms late for the rest of the session. */
.mem-c,
.evt-c,
.ldr-c,
.blog-c,
.gal-i,
a.car-c {
  transition-property: opacity, transform, box-shadow;
  transition-duration: 1s, .4s, .4s;
  transition-timing-function:
    cubic-bezier(.2, .8, .2, 1),
    cubic-bezier(.165, .84, .44, 1),
    ease;
  transition-delay: var(--anim-d, 0ms), var(--anim-d, 0ms), 0s
}

.evt-c:hover,
.ldr-c:hover,
.blog-c:hover,
.gal-i:hover,
.car-i:hover a.car-c {
  transform: translateY(-10px) scale(1.02);
  box-shadow: 0 20px 40px rgba(0, 0, 0, .12)
}

/* .mem-c is deliberately not in the list above. It lifts 4px and does not
   scale, which is both what the redesigned card asks for and the fix for the
   flicker documented below — the member card was the one measurably affected
   by it. Keep the two hovers separate: folding .mem-c back in reintroduces the
   dead band at the bottom edge of a short card. */
.mem-c:hover {
  transform: translateY(-4px);
  box-shadow: 0 20px 25px -5px rgba(2, 6, 23, .1), 0 8px 10px -6px rgba(2, 6, 23, .1)
}

/* Carousel cards take their hover from .car-i, the grid cell, not from the
   card itself. A -10px lift carries the card's bottom edge up out from under a
   pointer resting near it, which drops the hover, drops the card, and re-fires
   the hover — a visible flicker. .car-i does not move, so the hover target
   stays put. The grid cards below have no such wrapper; see the note there. */
.car-i {
  /* The lifted card overflows its cell; without this the shadow is clipped. */
  overflow: visible
}

/* KNOWN TRADE-OFF, grid cards only (.evt-c, .ldr-c, .blog-c, .gal-i): these
   are direct children of their grid with no wrapper to hang the hover off, so
   the -10px lift moves the hover target itself. On a *short* card the
   scale(1.02) does not add back enough height to cover the travel, leaving a
   band at the very bottom edge where the pointer loses and regains the card —
   measured at roughly 8px on a 168px member card, and none on a 466px
   leadership card. The member card was the short one, and it now lifts 4px on
   its own rule above, which is under the 8px band and clears the problem for
   that grid. The remaining four are tall enough not to show it. */

/* The same hover, restated at a higher specificity for revealed cards.
   Every card in these grids also carries `anim scale` or `anim up`, so once it
   reveals it matches `.anim.scale.vis { transform: scale(1) }` — three classes,
   which outranks a one-class `:hover` and pins the card flat. The symptom is
   specific and easy to miss: the shadow deepens on hover but the card never
   moves. Four classes settles it in the hover's favour. */
.anim.vis.evt-c:hover,
.anim.vis.ldr-c:hover,
.anim.vis.blog-c:hover,
.anim.vis.gal-i:hover {
  transform: translateY(-10px) scale(1.02)
}

.anim.vis.mem-c:hover {
  transform: translateY(-4px)
}

/* Clip the zoom to the card. .ldr-c and .blog-c already carry overflow:hidden
   for their rounded corners; the rest are stated here so an image can never
   grow past the border radius. */
.mem-c,
.evt-c,
.gal-i,
.ldr-c,
.blog-c {
  overflow: hidden
}

/* The image scales inside the card while the card itself lifts — two separate
   transforms on two elements, which is why the zoom is not simply folded into
   the card's own scale. */
.mem-c img,
.evt-c img,
.ldr-c img,
.blog-c img,
.gal-i img {
  transition: transform .7s ease
}

.evt-c:hover img,
.ldr-c:hover img,
.blog-c:hover img,
.gal-i:hover img {
  transform: scale(1.1)
}

/* A gentler zoom on the member card: the others hold photographs, this one
   holds a logo sitting inside its own padding, where a 10% push reads as the
   wordmark drifting rather than the picture opening up. */
.mem-c img {
  transition: transform .5s ease
}

.mem-c:hover img {
  transform: scale(1.05)
}

/* ---------------------------------------------------------------------------
   3. Floating ambient background
   ---------------------------------------------------------------------------
   Two soft gradient blobs drifting behind the hero artwork, plus the stat
   icons breathing on offset delays. Pseudo-elements and existing nodes only —
   no extra markup, so nothing here can be left behind in the DOM if it is
   removed later.
--------------------------------------------------------------------------- */
@keyframes float {
  0% {
    transform: translateY(0px)
  }

  50% {
    transform: translateY(-12px)
  }

  100% {
    transform: translateY(0px)
  }
}

.hero::before,
.hero::after {
  content: "";
  position: absolute;
  z-index: 3;
  /* Between .hero-ol (2) and .hero-c (10): the blobs read as atmosphere in the
     artwork, never as a wash over the headline. */
  border-radius: 50%;
  pointer-events: none;
  filter: blur(60px);
  will-change: transform
}

.hero::before {
  width: 26rem;
  height: 26rem;
  top: 8%;
  left: -8rem;
  background: radial-gradient(circle, rgba(188, 0, 45, .30), transparent 70%);
  animation: float 9s ease-in-out infinite
}

.hero::after {
  width: 22rem;
  height: 22rem;
  right: -6rem;
  bottom: 12%;
  background: radial-gradient(circle, rgba(255, 183, 197, .26), transparent 70%);
  animation: float 11s ease-in-out infinite 1.5s
}

/* The stat badges breathe on staggered delays so the row moves as a wave
   rather than four icons bobbing in lockstep. */
.hero-stats .stat-i {
  animation: float 6s ease-in-out infinite;
  will-change: transform
}

.hero-stats> :nth-child(2) .stat-i {
  animation-delay: .5s
}

.hero-stats> :nth-child(3) .stat-i {
  animation-delay: 1s
}

.hero-stats> :nth-child(4) .stat-i {
  animation-delay: 1.5s
}

/* ---------------------------------------------------------------------------
   Reduced motion
   ---------------------------------------------------------------------------
   Everything above is decoration. Reveals resolve to their finished state
   immediately rather than being skipped, so content still appears — it just
   does not travel.
--------------------------------------------------------------------------- */
@media(prefers-reduced-motion:reduce) {

  .anim {
    transition: none
  }

  .anim.up,
  .anim.left,
  .anim.right,
  .anim.scale {
    transform: none
  }

  .hero::before,
  .hero::after,
  .hero-stats .stat-i {
    animation: none
  }

  .mem-c,
  .evt-c,
  .ldr-c,
  .blog-c,
  .gal-i,
  a.car-c,
  .mem-c img,
  .evt-c img,
  .ldr-c img,
  .blog-c img,
  .gal-i img {
    transition: none
  }

  .mem-c:hover,
  .evt-c:hover,
  .ldr-c:hover,
  .blog-c:hover,
  .gal-i:hover,
  a.car-c:hover,
  .mem-c:hover img,
  .evt-c:hover img,
  .ldr-c:hover img,
  .blog-c:hover img,
  .gal-i:hover img {
    transform: none
  }

  /* The album overlay still fades in on hover — an opacity change is not
     motion. Only the scale-up and the staggered slide are dropped, so the
     caption arrives in place rather than travelling there. */
  .gal-ol-alb,
  .gal-ol-alb>*,
  .gal-alb:hover .gal-ol-alb,
  .gal-alb:hover .gal-ol-alb>* {
    transform: none;
    transition: opacity .3s
  }
}

/* Dashboard list: opt-in serial-number column and the count beside the title.
   .dash-sn-col is narrow and the number is muted — it is a reference, not data
   to be read down the page. */
.dash-count {
  font-weight: 600;
  color: var(--slate)
}

.dash-sn-col {
  width: 3.5rem
}

.dash-sn {
  color: var(--slate);
  font-variant-numeric: tabular-nums;
  font-size: .8125rem
}

/* ---------------------------------------------------------------------------
   Top contact bar — slim strip above the sticky header.
--------------------------------------------------------------------------- */
.topbar {
  background: var(--navy-d);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  color: rgba(255, 255, 255, .72);
  font-size: .75rem
}

.topbar-in {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .4rem;
  padding-top: .5rem;
  padding-bottom: .5rem
}

.topbar-c,
.topbar-r {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem 1rem
}

.topbar-l {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  color: rgba(255, 255, 255, .78);
  font-weight: 500;
  transition: color .2s
}

.topbar-l:hover {
  color: var(--w)
}

.topbar-ic {
  color: var(--red-l, #ff5f7e)
}

.topbar-sep {
  color: rgba(255, 255, 255, .25)
}

.topbar-soc {
  display: flex;
  align-items: center;
  gap: .4rem
}

.topbar-s {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, .1);
  color: var(--w);
  font-size: .625rem;
  font-weight: 700;
  line-height: 1;
  transition: background .2s, transform .2s
}

.topbar-svg {
  width: .8125rem;
  height: .8125rem;
  display: block
}

.topbar-s:hover {
  color: var(--w);
  transform: translateY(-1px)
}

/* Brand colour on the plate itself, not only on hover. These used to be text
   glyphs — "f", "ig", "in" — where colour on hover was the only thing telling
   the networks apart. They are the real marks now, so each wears its own
   colour all the time and the hover just lifts and brightens it. */
.tb-fb {
  background: #1877F2
}

.tb-wa {
  background: #25D366
}

.tb-ig {
  background: radial-gradient(circle at 30% 107%, #fdf497 0%, #fdf497 5%, #fd5949 45%, #d6249f 60%, #285AEB 90%)
}

.tb-li {
  background: #0A66C2
}

.tb-tk {
  background: #000
}

.tb-yt {
  background: #FF0000
}

.tb-tw {
  background: #000
}

.topbar-s:hover {
  filter: brightness(1.12)
}

.topbar-legal {
  display: flex;
  align-items: center;
  gap: .45rem;
  font-size: .6875rem;
  font-weight: 600
}

.topbar-legal a {
  color: rgba(255, 255, 255, .78);
  transition: color .2s
}

.topbar-legal a:hover {
  color: var(--w)
}

@media(min-width:640px) {
  .topbar-in {
    flex-direction: row;
    justify-content: space-between
  }
}

/* ---------------------------------------------------------------------------
   General Members directory — filter bar, card grid, avatar cards.
   Moved out of the template's inline <style> so the .board-empty rules it
   shares with the Leadership page have one definition instead of two.
--------------------------------------------------------------------------- */
.gm-bar {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.15rem;
  margin-bottom: 1.75rem;
  border-radius: 24px;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .06);
  box-shadow: 0 4px 18px rgba(5, 33, 81, .05)
}

.gm-bar-search {
  position: relative;
  flex: 1 1 auto;
  min-width: 0
}

.gm-bar-ic {
  position: absolute;
  top: 50%;
  left: 1rem;
  transform: translateY(-50%);
  font-size: .875rem;
  pointer-events: none
}

.gm-bar-search .gm-in {
  padding-left: 2.6rem
}

.gm-bar-act {
  display: flex;
  gap: .65rem;
  flex-wrap: wrap
}

.gm-in {
  width: 100%;
  padding: .8rem 1rem;
  border: 1px solid rgba(0, 0, 0, .12);
  border-radius: 16px;
  background: #f8fafc;
  color: var(--char, var(--navy));
  font-family: inherit;
  font-size: .875rem;
  transition: border-color .2s, box-shadow .2s, background .2s
}

.gm-in::placeholder {
  color: #94a3b8
}

.gm-in:focus {
  outline: none;
  background: var(--w);
  border-color: var(--navy);
  box-shadow: 0 0 0 3px rgba(5, 33, 81, .14)
}

.gm-sel {
  width: auto;
  font-weight: 600;
  cursor: pointer
}

.gm-btn {
  flex: none;
  padding: .8rem 1.6rem;
  border: 0;
  border-radius: 16px;
  cursor: pointer;
  background: var(--red);
  color: var(--w);
  font-family: inherit;
  font-size: .8125rem;
  font-weight: 800;
  box-shadow: 0 6px 16px rgba(188, 0, 45, .25);
  transition: background .25s, transform .25s
}

.gm-btn:hover {
  background: #9c0025;
  transform: translateY(-1px)
}

.gm-count {
  margin: 0 0 1.25rem;
  padding-left: .25rem;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: #64748b
}

.gm-g {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem
}

/* display:contents so the wrapper does not become a grid item of its own and
   break the .gm-g column tracks. */
.gm-hit {
  display: contents
}

.gm-hit[hidden] {
  display: none
}

.gm-c {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 100%;
  padding: 1.75rem 1.25rem 1.35rem;
  text-align: center;
  background: var(--w);
  border: 1px solid rgba(0, 0, 0, .07);
  border-radius: 24px;
  box-shadow: 0 4px 16px rgba(5, 33, 81, .06);
  transition: box-shadow .3s, transform .3s
}

.gm-c:hover {
  transform: translateY(-4px);
  box-shadow: 0 20px 42px rgba(5, 33, 81, .14)
}

/* Static, not absolutely positioned: a long designation ("Regional
   Representative — Province 1") would otherwise run under the avatar or off
   the card. In flow it wraps and pushes the avatar down instead. */
.gm-c-badge {
  display: inline-block;
  max-width: 100%;
  margin-bottom: .9rem;
  padding: .25rem .7rem;
  border-radius: 999px;
  background: rgba(188, 0, 45, .08);
  border: 1px solid rgba(188, 0, 45, .18);
  color: var(--red);
  font-size: .625rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  overflow-wrap: anywhere
}

.gm-c-av {
  width: 7rem;
  height: 7rem;
  flex: none;
  margin-bottom: 1rem;
  border-radius: 999px;
  overflow: hidden;
  background: var(--soft);
  border: 4px solid #eef2f7;
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, .08)
}

.gm-c-av img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s ease
}

.gm-c:hover .gm-c-av img {
  transform: scale(1.06)
}

.gm-c-n {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 800;
  line-height: 1.3;
  color: var(--navy);
  overflow-wrap: anywhere;
  transition: color .25s
}

.gm-c:hover .gm-c-n {
  color: var(--red)
}

.gm-c-t {
  margin: .3rem 0 0;
  font-size: .75rem;
  font-weight: 600;
  color: var(--slate)
}

/* margin-top:auto pins the icon row to the card bottom, so cards with and
   without contact details still line their avatars and names up. */
.gm-c-links {
  display: flex;
  gap: .4rem;
  margin-top: auto;
  padding-top: 1rem
}

.gm-c-l {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 999px;
  border: 1px solid rgba(0, 0, 0, .1);
  background: var(--w);
  color: var(--slate);
  font-size: .75rem;
  font-weight: 700;
  line-height: 1;
  transition: background .25s, color .25s, border-color .25s
}

.gm-c-l:hover {
  background: var(--red);
  border-color: var(--red);
  color: var(--w)
}

.gm-c-l:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px
}

.gm-nohit {
  text-align: center;
  padding: 2.5rem 1rem;
  color: #64748b;
  font-size: .9375rem
}

.gm-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 2.5rem
}

/* Shared with the Leadership page's empty state. */
.board-empty {
  text-align: center;
  padding: 3rem 1rem;
  margin: 1.5rem 0;
  border: 1px dashed #e2e8f0;
  border-radius: 12px;
  background: #f8fafc
}

.board-empty-t {
  font-size: 1rem;
  font-weight: 600;
  color: #0f172a;
  margin: 0
}

.board-empty-p {
  font-size: .875rem;
  color: #64748b;
  margin: .25rem 0 0
}

.board-empty-act {
  margin-top: 1rem
}

.board-empty-btn {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .5rem 1rem;
  font-size: .875rem;
  font-weight: 500;
  color: #fff;
  background: #2563eb;
  border-radius: 8px;
  text-decoration: none;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .08);
  transition: background .18s
}

.board-empty-btn:hover {
  background: #1d4ed8;
  color: #fff
}

@media(min-width:640px) {
  .gm-bar {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    padding: 1.35rem
  }

  .gm-bar-search {
    max-width: 24rem
  }

  .gm-g {
    grid-template-columns: repeat(2, 1fr)
  }
}

@media(min-width:1024px) {
  .gm-g {
    grid-template-columns: repeat(3, 1fr)
  }
}

@media(min-width:1280px) {
  .gm-g {
    grid-template-columns: repeat(4, 1fr)
  }
}

@media(prefers-reduced-motion:reduce) {

  .gm-c,
  .gm-c-av img,
  .gm-btn {
    transition: none
  }

  .gm-c:hover,
  .gm-c:hover .gm-c-av img,
  .gm-btn:hover {
    transform: none
  }
}

/* ---------------------------------------------------------------------------
   Auth screens — sign-in and the four password-reset steps.
   Shared by every template extending core/auth/base_auth.html. The header and
   footer are already suppressed on these routes (AUTH_URL_NAMES in
   core/context_processors.py), so the wrapper owns the whole viewport.
--------------------------------------------------------------------------- */
.auth-screen {
  min-height: 100vh;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  padding: 1rem;
  background: var(--navy)
}

.auth-card {
  width: 100%;
  max-width: 26rem;
  padding: 2rem;
  border-radius: 24px;
  text-align: center;
  background: var(--w);
  border: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 25px 60px rgba(0, 0, 0, .35)
}

.auth-logo {
  display: inline-block;
  margin-bottom: 1rem
}

.auth-logo img {
  height: 56px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  display: block
}

.auth-t {
  margin: 0;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--navy);
  line-height: 1.2
}

.auth-sub {
  margin: .35rem 0 1.5rem;
  font-size: .75rem;
  font-weight: 500;
  color: var(--slate);
  line-height: 1.6
}

/* Flash messages and form errors, relocated into the card. */
.auth-msgs {
  margin-bottom: 1.15rem;
  text-align: left
}

.auth-msg {
  margin: 0 0 .5rem;
  padding: .7rem .85rem;
  border-radius: 12px;
  font-size: .8125rem;
  font-weight: 600;
  background: rgba(22, 163, 74, .1);
  color: #16a34a
}

.auth-msg-err {
  background: rgba(188, 0, 45, .1);
  color: var(--red)
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  text-align: left
}

.auth-field {
  display: flex;
  flex-direction: column
}

.auth-lb {
  margin-bottom: .35rem;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #475569
}

.auth-in {
  width: 100%;
  padding: .8rem 1rem;
  border: 1px solid rgba(0, 0, 0, .12);
  border-radius: 12px;
  background: #f8fafc;
  color: var(--char, var(--navy));
  font-size: .875rem;
  font-family: inherit;
  transition: border-color .2s, box-shadow .2s, background .2s
}

.auth-in::placeholder {
  color: #94a3b8
}

.auth-in:focus {
  outline: none;
  background: var(--w);
  border-color: var(--navy);
  box-shadow: 0 0 0 3px rgba(5, 33, 81, .16)
}

/* Django renders field errors as a <ul class="errorlist"> above the input. */
.auth-field .errorlist {
  list-style: none;
  margin: 0 0 .35rem;
  padding: 0;
  font-size: .75rem;
  font-weight: 600;
  color: var(--red)
}

.auth-help {
  margin: .4rem 0 0;
  font-size: .6875rem;
  line-height: 1.5;
  color: var(--slate)
}

.auth-help ul {
  margin: .25rem 0 0;
  padding-left: 1rem
}

.auth-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .5rem;
  font-size: .75rem
}

.auth-check {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  color: #475569;
  cursor: pointer
}

.auth-check input {
  accent-color: var(--navy);
  cursor: pointer
}

.auth-link {
  color: var(--red);
  font-weight: 600
}

.auth-link:hover {
  text-decoration: underline
}

.auth-btn {
  width: 100%;
  margin-top: .25rem;
  padding: .9rem 1rem;
  border: 0;
  border-radius: 12px;
  cursor: pointer;
  display: block;
  text-align: center;
  background: var(--navy);
  color: var(--w);
  font-family: inherit;
  font-size: .9375rem;
  font-weight: 700;
  box-shadow: 0 8px 20px rgba(5, 33, 81, .28);
  transition: background .25s, transform .25s, box-shadow .25s
}

.auth-btn:hover {
  background: var(--navy-l);
  color: var(--w);
  transform: translateY(-2px);
  box-shadow: 0 12px 28px rgba(5, 33, 81, .36)
}

.auth-btn:focus-visible {
  outline: 2px solid var(--w);
  outline-offset: 3px
}

/* "You are already signed in as …" strip on the member login, in the amber the
   rest of the site uses for a state that is neither success nor error. */
.auth-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .85rem 1rem;
  margin-bottom: 1.25rem;
  text-align: left;
  border-radius: 12px;
  background: rgba(212, 160, 23, .1);
  border: 1px solid rgba(212, 160, 23, .35)
}

.auth-note strong {
  display: block;
  font-size: .8125rem;
  color: var(--navy)
}

.auth-note span {
  font-size: .75rem;
  color: var(--slate);
  overflow-wrap: anywhere
}

.auth-note-btn {
  flex: none;
  padding: .45rem .85rem;
  border-radius: 10px;
  border: 1px solid rgba(0, 0, 0, .12);
  background: var(--w);
  color: var(--navy);
  font-family: inherit;
  font-size: .75rem;
  font-weight: 700;
  cursor: pointer;
  transition: background .2s, border-color .2s
}

.auth-note-btn:hover {
  background: var(--soft);
  border-color: var(--navy)
}

.auth-foot {
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: .5rem;
  font-size: .75rem;
  color: rgba(255, 255, 255, .55)
}

.auth-foot a {
  color: rgba(255, 255, 255, .85);
  font-weight: 600
}

.auth-foot a:hover {
  color: var(--w);
  text-decoration: underline
}

@media(min-width:640px) {
  .auth-screen {
    padding: 1.5rem
  }

  .auth-card {
    padding: 2.5rem
  }
}

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

  .auth-btn:hover {
    transform: none
  }
}

/* Nepal-to-Japan Roadway: a live directory verification shortcut plus the
   four stages students move through. Namespaced to keep it isolated. */
.roadway{position:relative;overflow:hidden;padding:7.25rem 0;background:#03173a;color:#fff}.roadway-inner{position:relative;z-index:2}.roadway-grid{position:absolute;inset:0;opacity:.34;background-image:linear-gradient(rgba(255,255,255,.055) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.055) 1px,transparent 1px);background-size:52px 52px;mask-image:linear-gradient(to bottom,transparent,black 20%,black 82%,transparent)}.roadway-glow{position:absolute;border-radius:50%;filter:blur(85px);pointer-events:none}.roadway-glow--red{top:10%;right:-11rem;width:29rem;height:29rem;background:rgba(230,57,70,.26)}.roadway-glow--blue{bottom:-13rem;left:-9rem;width:29rem;height:29rem;background:rgba(23,92,206,.28)}
/* Label + heading, nothing else. The standfirst and the search box below it
   were removed; the 4rem the search carried under itself is folded into the
   head's own margin so the cards keep their distance instead of riding up. */
.roadway-head{max-width:52rem;margin:0 auto 4rem;padding-top:.75rem;text-align:center}.roadway-badge{display:inline-block;border:1px solid rgba(230,57,70,.4);border-radius:999px;background:rgba(230,57,70,.11);padding:.42rem .82rem;color:#ff9ea6;font-size:.65rem;font-weight:800;letter-spacing:.15em;text-transform:uppercase}.roadway-head h2{margin:1.4rem 0 0;font-family:'Plus Jakarta Sans',Inter,sans-serif;font-size:clamp(2.15rem,4.6vw,3.85rem);line-height:1.08;letter-spacing:-.045em;color:#fff}.roadway-head h2 span{background:linear-gradient(100deg,#ed4452,#ffb3b9);-webkit-background-clip:text;background-clip:text;color:transparent}
/* Flex wrap, not a grid, and four to a row rather than auto-fit.
   ─────────────────────────────────────────────────────────────
   Two things a grid could not do once the cards became dashboard rows:

   * hold the count. auto-fit fits as many tracks as the width allows, so a
     fifth step made five narrower cards on a wide screen — the row stopped
     looking like the design. flex-basis:25% pins it at four, and the fifth
     wraps to a second row of four.
   * centre a part-filled last row. Grid tracks are laid out from the start
     edge, so a lone fifth card sits hard left under the first; a wrapped flex
     line honours justify-content, so it centres under the four above it.

   align-items defaults to stretch, which is what makes every card in a row the
   same height without asking. */
.roadway-track{position:relative;display:flex;flex-wrap:wrap;justify-content:center;gap:1rem}
/* Basis, not width: 25% of the container minus the three gaps a four-up row
   carries. flex-grow stays 0 so a short last row keeps the card size of a full
   one instead of stretching two cards across the whole width. */
.roadway-step{flex:0 1 calc(25% - .75rem)}.roadway-trail{position:absolute;z-index:0;top:2rem;left:11%;right:11%;height:1px;background:linear-gradient(90deg,transparent,rgba(230,57,70,.82),rgba(255,255,255,.43),rgba(230,57,70,.82),transparent)}.roadway-step{position:relative;z-index:1;display:flex;min-height:17.5rem;flex-direction:column;padding:1.5rem;border:1px solid rgba(255,255,255,.13);border-radius:1.2rem;background:linear-gradient(145deg,rgba(255,255,255,.11),rgba(255,255,255,.035));color:inherit;text-decoration:none;box-shadow:inset 0 1px 0 rgba(255,255,255,.07);backdrop-filter:blur(14px)}.roadway-number{display:grid;width:2.55rem;height:2.55rem;place-items:center;border:1px solid rgba(255,117,127,.42);border-radius:.72rem;background:rgba(230,57,70,.17);color:#ff9ea6;font-size:.75rem;font-weight:900;letter-spacing:.04em}.roadway-emoji{position:absolute;top:1.65rem;right:1.4rem;font-size:1.4rem;filter:drop-shadow(0 6px 12px rgba(0,0,0,.2))}.roadway-step h3{margin:1.35rem 0 .55rem;font-family:'Plus Jakarta Sans',Inter,sans-serif;font-size:1.03rem;line-height:1.3}.roadway-step p{margin:0;color:#b8c5d9;font-size:.82rem;line-height:1.68}
/* Rich-text description. The card holds whatever Summernote produced, so the
   styling has to cover the elements a writer can actually make rather than one
   <p> the template controlled. Children are flush by default and spaced only
   between siblings, so a single paragraph sits exactly where the old one did. */
.roadway-desc{color:#b8c5d9;font-size:.82rem;line-height:1.68}
.roadway-desc>*{margin:0}
.roadway-desc>*+*{margin-top:.5rem}
.roadway-desc strong,.roadway-desc b{color:#e8eefb;font-weight:700}
.roadway-desc a{color:#ff9ea6;text-decoration:underline}
.roadway-desc ul,.roadway-desc ol{padding-left:1.15rem}
.roadway-desc li+li{margin-top:.2rem}
/* Editors paste images. Contain it rather than let it set the card's width. */
.roadway-desc img{max-width:100%;height:auto;border-radius:.5rem}
.roadway-more{margin-top:auto;padding-top:1.25rem;color:#ff9ea6;font-size:.72rem;font-weight:800}.roadway-more b{display:inline-block;margin-left:.25rem;transition:transform .25s}.roadway-step:hover .roadway-more b{transform:translateX(.35rem)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}/* Two up on tablets, one up on phones — the col-sm-6 / col-12 steps. */
@media(max-width:900px){.roadway-track{gap:1.2rem}.roadway-step{flex-basis:calc(50% - .6rem)}.roadway-trail{display:none}}@media(max-width:560px){.roadway{padding:5.25rem 0}.roadway-head{margin-bottom:2.75rem;padding-top:0}.roadway-step{flex-basis:100%;min-height:14.5rem}}@media(prefers-reduced-motion:reduce){.roadway-step,.roadway-number,.roadway-more b{transition:none}.roadway-step:hover{transform:none}}
/* -------------------------------------------------
   Dashboard Action Buttons – permanent visibility override
   -------------------------------------------------
   This ensures that all action icons/buttons in member request
   tables (Pending, Approved, Rejected) are always shown, regardless
   of any earlier Tailwind or JS hover‑based rules.
*/
.dash-actions a,
.dash-actions button,
.dash-actions .dash-btn,
.mrq-acts a,
.mrq-acts button,
.mrq-acts .dash-btn {
    opacity: 1 !important;
    visibility: visible !important;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
}

/* Dashboard Sidebar Enhancements */
/* Full-height flex layout for the sidebar container */
.dsh-sidebar {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 0.5rem;
  min-height: 100vh;
  padding: 1.5rem 1rem;
}

/* ---- sidebar footer identity ----
   Real rules for what was written as Tailwind utilities — tw-w-10, tw-h-10,
   tw-rounded-full, tw-overflow-hidden and the rest. No stylesheet in this
   project defines a tw- prefixed class and no Tailwind build is loaded on this
   page, so every one of them was inert: the avatar had no width, no height and
   no overflow clip.

   What that looked like: the <img> inside carried width:100%/height:100%, and
   with no sized parent to resolve against, 100% became the width of the sidebar
   column. A 2000px upload rendered as a ~210px block that shoved the username
   and role out of the footer. The global `img { max-width: 100% }` at the top
   of this file is the only reason it stopped there rather than running off the
   edge entirely. */
.dsh-side-user {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-width: 0;
  padding: .5rem .35rem;
  border-radius: 12px;
  text-decoration: none;
  transition: background .2s
}

.dsh-side-user:hover {
  background: rgba(255, 255, 255, .08)
}

.dsh-side-user:focus-visible {
  outline: 2px solid rgba(255, 255, 255, .6);
  outline-offset: 2px
}

/* flex:none, not just width/height: in a flex row a sized box can still be
   shrunk by a long username beside it, and an avatar squeezed out of round
   stops reading as an avatar. */
.dsh-side-av {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  overflow: hidden;
  background: #dc2626;
  color: #fff;
  font-size: .8125rem;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase
}

/* object-fit:cover fills the circle from the middle of the image whatever its
   aspect ratio, so a wide photo is cropped rather than letterboxed or squashed.
   The 100%/100% pair only means anything now that the parent has a size. */
.dsh-side-av img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block
}

/* min-width:0 is what allows the ellipsis below: without it a flex item
   refuses to shrink past its content and the name widens the footer. */
.dsh-side-id {
  display: flex;
  flex-direction: column;
  min-width: 0
}

.dsh-side-id strong {
  font-size: .8125rem;
  font-weight: 600;
  color: #f1f5f9;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}

.dsh-side-id small {
  font-size: .75rem;
  color: #94a3b8;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap
}
/* Navigation container fill */
.dsh-nav {
  flex: 1;
  display: flex;
  flex-direction: column;
}
/* Sidebar link styling – overrides */
.dsh-nav a.dsh-nav-i,
.dsh-nav a.dsh-nav-i--pin {
  display: flex;
  align-items: center;
  padding: 0.7rem 1rem;
  border-radius: 0.75rem;
  margin-bottom: 0.25rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: #94a3b8;
  transition: all 0.2s ease-in-out;
}
.dsh-nav a.dsh-nav-i:hover,
.dsh-nav a.dsh-nav-i--pin:hover {
  background: rgba(255,255,255,0.1);
  color: #fff;
}
/* Section headings */
.dsh-nav .section-heading {
  margin-top: 1.25rem;
  margin-bottom: 0.5rem;
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  color: #94a3b8;
  text-transform: uppercase;
  font-weight: 600;
}
/* Global Settings link sticky at bottom */
.dsh-sidebar .global-settings-link {
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding-top: 1rem;
}

/* ===========================================================================
   Justified body prose
   ===========================================================================
   Paragraph edges flush on both sides across the public site.

   Two things make justification work rather than merely look tidy in a mockup:

   hyphens: auto — the important one. Justification stretches word spaces to
   reach the right margin, so a narrow column with long words opens rivers of
   white down the page. Hyphenation lets the browser break words instead, and
   the gaps stay even. It needs a language to hyphenate against, which
   base.html supplies as <html lang="en">; without that attribute the property
   is silently inert.

   overflow-wrap: break-word — a URL or a long unbroken token cannot be
   hyphenated, and in a justified line it pushes past the container instead of
   wrapping.

   Scope. This is prose styling, so it is aimed at page and section body copy
   and then handed straight back anywhere the design does its own aligning:
   the two panels (which are interface, not reading matter), the header and
   footer, and everything the site deliberately centres through .tc. Those
   resets sit after the rule and match at equal or higher specificity, so they
   win — see the note on each.
   ---------------------------------------------------------------------- */
.sec p,
.abp p,
main p,
article p,
.container > p {
  text-align: justify;
  /* Stretch the spaces between words, never the letters inside them. */
  text-justify: inter-word;
  -webkit-hyphens: auto;
  hyphens: auto;
  overflow-wrap: break-word;
  /* "Relaxed" leading. Justified lines need more air than ragged-right ones:
     the eye tracks back along a full-width measure, and tight leading makes it
     land on the wrong line. */
  line-height: 1.75;
}

/* ---- Handed back ------------------------------------------------------
   The control panel and the member portal share base.html's <body>, so the
   selectors above reach into both — .dsh through `main p` (its canvas is a
   <main>), .mportal through the same. Justified interface copy reads as a
   defect, and hyphenating a status message is worse. `inherit` rather than
   `left` so each panel keeps whatever its own rules already set.

   Specificity: .dsh p and .mportal p are (0,1,1), which ties with .sec p and
   beats `main p`; coming last, the tie goes to these. */
.dsh p,
.mportal p {
  text-align: inherit;
  -webkit-hyphens: manual;
  hyphens: manual;
  line-height: inherit;
}

/* Centred by design. .tc is the site's text-align:center utility at (0,1,0),
   which `.sec p` at (0,1,1) would otherwise override — quietly un-centring
   every section subtitle on the site. Two cases, because they need different
   answers: a <p> that *is* .tc has to be re-centred outright, while a <p>
   inside a .tc container only has to stop overriding what it inherits. */
p.tc {
  text-align: center;
}

.tc p,
#header p,
#footer p,
.hero p,
.sec-label,
figcaption,
/* Confirmation dialogs. Both sit outside .dsh / .mportal — they are pinned to
   the viewport, so they are rendered after those wrappers close — which put
   them back in reach of the rule above. Their cards centre their own text, and
   a justified, hyphenated "You are about to permanently delete…" is the last
   thing a confirmation should look like. */
.del-modal-card p,
.mn-modal-card p {
  text-align: inherit;
  -webkit-hyphens: manual;
  hyphens: manual;
}

/* Single-line copy inside a pill, badge or button is never prose, and a
   hyphenated button label is a bug. These carry their own alignment. */
.btn-p,
.btn-s,
.btn-quiet,
.badge,
.pill {
  -webkit-hyphens: manual;
  hyphens: manual;
}