/* ==========================================================================
   NCIA Knowledge Library — prototype stylesheet
   Single stylesheet, no build step. Tokens first, then layout, then parts.
   ========================================================================== */

:root {
  /* brand — ramp built around #d3131d */
  --navy-900: #4a0509;
  --navy-800: #7a0b12;
  --navy-700: #a80f18;
  --navy-600: #d3131d;
  --navy-100: #fae3e4;
  --navy-050: #fdf4f4;

  /* accents — brand-hue tints, split by lightness not by hue. These drive chrome
     (progress bars, checkboxes, card icons), which stays maroon on purpose so the
     brand keeps dominating everything that isn't carrying meaning. */
  --teal-600: #8e1b22;
  --teal-100: #f7dfe0;
  --amber-600: #c4442c;
  --amber-100: #fbe6df;

  /* the one true green — reserved for "done/complete" state, off-brand on purpose */
  --green-600: #1a8f4c;
  --green-700: #15723d;   /* darker step — AA-safe under 11.5px badge text */
  --green-100: #e2f5e9;

  /* --------------------------------------------------------------------------
     Tag palette — the one place where hue is allowed to carry meaning.
     Badges label categories and states (pipeline stage, KPI trend, progress), so
     they have to be tellable apart at a glance. They used to be twelve tints of
     the same maroon: twelve names, one readable colour, so the coding did nothing.
     Muted / low-chroma on purpose — these sit beside the brand, they don't fight
     it. Constraints held: every pair is >=4.5:1 (WCAG AA for 11.5px bold), and
     any two that can land in the same list are >=25deg apart in hue.
     Slate and stone stay near-grey (<25% sat) so they read as neutrals.
     -------------------------------------------------------------------------- */
  --tag-slate-bg:  #ece7e7;  --tag-slate-fg:  #635456;
  --tag-stone-bg:  #ece5dc;  --tag-stone-fg:  #6f5c46;
  --tag-red-bg:    #fbdcdc;  --tag-red-fg:    #b0261d;
  --tag-amber-bg:  #fae8c8;  --tag-amber-fg:  #8a5a10;
  --tag-lime-bg:   #e9f0cd;  --tag-lime-fg:   #566b14;
  --tag-green-bg:  #e2f5e9;  --tag-green-fg:  #15723d;
  --tag-teal-bg:   #d6ede6;  --tag-teal-fg:   #0f6f63;
  --tag-cyan-bg:   #d7e9f0;  --tag-cyan-fg:   #0f6a7d;
  --tag-blue-bg:   #dde8f7;  --tag-blue-fg:   #2b4fa8;
  --tag-indigo-bg: #e3e0f7;  --tag-indigo-fg: #5040ad;
  --tag-purple-bg: #eddef5;  --tag-purple-fg: #7b3a9e;
  --tag-pink-bg:   #fadfe9;  --tag-pink-fg:   #a8306b;

  /* neutrals — warm greys pulled toward the brand red */
  --ink: #2b1618;
  /* long-form body colour: --ink is too hard at 17px over a page of prose,
     --ink-2 too soft. Sits between them and still clears AA on --bg. */
  --ink-read: #45292d;
  --ink-2: #5f4144;
  --ink-3: #8b6b6e;
  --line: #ecdcdd;
  --line-2: #f6eeef;
  --bg: #faf6f6;
  --surface: #ffffff;
  /* dashboard-style page canvas (Notion/Linear/Jira pattern: a soft grey
     behind white cards so they read as distinct surfaces) — warmed a touch
     off Atlassian's N20 (#F4F5F7) so it sits with this palette's warm reds
     instead of its cooler blue-grey. */
  --surface-canvas: #f4f0ef;

  /* type */
  --font: "Inter", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --serif: "Iowan Old Style", Georgia, "Times New Roman", serif;

  /* shape */
  --r-sm: 6px;
  --r: 10px;
  --r-lg: 16px;
  --shadow-1: 0 1px 2px rgba(74, 5, 9, .06), 0 1px 3px rgba(74, 5, 9, .05);
  --shadow-2: 0 2px 6px rgba(74, 5, 9, .07), 0 10px 24px rgba(74, 5, 9, .07);

  --wrap: 1220px;

  /* ------------------------------------------------------------------------
     Compact UI scale — the internal system's type and spacing ramp.

     Everything inside the section modal (and the three takeover scenes) sizes
     against these. The old sizes were a marketing-page ramp: on a 1366x768
     laptop at 100% zoom the About header plus six cards filled the whole
     viewport with 73px to spare, so every internal page read as though the
     browser were zoomed to ~115%. This ramp is tuned so that same viewport
     shows the header, both card rows, and a real slice of the next section.

     Type is fixed px on purpose — the hierarchy should read identically on a
     1366 laptop and a 1920 monitor, which is how dashboards (Linear, Jira,
     Notion) behave. Only the page gutter and the section rhythm open up on
     wide screens, via the clamp()s at the bottom.

     THE MAP DOES NOT USE THIS SCALE. assets/css/style.css lines ~330-1240 are
     the map and its HUD; they keep their own absolute sizes so the homepage
     composition is untouched. See the font-size pins under .mapchrome.
     ------------------------------------------------------------------------ */

  /* type — each step is a deliberate rung, not a multiplier of the last */
  --ui-text-2xs:  10px;    /* eyebrow, micro-label, uppercase tracking */
  --ui-text-xs:   11px;    /* badge, pill, counter */
  --ui-text-sm:   12px;    /* meta line, helper text, .small */
  --ui-text-base: 12.5px;  /* dense copy: card description, table cell */
  --ui-text-md:   13.5px;  /* default body text */
  --ui-text-lg:   15px;    /* lede, emphasised row title */
  --ui-text-xl:   17px;    /* h3 on a wide card, modal title */
  --ui-text-2xl:  18.5px;  /* h2, section heading */
  --ui-text-3xl:  24px;    /* h1, page title */
  --ui-text-4xl:  30px;    /* hero title on a takeover scene */

  /* spacing — one ramp, used for padding, margin and gap alike */
  --ui-space-2xs: 4px;
  --ui-space-xs:  6px;
  --ui-space-sm:  8px;
  --ui-space-md:  12px;
  --ui-space-lg:  16px;
  --ui-space-xl:  22px;
  --ui-space-2xl: 30px;

  /* components */
  --ui-control-h:    32px;  /* button, input, select — still a comfortable target */
  --ui-control-h-sm: 27px;
  --ui-card-pad:     14px;
  --ui-card-pad-lg:  18px;  /* panels and feature cards that carry more inside */
  --ui-grid-gap:     13px;
  --ui-icon:         16px;
  --ui-icon-lg:      19px;

  /* page rhythm — the only tokens that grow on a wide monitor */
  --ui-page-pad-top:    14px;
  --ui-page-pad-bottom: 36px;
  --ui-page-gutter:  clamp(18px, 2.4vw, 40px);
  --ui-section-gap:  clamp(22px, 2.2vw, 32px);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--ui-text-md);
  line-height: 1.55;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--navy-600); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3, h4 { margin: 0; font-family: var(--serif); line-height: 1.25; font-weight: 650; letter-spacing: -.01em; color: var(--navy-900); }
h1 { font-size: var(--ui-text-3xl); }
h2 { font-size: var(--ui-text-2xl); }
h3 { font-size: 14.5px; }
p { margin: 0 0 var(--ui-space-sm); }
p:last-child { margin-bottom: 0; }
ul { margin: 0; padding-left: 15px; }

.icon { width: var(--ui-icon); height: var(--ui-icon); flex: none; }
.icon-lg { width: var(--ui-icon-lg); height: var(--ui-icon-lg); flex: none; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 var(--ui-space-xl); }
.wrap--wide {
  max-width: none;
  padding-inline: var(--ui-page-gutter);
}
.muted { color: var(--ink-3); }
.small { font-size: var(--ui-text-sm); }
.mono { font-variant-numeric: tabular-nums; }
.center { text-align: center; }
.stack > * + * { margin-top: var(--ui-space-sm); }

/* ==========================================================================
   Global controls
   --------------------------------------------------------------------------
   The top bar, its brand lockup and its search field are gone: the map is the
   only view, so the map's HUD (.mapchrome) is the only chrome there is. What
   is left here are the icon buttons and drop-downs that HUD carries.

   There is no section navigation either: the sections are the map's buildings.
   ========================================================================== */

.iconbtn {
  position: relative;
  display: inline-flex; align-items: center; gap: 7px;
  height: 34px; padding: 0 9px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent; color: #f0d3d5;
  font: inherit; font-size: 13px;
  cursor: pointer; text-decoration: none;
  transition: background .15s, color .15s;
}
.iconbtn:hover { background: rgba(255, 255, 255, .12); color: #fff; text-decoration: none; }
.iconbtn:focus-visible { outline: 2px solid #ffb0b5; outline-offset: 1px; }
/* The account control: initials in a solid badge, same recipe as .org-avatar,
   sized to sit inside the 40px HUD circle rather than stretching it — a full
   name in that fixed circle is what used to overflow into three lines. */
.iconbtn__avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--navy-600);
  color: #fff;
  font-size: 11px; font-weight: 800; letter-spacing: .01em;
}

.menu { position: relative; }
.menu__panel {
  position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 214px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-2);
  z-index: 50;
}
.menu__head {
  padding: 7px 10px 8px;
  font-size: 11px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3);
}
.menu__note {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: var(--r-sm);
  color: var(--ink); font-size: 13.5px; text-decoration: none;
}
.menu__note:hover { background: var(--navy-050); text-decoration: none; }
/* A <button> sharing this class (e.g. Reset my account) needs the browser's
   default button chrome stripped so it reads as the same kind of row as the
   <a> links either side of it. */
button.menu__note {
  width: 100%; border: 0; background: none; font: inherit; text-align: left; cursor: pointer;
}
button.menu__note:disabled { opacity: .6; cursor: default; }

/* ==========================================================================
   Page scaffolding
   ========================================================================== */

.page { padding-block: var(--ui-space-xl) var(--ui-page-pad-bottom); }

.crumbs { display: flex; align-items: center; gap: var(--ui-space-xs); font-size: var(--ui-text-base); color: var(--ink-3); margin-bottom: var(--ui-space-sm); flex-wrap: wrap; }
/* The compact scale took the trail down to 12.5px, which left a bare text link
   about 19px tall. The padding buys the crumbs back a ~23px hit area without
   spending any more vertical room than the row already had. */
.crumbs a { color: var(--ink-3); padding-block: 2px; }
.crumbs span.sep { opacity: .5; }

.pagehead { margin-bottom: var(--ui-space-lg); }
.pagehead__row { display: flex; align-items: flex-start; gap: var(--ui-space-md); flex-wrap: wrap; }
.pagehead h1 { margin-bottom: var(--ui-space-2xs); }
.pagehead .lede { color: var(--ink-2); font-size: 14px; max-width: 660px; }
.pagehead__actions { margin-left: auto; display: flex; gap: var(--ui-space-sm); flex-wrap: wrap; }

.section { margin-top: var(--ui-section-gap); }
.section__head { display: flex; align-items: baseline; gap: var(--ui-space-md); margin-bottom: var(--ui-space-md); }
.section__head h2 { flex: none; }
.section__head .rule { flex: 1; height: 1px; background: var(--line); }
.section__head a { font-size: var(--ui-text-sm); white-space: nowrap; }

.eyebrow {
  font-size: var(--ui-text-2xs); font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3);
}

/* ==========================================================================
   Buttons, badges, chips
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; gap: var(--ui-space-xs);
  height: var(--ui-control-h); padding: 0 var(--ui-space-md);
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: inherit; font-size: var(--ui-text-md); font-weight: 550;
  cursor: pointer; text-decoration: none;
  transition: background .15s, border-color .15s;
}
.btn:hover { background: var(--navy-050); border-color: #edb9bc; text-decoration: none; }
.btn:focus-visible, .sidenav a:focus-visible, .checkrow:focus-visible {
  outline: 2px solid var(--navy-600); outline-offset: 2px;
}
.btn--primary { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }
.btn--primary:hover { background: var(--navy-800); border-color: var(--navy-800); }
.btn--sm { height: var(--ui-control-h-sm); padding: 0 var(--ui-space-sm); font-size: var(--ui-text-sm); }
.btn:disabled,
.btn[aria-disabled="true"] {
  background: var(--navy-100);
  border-color: var(--line);
  color: var(--ink-3);
  cursor: not-allowed;
  opacity: .72;
  box-shadow: none;
}
.btn:disabled:hover,
.btn[aria-disabled="true"]:hover {
  background: var(--navy-100);
  border-color: var(--line);
}

.badge {
  display: inline-flex; align-items: center;
  padding: 2px 7px; border-radius: 999px;
  font-size: var(--ui-text-xs); font-weight: 650; letter-spacing: .01em;
  background: var(--navy-100); color: var(--navy-700);
  white-space: nowrap;
}
/* Category & state badges. The colour is the signal here — "Beta" next to
   "Ongoing", "Down" next to "Up" — so each tone is a genuinely separate hue
   rather than another shade of the brand. See the tag palette in :root. */
.badge--slate  { background: var(--tag-slate-bg);  color: var(--tag-slate-fg); }
.badge--stone  { background: var(--tag-stone-bg);  color: var(--tag-stone-fg); }
.badge--red    { background: var(--tag-red-bg);    color: var(--tag-red-fg); }
.badge--amber  { background: var(--tag-amber-bg);  color: var(--tag-amber-fg); }
.badge--lime   { background: var(--tag-lime-bg);   color: var(--tag-lime-fg); }
.badge--green  { background: var(--tag-green-bg);  color: var(--tag-green-fg); }
.badge--teal   { background: var(--tag-teal-bg);   color: var(--tag-teal-fg); }
.badge--cyan   { background: var(--tag-cyan-bg);   color: var(--tag-cyan-fg); }
.badge--blue   { background: var(--tag-blue-bg);   color: var(--tag-blue-fg); }
.badge--indigo { background: var(--tag-indigo-bg); color: var(--tag-indigo-fg); }
.badge--purple { background: var(--tag-purple-bg); color: var(--tag-purple-fg); }
.badge--pink   { background: var(--tag-pink-bg);   color: var(--tag-pink-fg); }

.chip {
  display: inline-flex; align-items: center; gap: var(--ui-space-xs);
  padding: 4px 9px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  font-size: var(--ui-text-sm); color: var(--ink-2); text-decoration: none;
}
.chip:hover { border-color: var(--navy-600); color: var(--navy-700); text-decoration: none; }
.chip.is-on { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }
.chiprow { display: flex; gap: var(--ui-space-xs); flex-wrap: wrap; }

/* ==========================================================================
   Cards & grids
   ========================================================================== */

.grid { display: grid; gap: var(--ui-grid-gap); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: var(--ui-card-pad);
  box-shadow: var(--shadow-1);
}
a.card { display: block; color: inherit; }
a.card:hover { text-decoration: none; border-color: #eaacb0; box-shadow: var(--shadow-2); transform: translateY(-1px); }
a.card { transition: box-shadow .15s, transform .15s, border-color .15s; }

.card__icon {
  width: 30px; height: 30px; border-radius: 8px;
  display: grid; place-items: center; margin-bottom: var(--ui-space-sm);
  background: var(--navy-100); color: var(--navy-700);
}
.card h3 { margin-bottom: var(--ui-space-2xs); }
.card__meta { font-size: var(--ui-text-sm); color: var(--ink-3); margin-top: var(--ui-space-sm); display: flex; gap: var(--ui-space-md); flex-wrap: wrap; align-items: center; }
/* Two shapes in the wild: an icon followed by loose text, and a run of spans
   each opening with its own icon. Both need the glyph off the words. */
.card__meta > .icon { margin-right: 6px; }
.card__meta > span { display: inline-flex; align-items: center; gap: 6px; }
.card p { font-size: var(--ui-text-base); color: var(--ink-2); }

/* Edit Mode turns an About card into a <div> (its text is contenteditable,
   which a live link would steal carets from) — the card's own "Open page"
   link wears the corner so an administrator can still step into the
   section's page. Read mode never sees it: scoped to .is-edit-mode. */
.is-edit-mode .about-cards .card { position: relative; }
.is-edit-mode .about-cards .about-card__open {
  position: absolute;
  top: 10px;
  right: 10px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  padding: 5px 7px;
  color: var(--navy-700);
  background: var(--navy-100);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  text-decoration: none;
}
.is-edit-mode .about-cards .about-card__open:hover {
  background: var(--navy-700);
  border-color: var(--navy-700);
  color: #fff;
}
.is-edit-mode .about-cards .about-card__open .icon { width: 12px; height: 12px; }

/* ==========================================================================
   Home — the interactive map
   --------------------------------------------------------------------------
   The scene is one background image with destination buildings and reserved
   sites placed on top of it.
   Everything is driven by percentages of the map frame, so the whole thing
   scales as one picture and a building never drifts off its plot.

   Per-building values arrive from app/Data/map.php as custom properties:
     --x  horizontal centre     --w  width        --ar  image width / height
     --y  top edge              --beat  pulse offset, so the buildings are not in step

   NOTHING BELOW USES THE --ui-* COMPACT SCALE. The homepage composition is
   deliberately exempt from the density pass that tightened every internal
   page: the map is a picture you navigate, not a document you read, and its
   buildings, labels and HUD are all tuned to the artwork. The pin on the two
   roots just below is what keeps the smaller body font-size from leaking in
   by inheritance — it restores the 15px the map was always laid out against.
   ========================================================================== */

.mapchrome,
.map-intro,
.takeover-transition,
.interactive-map { font-size: 15px; line-height: 1.6; }
/* .small and .icon are global utilities the HUD also uses, so they carry the
   compact scale in from outside. Restated here at the sizes the map chrome
   was drawn against — 13px labels and 18px glyphs. */
.mapchrome .small { font-size: 13px; }
.mapchrome .icon { width: 18px; height: 18px; }
.mapchrome .icon-lg { width: 22px; height: 22px; }

/* The map owns the viewport, and the page is a window into it: the artwork is
   sized from the viewport, app.js pans it with translate3d, and buildings are
   positioned as percentages of the frame, so panning never moves them relative
   to the artwork.

   How big the artwork is drawn depends on the map style in play
   (app/Data/map_style.php), which hands the numbers down as custom properties
   on the element and picks one of the two modifiers below. Both take their
   scale from the viewport rather than a fixed pixel size: a fixed scale only
   ever framed correctly on the one screen it was measured on. */

body.is-map { overflow: hidden; }
body.is-map.is-intro-locked { cursor: wait; }
.is-intro-locked .mapchrome,
.is-intro-locked .mapstage {
  pointer-events: none;
  user-select: none;
}
.is-intro-locked .map-building__glow {
  opacity: 0;
  animation: none;
}

/* --- first-visit reveal --------------------------------------------------
   The city remains completely still beneath this fixed layer. The logo rests
   directly on a hand-built CSS cloud bank; once it fades, only the clouds move
   as the map is uncovered. */

.map-intro {
  position: fixed;
  inset: 0;
  z-index: 200;
  overflow: hidden;
  background: transparent;
  pointer-events: auto;
  isolation: isolate;
  transition: opacity .25s ease, visibility .25s ease;
}
.map-intro.is-finished {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.map-intro__logo-layer {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  padding: 28px;
  opacity: 1;
  visibility: visible;
  transition: opacity .5s ease, visibility .5s ease;
}
.map-intro.is-logo-away .map-intro__logo-layer {
  opacity: 0;
  visibility: hidden;
}

.map-intro__logo {
  display: block;
  width: clamp(250px, 42vw, 430px);
  height: auto;
  filter: drop-shadow(0 12px 24px rgba(58, 79, 88, .18));
  animation: map-intro-logo-pulse 1.7s ease-in-out infinite;
}
@keyframes map-intro-logo-pulse {
  0%, 100% { transform: scale(1); opacity: .88; }
  50% { transform: scale(1.035); opacity: 1; }
}

.map-intro__cloudscape {
  position: absolute;
  inset: -8%;
  z-index: 1;
  overflow: hidden;
  background:
    radial-gradient(ellipse at 48% 40%, rgba(255, 255, 255, .99) 0 24%, transparent 58%),
    linear-gradient(180deg, #e9f2f6 0%, #f7fafb 52%, #d9e7ed 100%);
  opacity: 1;
  transition: opacity 1.65s cubic-bezier(.4, 0, .2, 1);
}
.map-intro__cloud {
  position: absolute;
  width: var(--cloud-w);
  height: 18vw;
  left: var(--cloud-left);
  top: var(--cloud-top);
  border-radius: 50%;
  background: radial-gradient(
    ellipse at 50% 38%,
    rgba(255, 255, 255, .98) 0 58%,
    rgba(239, 246, 249, .95) 76%,
    rgba(202, 220, 228, .72) 100%
  );
  box-shadow:
    -8vw 2vw 6vw rgba(255, 255, 255, .9),
    8vw 1vw 7vw rgba(231, 240, 244, .92),
    0 6vw 7vw rgba(154, 183, 195, .34);
  filter: blur(5px);
  transform: translate3d(0, 0, 0) scale(1.08);
  transition:
    transform var(--cloud-time, 1.65s) cubic-bezier(.4, 0, .2, 1),
    opacity var(--cloud-time, 1.65s) ease;
  will-change: transform, opacity;
}
.map-intro__cloud::before,
.map-intro__cloud::after {
  content: '';
  position: absolute;
  bottom: 0;
  border-radius: 50%;
  background: inherit;
}
.map-intro__cloud::before {
  left: 12%;
  width: 43%;
  aspect-ratio: 1;
}
.map-intro__cloud::after {
  right: 9%;
  width: 54%;
  aspect-ratio: 1;
}

.map-intro__cloud--1 { --cloud-w: 62vw; --cloud-left: -16vw; --cloud-top: -8vh;  --cloud-x: -48vw; --cloud-y: -10vh; --cloud-time: 1.7s; }
.map-intro__cloud--2 { --cloud-w: 58vw; --cloud-left: 58vw;  --cloud-top: -7vh;  --cloud-x: 46vw;  --cloud-y: -9vh;  --cloud-time: 1.8s; }
.map-intro__cloud--3 { --cloud-w: 54vw; --cloud-left: -14vw; --cloud-top: 27vh;  --cloud-x: -52vw; --cloud-y: -2vh;  --cloud-time: 1.55s; }
.map-intro__cloud--4 { --cloud-w: 61vw; --cloud-left: 55vw;  --cloud-top: 24vh;  --cloud-x: 50vw;  --cloud-y: -3vh;  --cloud-time: 1.7s; }
.map-intro__cloud--5 { --cloud-w: 57vw; --cloud-left: -12vw; --cloud-top: 58vh;  --cloud-x: -48vw; --cloud-y: 8vh;   --cloud-time: 1.75s; }
.map-intro__cloud--6 { --cloud-w: 59vw; --cloud-left: 57vw;  --cloud-top: 56vh;  --cloud-x: 48vw;  --cloud-y: 9vh;   --cloud-time: 1.6s; }
.map-intro__cloud--7 { --cloud-w: 45vw; --cloud-left: 15vw;  --cloud-top: -15vh; --cloud-x: -8vw;  --cloud-y: -35vh; --cloud-time: 1.5s; }
.map-intro__cloud--8 { --cloud-w: 48vw; --cloud-left: 27vw;  --cloud-top: 72vh;  --cloud-x: 7vw;   --cloud-y: 36vh;  --cloud-time: 1.7s; }

.map-intro.is-clouds-away .map-intro__cloudscape { opacity: 0; }
.map-intro.is-clouds-away .map-intro__cloud {
  opacity: 0;
  transform: translate3d(var(--cloud-x), var(--cloud-y), 0) scale(1.18);
}

/* --- About takeover bridge ---------------------------------------------
   The map's intro uncovers a page; this bridge runs the same cloud bank in
   both directions across a real document navigation. It begins off-screen,
   closes over the About modal, remains closed while History/Awards/Offices
   loads, then parts to reveal that full-bleed scene. */
.takeover-transition {
  position: fixed;
  inset: 0;
  z-index: 500;
  overflow: hidden;
  visibility: hidden;
  pointer-events: none;
  isolation: isolate;
}
.takeover-transition.is-active,
.is-takeover-arrival .takeover-transition {
  visibility: visible;
  pointer-events: auto;
}
.takeover-transition .map-intro__cloudscape {
  opacity: 0;
  transition-duration: 1.7s;
}
.takeover-transition .map-intro__cloud {
  opacity: 0;
  transform: translate3d(var(--cloud-x), var(--cloud-y), 0) scale(1.18);
}
.takeover-transition .map-intro__logo-layer {
  opacity: 0;
  visibility: hidden;
  transform: scale(.965);
  transition: opacity .85s ease .32s, transform 1.05s cubic-bezier(.16, 1, .3, 1) .22s,
              visibility 0s linear 1.17s;
}
.takeover-transition.is-covered .map-intro__cloudscape,
.is-takeover-arrival .takeover-transition .map-intro__cloudscape {
  opacity: 1;
}
.takeover-transition.is-covered .map-intro__cloud,
.is-takeover-arrival .takeover-transition .map-intro__cloud {
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1.08);
}
.takeover-transition.is-covered .map-intro__logo-layer,
.is-takeover-arrival .takeover-transition .map-intro__logo-layer {
  opacity: 1;
  visibility: visible;
  transform: scale(1);
  transition: opacity .85s ease .32s, transform 1.05s cubic-bezier(.16, 1, .3, 1) .22s,
              visibility 0s linear 0s;
}

/* Arrival wins over the covered frame above and sends every cloud back out
   along its own left/right vector. The logo leaves slightly ahead of the
   cloud bank so the full-bleed page is the final clean frame. */
.is-takeover-arrival .takeover-transition.is-leaving .map-intro__logo-layer {
  opacity: 0;
  visibility: hidden;
  transform: scale(1.025);
  transition: opacity .55s ease, transform .7s ease, visibility 0s linear .55s;
}
/* History is a shared-element handoff: its opening scene provides the final
   rectangle, so the loader logo itself stays visible while moving there. */
.is-takeover-arrival .takeover-transition.is-logo-handoff.is-leaving .map-intro__logo-layer {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: none;
}
.takeover-transition__logo-mover {
  width: fit-content;
}
.takeover-transition.is-logo-handoff .takeover-transition__logo-mover {
  will-change: transform;
}
.takeover-transition.is-reverse-logo-handoff .map-intro__logo-layer {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: none;
}
.takeover-transition.is-reverse-logo-handoff .takeover-transition__logo-mover {
  will-change: transform;
}
.takeover-transition.is-reverse-logo-handoff .map-intro__logo {
  animation: none;
  opacity: .88;
  transform: scale(1);
}
.takeover-transition.is-logo-handoff .map-intro__logo {
  /* Freeze the pulse on its current frame. The stable outer layer performs
     the move, so two animations never compete for the logo's transform. */
  animation-play-state: paused;
}
.takeover-transition.is-navigation-settling .map-intro__logo {
  animation-play-state: paused;
}
.is-takeover-arrival .takeover-transition.is-leaving .map-intro__cloudscape {
  opacity: 0;
}
.is-takeover-arrival .takeover-transition.is-leaving .map-intro__cloud {
  opacity: 0;
  transform: translate3d(var(--cloud-x), var(--cloud-y), 0) scale(1.18);
}
body.is-takeover-transitioning { overflow: hidden; cursor: wait; }

.mapstage {
  position: relative;
  width: 100vw;
  height: 100dvh;
  overflow: hidden;
  /* Open water, for the axis where the artwork is narrower than the screen.
     Sampled from the artwork's own edges (#0170b9 mid-edge, #046db4 corner)
     and continued outward, so the seam at the artwork's border disappears. */
  background: radial-gradient(ellipse at 50% 47%, #0578c0 0%, #046db4 55%, #045c95 100%);
  touch-action: none;
  user-select: none;
}

.interactive-map {
  position: absolute;
  left: 0;
  top: 0;
  /* app.js writes translate3d(...) scale(...) here. The origin must be the
     top-left corner, not the default centre, so that a frame position is
     simply offset + fraction * size * scale -- which is what lets zoom stay
     anchored under the cursor. */
  transform-origin: 0 0;
  cursor: grab;
  will-change: transform;
}
.interactive-map.is-panning { cursor: grabbing; }

/* Fit: hold a window of the frame -- --map-fw/--map-fh of its width and height
   -- on screen at rest, so a scene that has margin around it is never cropped
   into. The second term is the height constraint expressed as a width, so
   min() can compare the two; whichever axis is tighter wins and the other
   overflows and pans. The artwork keeps its own shape. */
.interactive-map--fit {
  --map-w: min(calc(100vw * var(--map-fw)), calc(100dvh * var(--map-ar) * var(--map-fh)));
  width: var(--map-w);
  height: calc(var(--map-w) * var(--map-ar-inv));
}

/* Stretch: the map IS the viewport. For artwork that runs to all four sides,
   holding its aspect ratio would mean either cropping the difference (leaving
   a strip to drag into at rest) or letterboxing; giving the ratio up instead
   means it fills the screen exactly, with nothing cropped and nothing to pan
   until you zoom. Everything on the map -- artwork and buildings alike -- is a
   percentage of this one box, so they skew together and a building stays on
   its plot whatever shape the window is. */
.interactive-map--stretch {
  width: 100vw;
  height: 100dvh;
}

/* Hold-and-drag must pan the map. Without this the browser's native
   drag-and-drop wins: the pointer picks the building artwork (or its link) up
   as a drag image and the map itself never moves. app.js also cancels
   dragstart, for engines that ignore this property. */
.mapstage img,
.mapstage a { -webkit-user-drag: none; }

/* The background: one image, or the grid of tiles it was cut into. A single
   image needs no tracks -- the lone child fills the implicit cell -- so only
   the tiled styles declare them.

   Grid, not absolutely positioned fractions: adjacent tracks share one edge,
   so there is no pair of independently rounded boxes to leave a hairline of
   stage between them at fractional zoom. No gap, and the tiles fill their
   cells exactly -- object-fit: fill because the cell is the tile's own aspect
   ratio, and `contain` would letterbox inside it. */
.interactive-map__scene {
  position: absolute;
  inset: 0;
  display: grid;
  gap: 0;
}
.interactive-map__scene--tiled {
  grid-template-columns: repeat(var(--tile-cols), 1fr);
  grid-template-rows: repeat(var(--tile-rows), 1fr);
}
.interactive-map__scene picture { display: block; min-width: 0; min-height: 0; }
.interactive-map__tile {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: fill;
}

/* --- floating chrome over the scene ------------------------------------- */

.mapchrome {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 30;
  display: flex; align-items: flex-start; gap: 16px;
  padding: 16px 20px;
  pointer-events: none;                      /* the map stays clickable */
}
.mapchrome > * { pointer-events: auto; }
.mapchrome__tools {
  margin-left: auto;
  display: flex; align-items: center; gap: 8px;
  border-radius: 999px;
}
/* The modal's reverse morph lands on this exact horizontal capsule. Once the
   capsule has arrived, let the four controls separate from it one at a time
   instead of making them pop back in as a single group. */
.mapchrome__tools > * {
  transform-origin: center;
  transition: opacity .18s ease, transform .24s cubic-bezier(.2, .8, .2, 1);
}
body.is-modal-closing .mapchrome__tools > * {
  opacity: 0;
  transform: scale(.62);
  pointer-events: none;
}
body:not(.is-modal-closing) .mapchrome__tools > *:nth-child(1) { transition-delay: 0s; }
body:not(.is-modal-closing) .mapchrome__tools > *:nth-child(2) { transition-delay: .035s; }
body:not(.is-modal-closing) .mapchrome__tools > *:nth-child(3) { transition-delay: .07s; }
body:not(.is-modal-closing) .mapchrome__tools > *:nth-child(4) { transition-delay: .105s; }

.mapchrome__brand {
  position: fixed;
  left: 20px;
  bottom: 18px;
  display: block;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  opacity: .94;
  text-decoration: none;
  transition: opacity .2s ease, transform .2s ease;
}
.mapchrome__brand:hover {
  background: transparent;
  opacity: 1;
  text-decoration: none;
  transform: translateY(-1px);
}
.mapchrome__brand:focus-visible {
  outline: 2px solid var(--navy-700);
  outline-offset: 4px;
}
.mapchrome__brand-logo {
  display: block;
  width: clamp(150px, 15vw, 220px);
  height: auto;
  max-width: 42vw;
  object-fit: contain;
  filter:
    drop-shadow(0 1px 1px rgba(255, 255, 255, .8))
    drop-shadow(0 5px 10px rgba(21, 32, 46, .24));
}

/* the HUD pills reuse .iconbtn and .menu, each its own solid white pill */
.mapchrome .iconbtn {
  height: 40px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(74, 5, 9, .1), 0 10px 26px -12px rgba(74, 5, 9, .45);
  color: var(--ink-2);
}
.mapchrome .iconbtn { width: 40px; justify-content: center; padding: 0; }
.mapchrome .iconbtn:hover { background: var(--navy-050); color: var(--navy-700); }
.mapchrome .iconbtn:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }

/* --- map guide drawer ----------------------------------------------------
   A quarter-width reading panel rather than the map's full-screen module
   modal. It uses the same page background, surface headers, rules and type as
   the building pages, but enters from the right so it remains a map aid. */
.maphelp {
  position: fixed;
  inset: 0;
  z-index: 90;
}
.maphelp[hidden] { display: none; }

.maphelp__backdrop {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  padding: 0; border: 0;
  background: rgba(43, 22, 24, .28);
  opacity: 0;
  cursor: default;
  transition: opacity .24s ease;
}
.maphelp.is-open .maphelp__backdrop { opacity: 1; }

.maphelp__panel {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: 50vw;
  display: flex; flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--line);
  box-shadow: -18px 0 48px rgba(43, 22, 24, .2);
  transform: translate3d(100%, 0, 0);
  transition: transform .26s cubic-bezier(.22, .61, .36, 1);
}
.maphelp.is-open .maphelp__panel { transform: translate3d(0, 0, 0); }
.maphelp__panel:focus { outline: none; }

.maphelp__head {
  display: flex; align-items: center; gap: 16px;
  flex: none;
  padding: 17px 18px 17px 22px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.maphelp__head > div { min-width: 0; }
.maphelp__head .modal__close { margin-left: auto; flex: none; }
.maphelp__eyebrow {
  margin: 0;
  color: var(--ink-3);
  font-size: 10.5px; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase;
}
.maphelp__head h2 { margin-top: 2px; font-size: 20px; }

.maphelp__body {
  flex: 1; min-height: 0;
  padding: 24px 22px 32px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
.maphelp__intro {
  padding-bottom: 24px;
  border-bottom: 1px solid var(--line);
}
.maphelp__intro h3 { font-family: var(--serif); font-size: 24px; font-weight: 600; }
.maphelp__lede { margin-top: 10px; color: var(--ink-read); font-size: 15px; line-height: 1.7; }

.maphelp__tip {
  display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 11px;
  margin-top: 18px; padding: 14px;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface);
}
.maphelp__tip-icon {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 9px;
  background: var(--navy-100); color: var(--navy-700);
}
.maphelp__tip p { color: var(--ink-2); font-size: 13px; line-height: 1.55; }
.maphelp__tip strong { display: block; color: var(--navy-900); font-weight: 650; }

.maphelp__buildings { margin-top: 26px; }
.maphelp__section-head { display: flex; align-items: end; gap: 12px; }
.maphelp__section-head > div { min-width: 0; }
.maphelp__section-head h3 { margin-top: 2px; font-size: 16px; }
.maphelp__section-head .badge { margin-left: auto; flex: none; }

.maphelp__list { list-style: none; margin: 14px 0 0; padding: 0; }
.maphelp__item {
  display: grid; grid-template-columns: 38px minmax(0, 1fr); gap: 12px;
  padding: 14px 0;
  border-top: 1px solid var(--line);
}
.maphelp__building-icon {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: 9px;
  background: var(--navy-100); color: var(--navy-700);
}
.maphelp__item h4 { font-size: 14px; line-height: 1.35; }
.maphelp__item p { margin-top: 4px; color: var(--ink-2); font-size: 12.5px; line-height: 1.55; }
.maphelp__item .maphelp__purpose {
  color: var(--navy-800);
  font-weight: 650;
}
.maphelp__item .maphelp__contents { margin-top: 3px; }

body.is-help-open { overflow: hidden; }

@media (max-width: 760px) {
  .maphelp__panel { width: min(92vw, 420px); }
  .maphelp__head { padding: 14px 14px 14px 18px; }
  .maphelp__body { padding: 21px 18px 28px; }
}
@media (max-width: 480px) { .maphelp__panel { width: 100%; } }

@media (prefers-reduced-motion: reduce) {
  .maphelp__backdrop, .maphelp__panel { transition: none; }
}

/* --- a building ---------------------------------------------------------- */

.map-building {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  height: var(--h);
  transform: translateX(-50%) rotate(var(--rot, 0deg));
  transform-origin: 50% 100%;                /* grows out of its own base */
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .4s cubic-bezier(.16, 1, .3, 1);
}
.map-building > picture,
.map-building img {
  display: block;
  width: 100%;
  height: 100%;
}
.map-building img {
  /* The background is stretched independently on X and Y. The building image
     must use the exact same stretch; contain would preserve its own aspect
     ratio, add internal letterboxing, and make it drift off the empty lot. */
  object-fit: fill;
  filter: drop-shadow(0 6px 10px rgba(74, 5, 9, .18));
  transition: filter .38s cubic-bezier(.16, 1, .3, 1);
}

.map-building:hover,
.map-building:focus-visible {
  transform: translateX(-50%) translateY(-1.4%) rotate(var(--rot, 0deg)) scale(1.035);
  z-index: 3;
}

/* Run the same hover treatment as a real pointer hover before Welcome opens.
   Only the stacking order differs, so the cue stays visible over the map. */
.map-building.is-intro-highlight {
  z-index: 20;
  transform: translateX(-50%) translateY(-1.4%) rotate(var(--rot, 0deg)) scale(1.035);
}
.map-building:hover img,
.map-building:focus-visible img,
.map-building.is-intro-highlight img {
  filter:
    drop-shadow(0 14px 20px rgba(74, 5, 9, .26))
    drop-shadow(0 0 14px rgba(211, 19, 29, .55))
    brightness(1.06) saturate(1.04);
}
@keyframes welcome-hover-image-pulse {
  from {
    filter:
      drop-shadow(0 14px 20px rgba(74, 5, 9, .26))
      drop-shadow(0 0 14px rgba(211, 19, 29, .55))
      brightness(1.06) saturate(1.04);
  }
  to {
    filter:
      drop-shadow(0 10px 16px rgba(74, 5, 9, .2))
      drop-shadow(0 0 8px rgba(211, 19, 29, .35))
      brightness(1.03) saturate(1.02);
  }
}
.map-building.is-intro-highlight img {
  animation: welcome-hover-image-pulse .5s .28s ease-in-out 2 alternate forwards;
}
.map-building:active { transform: translateX(-50%) translateY(-.4%) rotate(var(--rot, 0deg)) scale(1.01); }
.map-building:focus { outline: none; }

/* CSS-only lot notices are part of the scene, not destinations. Map dragging
   passes through them on the homepage; the calibration tool has its own copy
   of this artwork inside a draggable wrapper. */
.map-building--inactive {
  cursor: default;
  pointer-events: none;
}
.map-building--locked picture img { filter: grayscale(1) brightness(.7); }
.map-building--locked .map-building__glow { display: none; }
.map-lot-notice {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  gap: 2%;
  color: #fff;
  text-align: center;
  text-transform: uppercase;
}
.map-lot-notice__stamp,
.map-lot-notice__note {
  position: relative;
  z-index: 1;
}
.map-lot-notice__stamp {
  padding: .2em .7em .24em;
  border: .16em solid currentColor;
  background: #b30d18;
  box-shadow: 0 .16em .3em rgba(74, 5, 9, .28);
  font-size: clamp(9px, 1.35vw, 23px);
  font-weight: 900;
  line-height: 1;
  letter-spacing: .12em;
  transform: rotate(-4deg);
}
.map-lot-notice__note {
  color: #253246;
  font-size: clamp(6px, .58vw, 10px);
  font-weight: 800;
  letter-spacing: .14em;
  text-shadow: 0 1px 2px rgba(255, 255, 255, .95), 0 0 5px rgba(255, 255, 255, .8);
}

/* the ground glow: an ellipse on the plaza, not a box around the artwork */
.map-building__glow {
  position: absolute;
  left: 50%; bottom: 2%;
  width: 74%; aspect-ratio: 2.6;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(211, 19, 29, .5), rgba(211, 19, 29, 0) 72%);
  opacity: 0;
  pointer-events: none;
  animation: building-beat 4.4s var(--beat, 0s) ease-in-out infinite;
}
.map-building:hover .map-building__glow,
.map-building:focus-visible .map-building__glow,
.map-building.is-intro-highlight .map-building__glow { opacity: .85; animation: none; }

@keyframes welcome-hover-glow-pulse {
  from { opacity: .85; transform: translateX(-50%) scale(1); }
  to   { opacity: .48; transform: translateX(-50%) scale(.9); }
}
.map-building.is-intro-highlight .map-building__glow {
  animation: welcome-hover-glow-pulse .5s .28s ease-in-out 2 alternate forwards;
}

@keyframes building-beat {
  0%, 62%, 100% { opacity: 0;   transform: translateX(-50%) scale(.86); }
  18%           { opacity: .34; transform: translateX(-50%) scale(1); }
  40%           { opacity: .12; transform: translateX(-50%) scale(.95); }
}

/* --- one morphing building tooltip ---------------------------------------
   The compact white name pill and the dark information card are the same
   element. Its top edge remains fixed while the second grid row opens, so the
   title stays anchored and the card grows down toward the building.

   Two rules keep that morph smooth, and both matter more than the easing:

   1. Nothing inside the box re-lays-out while the box moves. app.js measures
      the copy once and writes --tip-copy-width, so the description is wrapped
      at its final width before the card ever opens; the growing card only
      un-clips text that is already in position. Padding is identical in both
      states for the same reason: the title then simply rides the box out to
      its new width instead of also sliding around inside it. Widths come from
      the same measurement (--tip-rest-width, --tip-open-width), so the card is
      only ever as wide as its own text.
   2. No backdrop-filter. The tooltip lives inside .interactive-map, a large
      composited layer, and re-blurring that backdrop on every frame of a
      resizing element is what made the morph judder on a zoomed-in map. An
      opaque fill plus will-change while open keeps repaints local. */

.map-building__label {
  /* Rest values are the *closing* transition: shorter, and eased out rather
     than accelerating into a hard stop the way the opening curve does.

     The colour duration is deliberately far shorter than the shape one, and
     never grows with it. The pill and the card invert -- #7a0b12 on white
     becomes white on #4a0509 -- so any cross-fade between them passes through
     a midpoint where text and background are the same muddy pink and the
     title is unreadable. It cannot be eased around, only crossed quickly
     enough not to be seen, which leaves the shape free to take its time. */
  --tip-width-duration: .18s;
  --tip-shape-duration: .18s;
  --tip-color-duration: .07s;
  --tip-motion-ease: cubic-bezier(.33, 0, .2, 1);
  position: absolute;
  left: 50%;
  top: calc(-1.35em - 22px - var(--label-dy, 0%));
  transform: translateX(-50%);
  rotate: calc(var(--rot, 0deg) * -1);
  z-index: 5;
  display: grid;
  grid-template-rows: auto 0fr;
  /* Stretch, not start: the description row has to be exactly as tall as its
     track for its own overflow:hidden to clip anything. Left at start it was
     sized by its content instead, so the copy hung outside the card and was
     painted straight onto the map for the length of the morph. */
  align-items: stretch;
  width: var(--tip-rest-width, max-content);
  max-width: 260px;
  padding: 6px 12px 7px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .72);
  background: #fff;
  box-shadow: 0 1px 2px rgba(74, 5, 9, .16), 0 6px 16px -6px rgba(74, 5, 9, .3);
  color: var(--navy-800);
  font-size: clamp(10px, .82vw, 13.5px);
  line-height: 1.35;
  letter-spacing: -.005em;
  text-align: left;
  pointer-events: none;
  transition:
    width var(--tip-width-duration) var(--tip-motion-ease),
    grid-template-rows var(--tip-shape-duration) var(--tip-motion-ease),
    border-radius var(--tip-width-duration) var(--tip-motion-ease),
    border-color var(--tip-color-duration) linear,
    background-color var(--tip-color-duration) linear,
    color var(--tip-color-duration) linear,
    box-shadow var(--tip-shape-duration) var(--tip-motion-ease);
}
.map-building__label-head {
  display: flex;
  align-items: center;
  min-width: 0;
  font-weight: 650;
  white-space: nowrap;
}
/* Zero width at rest so the collapsed row cannot lend the pill the
   description's intrinsic width before app.js has measured anything. */
.map-building__description-wrap {
  width: 0;
  min-height: 0;
  overflow: hidden;
  opacity: 0;
  transform: translate3d(0, -3px, 0);
  transition:
    opacity .1s linear,
    transform .14s var(--tip-motion-ease);
}
.map-building__description {
  display: block;
  width: var(--tip-copy-width, 172px);
  padding-top: 5px;
  color: #f6dfe0;
  font-size: .9em;
  font-weight: 400;
  line-height: 1.42;
  white-space: normal;
  text-wrap: pretty;
}
/* the tail pointing down from the pill toward the building */
.map-building__label::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 6px solid transparent;
  border-top-color: #fff;
  filter: drop-shadow(0 2px 1px rgba(74, 5, 9, .1));
  transition: border-color var(--tip-color-duration) linear;
}
/* collapsed to zero width at rest so the pill centers on the text alone;
   expands open on hover instead of just fading in, so the label doesn't jump */
.map-building__go {
  flex: none;
  width: 0; height: 1em;
  opacity: 0;
  overflow: hidden;
  transform: translateX(-4px);
  transition:
    width var(--tip-width-duration) var(--tip-motion-ease),
    margin-left var(--tip-width-duration) var(--tip-motion-ease),
    opacity .1s linear,
    transform var(--tip-width-duration) var(--tip-motion-ease);
}

/* Opening runs wider-then-taller: the box reaches its final width first, so
   the copy is un-clipped into a settled column rather than a moving one. */
.map-building:hover .map-building__label,
.map-building:focus-visible:not(.is-tooltip-focus-suppressed) .map-building__label {
  --tip-width-duration: .26s;
  --tip-shape-duration: .36s;
  --tip-color-duration: .05s;
  --tip-motion-ease: cubic-bezier(.16, 1, .3, 1);
}
.map-building.is-intro-highlight .map-building__label {
  --tip-width-duration: .7s;
  --tip-shape-duration: 1s;
  --tip-color-duration: .12s;
  --tip-motion-ease: cubic-bezier(.16, 1, .3, 1);
}
.map-building:hover .map-building__label,
.map-building:focus-visible:not(.is-tooltip-focus-suppressed) .map-building__label,
.map-building.is-intro-highlight .map-building__label {
  grid-template-rows: auto 1fr;
  width: var(--tip-open-width, 196px);
  border-radius: 12px;
  background: var(--navy-900);
  border-color: rgba(255, 255, 255, .16);
  color: #fff;
  box-shadow: 0 2px 6px rgba(74, 5, 9, .22), 0 14px 28px -12px rgba(74, 5, 9, .62);
  will-change: transform;
}
.map-building:hover .map-building__label::after,
.map-building:focus-visible:not(.is-tooltip-focus-suppressed) .map-building__label::after,
.map-building.is-intro-highlight .map-building__label::after {
  border-top-color: var(--navy-900);
}
.map-building:hover .map-building__description-wrap,
.map-building:focus-visible:not(.is-tooltip-focus-suppressed) .map-building__description-wrap,
.map-building.is-intro-highlight .map-building__description-wrap {
  width: 100%;
  opacity: 1;
  transform: translate3d(0, 0, 0);
}
.map-building:hover .map-building__description-wrap,
.map-building:focus-visible:not(.is-tooltip-focus-suppressed) .map-building__description-wrap {
  transition-duration: .2s, .26s;
  transition-timing-function: cubic-bezier(.16, 1, .3, 1);
  transition-delay: .13s;
}
.map-building.is-intro-highlight .map-building__description-wrap {
  transition-duration: .3s, .36s;
  transition-timing-function: cubic-bezier(.16, 1, .3, 1);
  transition-delay: .34s;
}
.map-building:hover .map-building__go,
.map-building:focus-visible:not(.is-tooltip-focus-suppressed) .map-building__go,
.map-building.is-intro-highlight .map-building__go {
  width: 1em;
  margin-left: 5px;
  opacity: 1;
  transform: translateX(0);
}

.map-building:focus-visible .map-building__label {
  outline: 2px solid var(--navy-600);
  outline-offset: 3px;
}

/* Edge-aware variants keep the single expanding card within the map frame. */
.map-building__label--below {
  top: calc(100% + 6px);
}
.map-building__label--below::after {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: #fff;
  filter: drop-shadow(0 -2px 1px rgba(74, 5, 9, .1));
}
.map-building:hover .map-building__label--below::after,
.map-building:focus-visible:not(.is-tooltip-focus-suppressed) .map-building__label--below::after,
.map-building.is-intro-highlight .map-building__label--below::after {
  border-top-color: transparent;
  border-bottom-color: var(--navy-900);
}

.map-building__label--left { left: 0; transform: none; }
.map-building__label--left::after { left: 18%; }
.map-building__label--right { left: auto; right: 0; transform: none; }
.map-building__label--right::after { left: 82%; }

/* --- the building whose section is open --------------------------------- */

.map-building.is-active {
  transform: translateX(-50%) translateY(-1.6%) rotate(var(--rot, 0deg)) scale(1.04);
  z-index: 3;
}
.map-building.is-active img {
  filter:
    drop-shadow(0 16px 22px rgba(74, 5, 9, .3))
    drop-shadow(0 0 18px rgba(211, 19, 29, .75))
    brightness(1.08);
}
.map-building.is-active .map-building__glow {
  opacity: 1;
  animation: building-active 2.2s ease-in-out infinite;
}
.map-building.is-active .map-building__label {
  background: var(--navy-700);
  border-color: #fff;
  color: #fff;
}

@keyframes building-active {
  0%, 100% { opacity: .55; transform: translateX(-50%) scale(.94); }
  50%      { opacity: 1;   transform: translateX(-50%) scale(1.06); }
}

/* ==========================================================================
   Lists
   ========================================================================== */

.list { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.list__row {
  display: flex; align-items: center; gap: var(--ui-space-md);
  padding: 9px var(--ui-space-md); border-bottom: 1px solid var(--line-2);
  color: inherit; text-decoration: none;
}
.list__row:last-child { border-bottom: 0; }
.list__row:hover { background: var(--navy-050); text-decoration: none; }
.list__main { min-width: 0; flex: 1; }
.list__title { font-weight: 600; font-size: var(--ui-text-md); color: var(--navy-800); }
.list__sub { font-size: var(--ui-text-sm); color: var(--ink-3); margin-top: 1px; }
.list__side { display: flex; align-items: center; gap: var(--ui-space-md); font-size: var(--ui-text-sm); color: var(--ink-3); flex: none; }
.list__head {
  display: flex; gap: var(--ui-space-md); padding: 7px var(--ui-space-md);
  background: var(--navy-050); border-bottom: 1px solid var(--line);
  font-size: var(--ui-text-xs); font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3);
}

/* ==========================================================================
   Sidebar layout (detail pages)
   ========================================================================== */

/* min-width:0 on the tracks, or a grid item's automatic minimum size lets one
   wide child (a data table) push the whole column past the viewport and scroll
   the page sideways. Those children scroll inside themselves; the column must
   not grow to fit them. */
.split { display: grid; grid-template-columns: 220px 1fr; gap: var(--ui-space-xl); align-items: start; }
.split > * { min-width: 0; }
.split--right { grid-template-columns: 1fr 270px; }

/* Carries an .article-toc rail outside the article shell it was designed for
   (the course page's dashboard-style .split, not .article-shell). A wider
   first track gives the rail room to sit toward the page edge instead of
   flush against the main column, the way it does on the Welcome steps. */
/* The mission card's serif statement text needs more room than the default
   300px aside gives it, so About trades some of the main column's share over
   (that column holds "What we place" — see .cover-panel at the end of this
   file). Since "What we place" is a single list panel it no longer fills a
   wide track on its own, so the aside takes a proportional share rather than a
   fixed 420px — the two columns then grow together instead of opening a gap
   down the middle of a wide window. */
.about-split { grid-template-columns: minmax(0, 1fr) minmax(410px, 0.6fr); }

.split--toc { grid-template-columns: 200px minmax(0, 1fr); }
.split--toc .article-toc { position: sticky; top: 100px; width: 100%; justify-self: start; margin-right: 0; }

.sidenav { position: sticky; top: 100px; }
.sidenav__title { font-size: var(--ui-text-2xs); font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3); margin-bottom: var(--ui-space-sm); }
.sidenav a {
  display: flex; align-items: center; gap: var(--ui-space-sm);
  padding: 6px var(--ui-space-sm); border-radius: var(--r-sm);
  color: var(--ink-2); font-size: var(--ui-text-md); text-decoration: none;
}
.sidenav a:hover { background: var(--navy-100); color: var(--navy-800); text-decoration: none; }
.sidenav a.is-active { background: var(--navy-700); color: #fff; font-weight: 600; }
.sidenav a .n { margin-left: auto; font-size: var(--ui-text-xs); opacity: .65; }

/* ==========================================================================
   Document identity header (the "same DNA" block)
   ========================================================================== */

.identity {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); overflow: hidden; box-shadow: var(--shadow-1);
}
.identity__top { padding: var(--ui-space-lg) var(--ui-space-lg); border-bottom: 1px solid var(--line-2); background: var(--navy-050); }
.identity__top h1 { font-size: 20px; margin: var(--ui-space-xs) 0 0; }
.identity__grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 1px; background: var(--line-2);
}
.identity__cell { background: var(--surface); padding: 10px var(--ui-space-md); }
.identity__cell dt { font-size: var(--ui-text-2xs); font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); }
.identity__cell dd { margin: 3px 0 0; font-size: var(--ui-text-md); color: var(--ink); }

/* ==========================================================================
   Journeys & flows
   ========================================================================== */

.journey { display: grid; gap: 0; }
.journey__step { display: grid; grid-template-columns: 44px 1fr; gap: 14px; }
.journey__rail { display: flex; flex-direction: column; align-items: center; }
.journey__line { flex: 1; width: 2px; background: var(--line); min-height: 15px; }
.journey__body { padding-bottom: 15px; }
.journey__card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 13px 15px; box-shadow: var(--shadow-1);
}
.journey__card h3 { font-size: 14.5px; }
.is-current .journey__card { border-color: var(--navy-600); }
.is-locked .journey__card { opacity: .72; }
.journey [hidden] { display: none; }

/* circular step progress — replaces the old flat numbered dot */
.ring { position: relative; width: 44px; height: 44px; flex: none; display: grid; place-items: center; border-radius: 50%; }
.ring__svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.ring__track { fill: none; stroke: var(--line); stroke-width: 3; }
.ring__fill {
  fill: none; stroke: var(--ink-3); stroke-width: 3; stroke-linecap: round;
  transition: stroke-dashoffset .5s ease;
}
.ring__label { position: absolute; font-size: 10.5px; font-weight: 700; color: var(--ink-3); letter-spacing: -.02em; }
.ring__icon {
  position: absolute; width: 22px; height: 22px; border-radius: 50%;
  display: none; place-items: center; color: #fff;
}
.ring__icon .icon { width: 13px; height: 13px; stroke-width: 3; }

.ring.is-done .ring__track,
.ring.is-done .ring__fill { stroke: var(--green-600); }
.ring.is-done .ring__icon { display: grid; background: var(--green-600); }
.ring.is-done .ring__label { display: none; }

.ring.is-current .ring__fill { stroke: var(--navy-700); }
.ring.is-current .ring__label { color: var(--navy-700); }
.ring.is-current { box-shadow: 0 0 0 4px rgba(211, 19, 29, .18); }

.ring.is-locked .ring__label { color: var(--ink-3); }

.btn.is-disabled,
.btn[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed; pointer-events: none;
}

/* Horizontal step flow (the → diagrams from the plan). A centered grid,
   four nodes per row — the arrow is each node's own ::after, not a
   separate grid item, so adding or removing a node never has to manage
   arrows between cards, only the cards themselves. */
.flow {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 200px));
  gap: 18px 24px;
  max-width: 100%;
  width: fit-content;
  margin: 0 auto;
}
.flow__node {
  position: relative;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 9px 12px; font-size: 13.5px; font-weight: 600; color: var(--navy-800);
  display: flex; align-items: center; gap: 7px; min-width: 0;
}
.flow__node > span { overflow-wrap: anywhere; }
/* The arrow after every node except a row's last (4th, 8th, …) or the
   flow's actual last node, whichever comes first. */
.flow__node:not(:nth-child(4n)):not(:last-child)::after {
  content: "";
  position: absolute;
  top: 50%;
  right: -25px;
  width: 14px;
  height: 14px;
  transform: translateY(-50%);
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238a7a7c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13'/%3E%3Cpath d='m13 6 6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
}
.is-edit-mode .flow__node .edit-remove { position: absolute; top: -8px; right: -8px; margin: 0; background: var(--surface); border: 1px solid var(--line); }
.is-edit-mode .flow { margin-bottom: 7px; }

@media (max-width: 640px) {
  .flow { grid-template-columns: minmax(0, 1fr); }
  .flow__node:not(:nth-child(4n)):not(:last-child)::after { display: none; }
}

/* ==========================================================================
   Progress
   ========================================================================== */

.bar { height: 6px; border-radius: 999px; background: var(--line-2); overflow: hidden; }
.bar > i { display: block; height: 100%; background: var(--teal-600); border-radius: 999px; }
.bar--navy > i { background: var(--navy-600); }

/* ==========================================================================
   Tables
   ========================================================================== */

.tablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
table.data { width: 100%; border-collapse: collapse; font-size: var(--ui-text-md); min-width: 540px; }
table.data th {
  text-align: left; padding: 8px var(--ui-space-md); background: var(--navy-050);
  font-size: var(--ui-text-xs); font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3);
  border-bottom: 1px solid var(--line);
}
table.data td { padding: 8px var(--ui-space-md); border-bottom: 1px solid var(--line-2); vertical-align: middle; }
table.data tr:last-child td { border-bottom: 0; }
table.data tr:hover td { background: var(--navy-050); }

/* ==========================================================================
   Stats
   ========================================================================== */

.stats { display: grid; grid-template-columns: repeat(var(--stat-cols, 4), minmax(0, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.stat { background: var(--surface); padding: var(--ui-space-md) var(--ui-space-lg); }
.stat b { display: block; font-size: 20px; font-weight: 700; color: var(--navy-800); line-height: 1.1; }
.stat span { font-size: var(--ui-text-sm); color: var(--ink-3); }

/* Welcome overview metrics — progress needs more context than a generic stat. */
.welcome-metrics {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--ui-grid-gap);
}
.welcome-metric {
  position: relative; min-width: 0; overflow: hidden;
  padding: var(--ui-card-pad-lg); border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); box-shadow: var(--shadow-1);
}
.welcome-metric::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--metric-accent, var(--navy-600));
}
.welcome-metric--progress { --metric-accent: var(--green-600); --metric-tint: var(--green-100); --metric-ink: var(--green-700); }
.welcome-metric--time { --metric-accent: var(--navy-600); --metric-tint: var(--navy-100); --metric-ink: var(--navy-700); }
.welcome-metric__header { display: flex; align-items: center; gap: var(--ui-space-sm); }
.welcome-metric__icon {
  width: 32px; height: 32px; flex: none; display: grid; place-items: center;
  border-radius: 9px; background: var(--metric-tint); color: var(--metric-ink);
}
.welcome-metric__icon .icon { width: var(--ui-icon); height: var(--ui-icon); }
.welcome-metric__eyebrow {
  margin: 0 0 1px; color: var(--ink-3); font-size: var(--ui-text-2xs); font-weight: 700;
  letter-spacing: .08em; line-height: 1.35; text-transform: uppercase;
}
.welcome-metric h2 { margin: 0; color: var(--ink-2); font-size: var(--ui-text-md); line-height: 1.35; }
.welcome-metric__reading {
  display: flex; align-items: flex-end; justify-content: space-between; gap: var(--ui-space-md);
  margin-top: var(--ui-space-md);
}
.welcome-metric__value { display: flex; align-items: baseline; gap: var(--ui-space-xs); margin: 0; line-height: 1; }
.welcome-metric__value strong {
  color: var(--ink); font-size: clamp(26px, 2.6vw, 32px); font-weight: 750;
  letter-spacing: -.04em;
}
.welcome-metric__value span { color: var(--ink-2); font-size: var(--ui-text-md); font-weight: 600; }
.welcome-metric__status {
  padding: 3px var(--ui-space-sm); border-radius: 999px; background: var(--green-100);
  color: var(--green-700); font-size: var(--ui-text-xs); font-weight: 700; white-space: nowrap;
}
.welcome-metric__bar {
  height: 7px; margin-top: 15px; overflow: hidden; border-radius: 999px;
  background: var(--line-2);
}
.welcome-metric__bar span {
  display: block; height: 100%; border-radius: inherit; background: var(--green-600);
}
.welcome-metric__note { margin: 10px 0 0; color: var(--ink-3); font-size: 12.5px; }
.welcome-metric--time .welcome-metric__note {
  margin-top: 20px; padding-top: 10px; border-top: 1px solid var(--line-2);
}

/* ==========================================================================
   Misc panels
   ========================================================================== */

.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: 15px; }
.panel--accent { border-left: 3px solid var(--navy-600); }
.panel--gold {
  background: linear-gradient(135deg, #fff4f4, #fff);
  border-color: #f0c4c7;
}

.note {
  background: var(--navy-050); border: 1px dashed #edb9bc; border-radius: var(--r);
  padding: 10px 12px; font-size: 13px; color: var(--ink-2);
}

.filedot {
  width: 34px; height: 34px; border-radius: 7px; flex: none;
  display: grid; place-items: center;
  font-size: 9.5px; font-weight: 800; letter-spacing: .02em;
  background: var(--navy-100); color: var(--navy-700);
}
.filedot--PPTX { background: #f9e3da; color: #9a4a25; }
.filedot--DOCX { background: #f9e4e2; color: #a3382b; }
.filedot--XLSX { background: #f7e0dc; color: #94402e; }
.filedot--ZIP  { background: #f0e7e4; color: #75574f; }
.filedot--SVG  { background: #f4dade; color: #7c1b2c; }
.filedot--JPG  { background: #fbdce4; color: #a52449; }
.filedot--HTML { background: #f5e2e1; color: #8a3230; }
.filedot--PDF  { background: #fbd7d9; color: #a80f18; }

/* checklist rows */
.checkrow {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 0;
  border: 0; border-bottom: 1px solid var(--line-2); background: transparent;
  color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.checkrow:last-child { border-bottom: 0; }
.checkbox { width: 18px; height: 18px; border-radius: 5px; border: 1.5px solid #e3c2c4; flex: none; display: grid; place-items: center; color: #fff; }
/* Ticking a box means done, and done is green everywhere else in this UI
   (progress rings, "Complete" badges) — it was reading as brand maroon. */
.checkbox.on { background: var(--green-600); border-color: var(--green-600); }
.checkrow:hover .checkbox { border-color: var(--green-600); }

/* The mission is the one statement on this page that should stop you, so it is
   inverted instead of being a fifth pink box. Same brand hue, opposite value —
   the contrast does the work that another tint could not. */
.mission-card {
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: 40px minmax(0, 1fr); gap: var(--ui-space-md);
  padding: clamp(16px, 2.2vw, 24px);
  border: 0; border-radius: var(--r);
  background: linear-gradient(135deg, #4a0509 0%, #6d0a10 55%, #8a0d14 100%);
  box-shadow: var(--shadow-2);
}
/* The pull is budgeted against the window, so inside the section modal — where
   the article sits in a dialog inset from both edges and the shell is already
   centred on its own container — it reached past the dialog and ran over the
   contents rail. The article layout gives wide blocks the whole column now,
   which is the room this was trying to borrow. */
.mission-card--wide {
  margin-inline: calc(clamp(0px, calc(50vw - 623px), 60px) * -1);
}
.article-page .mission-card--wide,
.modal__body .mission-card--wide { margin-inline: 0; }
/* soft highlight so the flat fill reads as a surface, not a block of ink */
.mission-card::after {
  content: ""; position: absolute; top: -60%; right: -10%;
  width: 420px; height: 420px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, .10), transparent 70%);
  pointer-events: none;
}
.mission-card > * { position: relative; z-index: 1; }
.mission-card__icon {
  width: 40px; height: 40px; display: grid; place-items: center;
  border-radius: 11px; color: #fff;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .18);
}
.mission-card__label {
  margin-bottom: var(--ui-space-2xs); font-size: var(--ui-text-2xs); font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: #f5c8cb;
}
.mission-card__content { display: grid; gap: var(--ui-space-lg); }
.mission-card__principle + .mission-card__principle {
  padding-top: var(--ui-space-lg);
  border-top: 1px solid rgba(255, 255, 255, .18);
}
.mission-card__statement {
  max-width: 820px; margin-bottom: var(--ui-space-sm); font-family: var(--serif);
  font-size: clamp(17px, 1.6vw, 22px); line-height: 1.35; color: #fff;
}
.mission-card__principle .mission-card__statement { margin-bottom: 0; }
/* .70 is the floor that still clears AA against the light end of the gradient */
.mission-card .muted { color: rgba(255, 255, 255, .7); }

/* No icon column on the About page's card: content fills the full width. */
.mission-card--no-icon { grid-template-columns: minmax(0, 1fr); }
/* Scaled down from the welcome page's full-width card to fit this narrower
   aside without wrapping awkwardly. */
.mission-card--compact { gap: 12px; padding: 16px; }
.mission-card--compact .mission-card__statement { font-size: 18px; line-height: 1.45; max-width: none; }
.mission-card--compact .mission-card__content { gap: 15px; }
.mission-card--compact .mission-card__principle + .mission-card__principle { padding-top: 15px; }

.company-timeline {
  position: relative; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 9px; margin: 0; padding: 18px 0 0; list-style: none;
}
.company-timeline::before {
  content: ""; position: absolute; right: 4px; bottom: 39px; left: 4px;
  height: 3px; border-radius: 999px;
  background: linear-gradient(90deg, #7a0b12, #8a5a10 20%, #566b14 40%, #0f6f63 60%, #2b4fa8 80%, #7b3a9e);
}
.company-timeline::after {
  content: ""; position: absolute; right: 0; bottom: 34px;
  border-top: 6px solid transparent; border-bottom: 6px solid transparent;
  border-left: 9px solid #7b3a9e;
}
.company-timeline__item {
  --milestone: var(--navy-600);
  position: relative; z-index: 1; display: grid; grid-template-rows: 1fr 20px 29px;
  min-width: 0; text-align: center;
}
/* Milestones walk the colour wheel instead of stepping through six reds, so the
   eye can tell eras apart at a glance and the row stops reading as one block.
   Starts on brand maroon (the founding) and travels to purple (today). Each
   stop is a tag-palette tone, so it stays in the same muted family as the rest
   of the UI; the wash is the same hue at ~96% lightness to keep body text AA.
   The rules cycle (6n+k), so rows seven and onward repeat the same six —
   nothing beyond the sixth ever draws the neutral fallback above. */
.company-timeline__item:nth-child(6n+1) { --milestone: #7a0b12; --milestone-wash: #fdf4f4; }
.company-timeline__item:nth-child(6n+2) { --milestone: #8a5a10; --milestone-wash: #fdf6ea; }
.company-timeline__item:nth-child(6n+3) { --milestone: #566b14; --milestone-wash: #f6faea; }
.company-timeline__item:nth-child(6n+4) { --milestone: #0f6f63; --milestone-wash: #eef8f4; }
.company-timeline__item:nth-child(6n+5) { --milestone: #2b4fa8; --milestone-wash: #eff5fd; }
.company-timeline__item:nth-child(6n+6) { --milestone: #7b3a9e; --milestone-wash: #f9f0fd; }
.company-timeline__card-wrap { position: relative; height: 100%; padding-top: 26px; }
.company-timeline__icon {
  position: absolute; top: 0; left: 50%; z-index: 2; transform: translateX(-50%);
  width: 66px; height: 66px; display: grid; place-items: center;
  border: 5px solid var(--surface); border-radius: 50%;
  background: var(--milestone); color: #fff; box-shadow: var(--shadow-1);
}
.company-timeline__card {
  height: 100%; min-height: 170px; padding: 33px 10px 30px;
  background: var(--milestone-wash, var(--line-2));
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 28px), 50% 100%, 0 calc(100% - 28px));
}
.company-timeline__label {
  margin-bottom: 5px; color: var(--milestone); font-size: 9.5px;
  font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
}
.company-timeline__card h3 { margin-bottom: 9px; font-size: 14px; }
.company-timeline__card p { margin: 0; color: var(--ink-2); font-size: 12px; line-height: 1.5; }
.company-timeline__marker {
  width: 15px; height: 15px; place-self: center; border-radius: 50%;
  background: var(--milestone); box-shadow: 0 0 0 4px var(--surface);
}
.company-timeline__year {
  color: var(--milestone); font-size: 13px; font-weight: 800;
  font-variant-numeric: tabular-nums;
}


/* ---------------------------------------------------------------------------
   Organization chart (Welcome, step 2)
   The old version hung all ten departments off one placeholder node, so it drew
   a hierarchy that does not exist and taught nothing. This one shows the shape
   a new employee actually needs: two tiers of leadership, three groups, and the
   departments inside each. Names only — the detail lives under Departments.
   --------------------------------------------------------------------------- */

.org-chart {
  --org-gap: clamp(12px, 1.6vw, 20px);
  --org-line: #ded0d1;
  display: grid; justify-items: center;
  min-width: 0;
}

.org-chart__node {
  width: min(100%, 460px); padding: 13px 16px;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); box-shadow: var(--shadow-1);
  text-align: center;
}
.org-chart__tier {
  margin: 0 0 5px; color: var(--navy-600); font-size: 10px; font-weight: 800;
  letter-spacing: .11em; text-transform: uppercase;
}
.org-chart__node strong { display: block; color: var(--navy-900); font-size: 14px; }
.org-chart__node > span { display: block; margin-top: 2px; color: var(--ink-2); font-size: 13px; }
.org-chart__note { margin: 7px 0 0; color: var(--ink-3); font-size: 12.5px; line-height: 1.5; }

.org-chart__stem { width: 2px; height: 22px; background: var(--org-line); }
/* Spans centre-of-first-column to centre-of-last, so the three drops below land
   on the three cards whatever the gap resolves to. */
.org-chart__branch {
  width: calc(100% - (100% - var(--org-gap) * 2) / 3);
  height: 2px; background: var(--org-line);
}

.org-chart__groups {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--org-gap); align-items: start;
  width: 100%; margin-top: 18px;
}

/* One accent per group, so the three branches stay tellable apart at a glance
   without three different card treatments. */
.org-group {
  position: relative; display: grid; align-content: start;
  padding: 15px 15px 14px;
  border: 1px solid var(--line); border-top: 3px solid var(--group-accent);
  border-radius: var(--r); background: var(--surface);
}
.org-group::before {
  content: ""; position: absolute; top: -22px; left: calc(50% - 1px);
  width: 2px; height: 22px; background: var(--org-line);
}
.org-group--blue  { --group-accent: var(--tag-blue-fg);  --group-tint: var(--tag-blue-bg); }
.org-group--teal  { --group-accent: var(--tag-teal-fg);  --group-tint: var(--tag-teal-bg); }
.org-group--amber { --group-accent: var(--tag-amber-fg); --group-tint: var(--tag-amber-bg); }

/* Floors rather than a shared subgrid: the department lists still start on the
   same line across the three cards, but each card ends after its own last
   department instead of stretching to match the group that has five. The floor
   sits on the wrapping line itself, not on the head — a min-height on the head
   would stretch its rows and drift the three titles out of line. */
.org-group__head { display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 3px 10px; }
.org-group__icon {
  grid-row: span 2; width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 9px; background: var(--group-tint); color: var(--group-accent);
}
.org-group__icon .icon { width: 18px; height: 18px; }
.org-group__head h4 { align-self: center; color: var(--navy-900); font-size: 14px; }
.org-group__lead { min-height: 2.8em; margin: 0; color: var(--ink-3); font-size: 11.5px; line-height: 1.4; }
.org-group__role {
  /* three lines plus the padding, because border-box makes min-height include it */
  min-height: calc(4.65em + 13px);
  margin: 10px 0 0; padding-bottom: 11px; border-bottom: 1px solid var(--line-2);
  color: var(--ink-2); font-size: 13px; line-height: 1.55;
}

.org-group__depts { list-style: none; margin: 4px 0 0; padding: 0; }
.org-group__depts a {
  display: flex; align-items: center; justify-content: space-between; gap: 7px;
  padding: 7px 0; border-bottom: 1px solid var(--line-2);
  color: var(--ink); font-size: 13.5px; font-weight: 600;
}
.org-group__depts li:last-child a { border-bottom: 0; }
.org-group__depts a .icon { width: 14px; height: 14px; color: var(--ink-3); flex: none; }
.org-group__depts a:hover { color: var(--group-accent); text-decoration: none; }
.org-group__depts a:hover .icon { color: var(--group-accent); }

/* A waterfall rather than a left-to-right flow: each stage hands the work down
   to the next, and the step-per-step indent makes that descent the shape of the
   diagram. Tones match the three groups in the chart above, so a reader can see
   which group each stage belongs to without the label repeating it. */
.waterfall {
  --wf-indent: clamp(18px, 3vw, 46px);
  --wf-gap: 12px;
  --wf-line: #e0cfd0;
  list-style: none; display: grid; gap: var(--wf-gap);
  margin: 18px 0 0; padding: 0;
  min-width: 0;
}
.waterfall__step { position: relative; padding-left: calc(var(--i) * var(--wf-indent)); }

/* The elbow: down from inside the previous card, then right to this one's edge.
   Both offsets are derived from --i, so the corner lands correctly however far
   the indent resolves at this viewport. */
.waterfall__step + .waterfall__step::before {
  content: "";
  position: absolute;
  top: calc(var(--wf-gap) * -1);
  left: calc((var(--i) - 1) * var(--wf-indent) + 17px);
  width: calc(var(--wf-indent) - 17px);
  height: calc(var(--wf-gap) + 21px);
  border-left: 2px solid var(--wf-line);
  border-bottom: 2px solid var(--wf-line);
  border-bottom-left-radius: 9px;
}

.waterfall__card {
  display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 10px;
  padding: 12px 15px;
  border: 1px solid var(--line); border-left: 3px solid var(--wf-accent, var(--ink-3));
  border-radius: var(--r); background: var(--surface);
}
.waterfall__step--blue  { --wf-accent: var(--tag-blue-fg);  --wf-tint: var(--tag-blue-bg); }
.waterfall__step--teal  { --wf-accent: var(--tag-teal-fg);  --wf-tint: var(--tag-teal-bg); }
.waterfall__step--amber { --wf-accent: var(--tag-amber-fg); --wf-tint: var(--tag-amber-bg); }
.waterfall__step--purple { --wf-accent: var(--tag-purple-fg); --wf-tint: var(--tag-purple-bg); }
.waterfall__step--plain { --wf-accent: var(--ink-3);        --wf-tint: var(--line-2); }

.waterfall__n {
  width: 26px; height: 26px; display: grid; place-items: center;
  border-radius: 50%; background: var(--wf-tint); color: var(--wf-accent);
  font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums;
}
.waterfall__card strong { display: block; color: var(--navy-900); font-size: 14px; }
.waterfall__card p { margin: 3px 0 0; color: var(--ink-2); font-size: 13.5px; line-height: 1.55; }

/* Below this the three columns stop being readable. Stacked, the connectors
   would point at nothing, so the chart drops to a plain sequence of groups. */
@media (max-width: 780px) {
  .org-chart__groups { grid-template-columns: minmax(0, 1fr); margin-top: 14px; }
  .org-group__lead, .org-group__role { min-height: 0; }
  .org-chart__branch { display: none; }
  .org-group::before { display: none; }
  .org-chart__node { width: 100%; }
  /* The cascade costs more width than it is worth once the cards are this
     narrow; the numbers still carry the order. */
  .waterfall { --wf-indent: 0px; }
  .waterfall__step + .waterfall__step::before {
    left: 17px; width: 0; height: var(--wf-gap);
    border-bottom: 0; border-bottom-left-radius: 0;
  }
}


/* Centered rows use intrinsic width so an opening panel moves the active
   portrait and every portrait before it to the left. */
/* The tiers are 1 / 4 / 5 / 1 portraits centred in a ~1000px panel, so the short
   rows used to leave most of the width blank. Two things fix that without
   touching the arrangement: the portraits are bigger (the widest tier now nearly
   fills the panel), and the empty space is given a job — it carries the actual
   org-chart rules connecting each tier, drawn in CSS. */
.leadership-directory {
  --leader-portrait: clamp(124px, 12vw, 176px);
  --row-gap: clamp(10px, 1.25vw, 18px);
  /* Tiers sit close together now that nothing is drawn between them. The old
     gap was sized to give the connector tree room to be read; without it that
     space only separated the portraits from each other. */
  --tier-gap: clamp(12px, 1.5vw, 20px);
  position: relative;
  display: grid;
  gap: var(--tier-gap);
  /* Wider side padding than the tiers need: it is the room a speech bubble on
     an end portrait grows into. */
  padding: 21px clamp(19px, 4vw, 38px) 18px;
  border-radius: var(--r);
  background:
    radial-gradient(circle, #f0e5e6 1.1px, transparent 1.2px) 0 0 / 24px 24px,
    linear-gradient(180deg, #fdfbfb, #faf6f6);
  min-width: 0;
}
.leadership-row {
  --pitch: calc(var(--leader-portrait) + var(--row-gap));
  position: relative;
  display: flex;
  justify-content: center;
  gap: var(--row-gap);
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
}
/* The tiers used to be joined by a drawn tree — a stem down from the row above
   and a horizontal bus with one drop per portrait. Those connectors are gone,
   and so is the padding that reserved room for them: the tiers are now spaced
   by --tier-gap alone. */

.leadership-person {
  position: relative;
  flex: 0 0 auto;
  width: var(--leader-portrait);
  min-width: 0;
  border: 1px solid #efe6e6;
  border-radius: var(--r-sm);
  background: var(--surface);
  transition: border-color .2s ease, box-shadow .2s ease;
}
.leadership-person:hover,
.leadership-person:focus-within {
  border-color: #d8c9ca;
  box-shadow: var(--shadow-1);
}
.leadership-person__trigger {
  display: block;
  width: 100%;
  min-width: 0;
  padding: 0;
  border: 0;
  border-radius: inherit;
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: center;
  cursor: pointer;
}
.leadership-person__trigger:focus-visible {
  position: relative;
  z-index: 2;
  outline: 2px solid var(--navy-600);
  outline-offset: -2px;
}
.leadership-person__portrait {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: inherit;
  background: #fff;
}
.leadership-person__portrait img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
}
.leadership-person__caption {
  display: block;
  min-height: 44px;
  padding: 7px 5px 9px;
  line-height: 1.3;
}
.leadership-person__caption strong,
.leadership-person__caption > span { display: block; }
.leadership-person__caption strong {
  margin-bottom: 3px;
  color: var(--ink);
  font-size: 11.5px;
  font-weight: 750;
}
.leadership-person__caption > span {
  color: var(--ink-2);
  font-size: 10px;
}

/* The quote a leader "says" when you point at them. A bubble that floats above
   the head reads as speech in a way a panel sliding out of the card never did,
   and because it overlays rather than expands, the row keeps its width and the
   org-chart rules below stay lined up with the portraits. */
.leader-quote {
  position: absolute;
  bottom: calc(100% + 13px);
  left: 50%;
  z-index: 5;
  width: max-content;
  max-width: min(258px, 70vw);
  margin: 0;
  padding: 10px 13px;
  border: 1px solid #e3d5d6;
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-2);
  color: var(--ink-read);
  font-size: 13px;
  line-height: 1.5;
  text-align: left;
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 6px);
  transition: opacity .16s ease, transform .16s ease, visibility 0s linear .16s;
}
/* The measure holds the bubble at its finished size while the typed copy fills
   in over the top of it, so a quote appearing never resizes the bubble or drags
   the tail off the person's head. */
.leader-quote__body { position: relative; display: block; }
.leader-quote__measure { visibility: hidden; }
.leader-quote__typed { position: absolute; inset: 0; }
.leader-quote__typed::after {
  content: "";
  display: inline-block;
  width: 1px;
  height: 1.05em;
  margin-left: 2px;
  vertical-align: -.14em;
  background: var(--navy-600);
  animation: leader-typing-caret .75s steps(1) infinite;
}
.leader-quote.is-typed .leader-quote__typed::after { display: none; }
@keyframes leader-typing-caret { 50% { opacity: 0; } }

/* Read by aria-describedby on the trigger; never typed, never hidden from AT. */
.leader-quote__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* The tail: a corner of the bubble itself, so border and fill match without a
   second colour to keep in sync. */
.leader-quote::after {
  content: "";
  position: absolute;
  bottom: -7px;
  left: 50%;
  width: 12px;
  height: 12px;
  background: var(--surface);
  border-right: 1px solid #e3d5d6;
  border-bottom: 1px solid #e3d5d6;
  border-bottom-right-radius: 3px;
  transform: translateX(-50%) rotate(45deg);
}
.leadership-person:hover .leader-quote,
.leadership-person:focus-within .leader-quote {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  transition-delay: 0s;
}
/* An end portrait would push its bubble past the panel, so those two anchor to
   their own edge instead of to their centre. Guarded against rows of one, where
   first and last are the same portrait and centring is already correct. */
.leadership-person:first-child:not(:last-child) .leader-quote {
  left: -10px;
  transform: translate(0, 6px);
}
.leadership-person:first-child:not(:last-child):hover .leader-quote,
.leadership-person:first-child:not(:last-child):focus-within .leader-quote { transform: translate(0, 0); }
.leadership-person:first-child:not(:last-child) .leader-quote::after {
  left: calc(var(--leader-portrait) / 2 + 10px);
}
.leadership-person:last-child:not(:first-child) .leader-quote {
  left: auto;
  right: -10px;
  transform: translate(0, 6px);
}
.leadership-person:last-child:not(:first-child):hover .leader-quote,
.leadership-person:last-child:not(:first-child):focus-within .leader-quote { transform: translate(0, 0); }
.leadership-person:last-child:not(:first-child) .leader-quote::after {
  left: auto;
  right: calc(var(--leader-portrait) / 2 + 10px);
  transform: translateX(50%) rotate(45deg);
}
/* search result groups */
.resgroup { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.resgroup__head { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: var(--navy-050); border-bottom: 1px solid var(--line); }
.resgroup__head h3 { font-size: 13.5px; }
.resgroup__head .n { margin-left: auto; font-size: 12px; color: var(--ink-3); }

/* ==========================================================================
   Departments — the directory
   --------------------------------------------------------------------------
   Three groups, each a band: a rail on the left that names the group and
   stays in view while its departments scroll past on the right. The bands are
   separated by structure — space and a heavy rule — not by tinted boxes, so
   the page keeps the library's own palette: warm canvas, white cards, maroon
   only where something is named or can be clicked.

   Logos are uploaded in every shape. initDepartmentLogos() in app.js crops
   each one to its own content, and the stage below contains the result, so a
   badge and a wide lockup end up the same visual size.
   ========================================================================== */
.deptpage-head {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 28px;
  margin: 8px 0 8px; padding-bottom: 26px;
}
.deptpage-head__copy { min-width: 0; max-width: 62ch; }
.deptpage-head__copy h1 {
  margin: 0 0 12px; font-size: clamp(34px, 4vw, 44px); line-height: 1.05;
  font-weight: 500; letter-spacing: -.03em;
}
.deptpage-head__copy p { margin: 0; color: var(--ink-2); font-size: 14.5px; line-height: 1.7; }
.deptpage-head__aside { display: flex; align-items: flex-end; gap: 22px; flex: none; }
.deptpage-head__stats { display: flex; align-items: flex-end; margin: 0; }
.deptpage-head__stat { display: grid; gap: 2px; min-width: 86px; padding: 0 22px; border-left: 1px solid var(--line); }
.deptpage-head__stat:first-child { padding-left: 0; border-left: 0; }
.deptpage-head__stat dd {
  order: -1; margin: 0; color: var(--navy-800); font-family: var(--serif);
  font-size: 32px; line-height: 1; font-weight: 500;
}
.deptpage-head__stat dt { color: var(--ink-2); font-size: 12px; white-space: nowrap; }
.deptpage-head__actions { display: flex; flex-wrap: wrap; gap: var(--ui-space-xs); }
.deptpage-head__actions:empty { display: none; }

/* --- the bands ----------------------------------------------------------- */
.deptgroups { display: grid; gap: 0; margin: 0; }
.deptgroup {
  display: grid; grid-template-columns: minmax(220px, 290px) minmax(0, 1fr);
  gap: 20px 48px; align-items: start;
  padding: 34px 0 46px;
  border-top: 2px solid var(--navy-800);
}
.deptgroup__rail { align-self: stretch; min-width: 0; }
/* The rail rides along while its own band scrolls (the modal body is the
   scroller), then leaves with it — so the reader always knows which group
   the card under their eye belongs to. */
.deptgroup__railinner { position: sticky; top: 24px; display: grid; justify-items: start; }
.deptgroup__icon {
  display: grid; place-items: center; width: 44px; height: 44px; margin-bottom: 18px;
  border-radius: 12px; background: var(--navy-800); color: #fff;
}
.deptgroup__name {
  margin: 0; color: var(--ink); font-family: var(--serif);
  font-size: clamp(26px, 2.3vw, 32px); font-weight: 500; line-height: 1.1; letter-spacing: -.015em;
}
.deptgroup__role { margin: 12px 0 0; color: var(--ink-read); font-size: 14px; line-height: 1.65; text-wrap: pretty; }
.deptgroup__facts {
  display: grid; gap: 12px; width: 100%; margin: 22px 0 0; padding-top: 16px;
  border-top: 1px solid var(--line);
}
.deptgroup__facts > div { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 10px; align-items: baseline; }
.deptgroup__facts dt { color: var(--ink-3); font-size: 12px; }
.deptgroup__facts dd { margin: 0; color: var(--ink); font-size: 13px; font-weight: 600; line-height: 1.45; }

/* --- the cards ----------------------------------------------------------- */
.deptwall {
  list-style: none; display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 18px; min-width: 0; margin: 0; padding: 0;
}
.deptwall > li {
  position: relative; display: flex; min-width: 0; overflow: hidden;
  border: 1px solid var(--line); border-radius: 14px; background: var(--surface);
  box-shadow: 0 1px 2px rgba(74, 5, 9, .04);
  transition: border-color .16s ease, box-shadow .16s ease;
}
.deptwall > li:hover {
  border-color: color-mix(in srgb, var(--navy-700) 40%, var(--line));
  box-shadow: 0 14px 30px -16px rgba(74, 5, 9, .28);
}
.deptlogo {
  position: relative; display: flex; flex: 1; flex-direction: column;
  min-width: 0; padding: 0 22px 18px; color: var(--ink); text-decoration: none;
}
.deptlogo:hover { color: var(--ink); text-decoration: none; }
.deptlogo:focus-visible { outline: 2px solid var(--navy-600); outline-offset: -3px; border-radius: 14px; }

.deptlogo__media {
  display: grid; place-items: center; box-sizing: border-box;
  width: calc(100% + 44px); height: 164px; flex: none; overflow: hidden;
  margin: 0 -22px; padding: 26px 28px;
  border-bottom: 1px solid var(--line-2); background: var(--surface);
}
.deptlogo__media picture { display: grid; place-items: center; width: 100%; height: 100%; min-width: 0; min-height: 0; }
.deptlogo__media > .deptlogo__art,
.deptlogo__media picture > .deptlogo__art {
  display: block; width: 100%; height: 100%; max-width: 232px; max-height: 92px; object-fit: contain;
}
.deptlogo__placeholder {
  display: grid; place-items: center; width: 100%; height: 100%; padding: 12px 16px;
  border-radius: 10px; background: var(--navy-050); color: var(--navy-800);
  font-family: var(--serif); font-size: 22px; line-height: 1.2; text-align: center; text-wrap: balance;
}
.deptlogo__body { display: flex; flex: 1; flex-direction: column; gap: 8px; padding-top: 18px; }
.deptlogo__name { color: var(--ink); font-family: var(--serif); font-size: 20px; font-weight: 500; line-height: 1.25; }
.deptlogo__blurb { margin-bottom: 8px; color: var(--ink-2); font-size: 13px; line-height: 1.6; text-wrap: pretty; }
body:not(.is-edit-mode) .deptlogo__blurb {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
.deptlogo__footer {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: auto; padding-top: 14px; border-top: 1px solid var(--line-2);
}
.deptlogo__visit { color: var(--navy-700); font-size: 13px; font-weight: 600; }
.deptlogo:hover .deptlogo__visit { text-decoration: underline; text-underline-offset: 3px; }
.deptlogo__sections { color: var(--ink-3); font-size: 12px; white-space: nowrap; }
.deptlogo__edit { position: absolute; right: 12px; bottom: 12px; z-index: 3; }
.is-edit-mode .deptlogo__body { padding-bottom: 34px; }

@media (max-width: 900px) {
  .deptgroup { grid-template-columns: minmax(0, 1fr); gap: 22px; padding: 26px 0 36px; }
  .deptgroup__railinner { position: static; }
  .deptgroup__role { max-width: 64ch; }
  .deptgroup__facts { grid-template-columns: auto minmax(0, 1fr); gap: 28px; max-width: 64ch; }
  .deptgroup__facts > div { grid-template-columns: none; gap: 2px; }
}
@media (max-width: 620px) {
  .deptpage-head { align-items: flex-start; flex-direction: column; gap: 18px; padding-bottom: 18px; }
  .deptpage-head__aside { width: 100%; justify-content: space-between; flex-wrap: wrap; gap: 14px; }
  .deptpage-head__actions { width: 100%; }
  .deptgroup__icon { width: 40px; height: 40px; margin-bottom: 14px; }
  .deptwall { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .deptlogo { padding: 0 20px 16px; }
  .deptlogo__media { width: calc(100% + 40px); margin: 0 -20px; height: 150px; padding: 22px 26px; }
}
@media (prefers-reduced-motion: reduce) {
  .deptwall > li { transition: none; }
}

/* Cover-led library. The covers are CSS artwork so every official resource
   gets a consistent identity without pretending placeholder images are real
   publications. */
.bookshelf { margin-top: 24px; }
.bookshelf-tools {
  display: grid;
  grid-template-columns: minmax(260px, 1.65fr) repeat(5, minmax(120px, .72fr)) auto;
  gap: 10px; align-items: end;
  padding: 15px;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background:
    radial-gradient(circle at 8% 0%, rgba(143, 20, 27, .08), transparent 34%),
    linear-gradient(135deg, var(--surface), var(--navy-050));
  box-shadow: var(--shadow-1);
}
.bookshelf-field { min-width: 0; }
.bookshelf-field label {
  display: block; margin: 0 0 6px 2px;
  color: var(--ink-2); font-size: 12px; font-weight: 700;
}
/* One explicit height, not min-height: a date input carries native inner
   chrome that made it ~3px taller than the selects beside it, so the filter
   row sat at three different heights. Height + border-box pins them level. */
.bookshelf-field select,
.bookshelf-field input[type="date"],
.bookshelf-search {
  width: 100%; height: var(--ui-control-h); min-height: 0;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: var(--ui-text-sm);
}
.bookshelf-field select,
.bookshelf-field input[type="date"] { padding: 0 10px; cursor: pointer; }
.bookshelf-search {
  display: flex; align-items: center; gap: 8px; padding: 0 10px;
}
.bookshelf-search .icon { width: 18px; height: 18px; flex: none; color: var(--ink-3); }
.bookshelf-search input {
  width: 100%; min-width: 0; padding: 0;
  border: 0; outline: 0; background: transparent; color: var(--ink);
  font: inherit; font-size: 14px;
}
.bookshelf-field select:hover,
.bookshelf-field input[type="date"]:hover,
.bookshelf-search:hover { border-color: #d8a6a9; }
.bookshelf-field select:focus-visible,
.bookshelf-field input[type="date"]:focus-visible,
.bookshelf-search:focus-within {
  border-color: var(--navy-600); outline: 2px solid rgba(143, 20, 27, .18); outline-offset: 1px;
}
.bookshelf-clear { height: var(--ui-control-h); min-height: 0; }
.bookshelf-clear:disabled { opacity: .48; cursor: default; }

.bookshelf-status {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  margin: 18px 0 15px; padding-bottom: 10px; border-bottom: 1px solid var(--line);
  color: var(--ink-3); font-size: 12.5px;
}
.bookshelf-status p { margin: 0; }
.bookshelf-status strong { color: var(--navy-900); font-size: 15px; }
.bookshelf-empty {
  margin: 21px 0; padding: 18px;
  border: 1px dashed #d8a6a9; border-radius: var(--r);
  background: var(--navy-050); color: var(--ink-2); text-align: center;
}

.book-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(185px, 1fr));
  gap: 25px 19px; align-items: start;
}
.book-card {
  display: flex; flex-direction: column; min-width: 0;
  color: var(--ink); text-decoration: none; perspective: 900px;
}
.book-card:hover { text-decoration: none; }
.book-card:focus-visible { outline: 0; }
.book-card:focus-visible .book-cover {
  outline: 3px solid var(--navy-600); outline-offset: 4px;
}
.book-cover {
  --cover-a: #5f1017;
  --cover-b: #28070b;
  position: relative; isolation: isolate;
  display: flex; flex-direction: column;
  aspect-ratio: .72; min-height: 160px; overflow: hidden;
  padding: 19px 15px 15px 22px;
  border: 1px solid rgba(29, 8, 10, .35); border-radius: 3px 9px 9px 3px;
  background:
    radial-gradient(circle at 78% 18%, rgba(255, 255, 255, .16), transparent 25%),
    linear-gradient(145deg, var(--cover-a), var(--cover-b));
  box-shadow: 0 14px 24px rgba(44, 20, 22, .18), 5px 5px 0 #eadfda, 7px 7px 0 #cbbdb8;
  color: #fff;
  transform-origin: left center;
  transition: transform .22s ease, box-shadow .22s ease;
}
.book-cover::before {
  content: ""; position: absolute; z-index: -1; inset: 10px;
  border: 1px solid rgba(255, 255, 255, .2); border-radius: 2px 6px 6px 2px;
  pointer-events: none;
}
.book-cover::after {
  content: ""; position: absolute; right: 8px; bottom: 8px;
  width: 32px; height: 32px; opacity: .42;
  border-right: 1px solid currentColor; border-bottom: 1px solid currentColor;
  pointer-events: none;
}
.book-card:hover .book-cover {
  transform: translateY(-5px) rotateY(-4deg);
  box-shadow: 0 20px 30px rgba(44, 20, 22, .22), 7px 6px 0 #eadfda, 9px 8px 0 #cbbdb8;
}
.book-cover--navy { --cover-a: #243c5a; --cover-b: #0d1b2b; }
.book-cover--cranberry { --cover-a: #9a2630; --cover-b: #4a090e; }
.book-cover--teal { --cover-a: #286b6a; --cover-b: #113837; }
.book-cover--amber { --cover-a: #9a6428; --cover-b: #503013; }
.book-cover--plum { --cover-a: #694269; --cover-b: #342033; }
.book-cover--slate { --cover-a: #56626d; --cover-b: #293038; }
.book-cover__spine {
  position: absolute; inset: 0 auto 0 0; width: 14px;
  border-right: 1px solid rgba(255, 255, 255, .16);
  background: linear-gradient(90deg, rgba(0, 0, 0, .35), rgba(255, 255, 255, .08), rgba(0, 0, 0, .2));
}
.book-cover__edition {
  color: rgba(255, 255, 255, .78); font-size: 10px; font-weight: 750;
  letter-spacing: .12em; line-height: 1.35; text-transform: uppercase;
}
.book-cover__title {
  display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 5;
  margin-top: 15px;
  color: #fff; font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(14px, 1.35vw, 17px); font-weight: 600; line-height: 1.18;
  overflow-wrap: anywhere; text-wrap: balance;
}
.book-cover__rule { width: 34px; height: 2px; margin: 13px 0 10px; background: rgba(255, 255, 255, .65); }
.book-cover__department {
  color: rgba(255, 255, 255, .8); font-size: 11px; font-weight: 600; line-height: 1.35;
}
.book-cover__brand {
  margin-top: auto; color: rgba(255, 255, 255, .86);
  font-size: 10px; font-weight: 800; letter-spacing: .16em;
}
.book-card__details { display: flex; flex-direction: column; min-width: 0; padding: 14px 5px 0; }
.book-card__title { color: var(--navy-900); font-size: 14px; font-weight: 680; line-height: 1.35; }
.book-card__owner { margin-top: 4px; color: var(--ink-2); font-size: 12px; }
.book-card__file {
  margin-top: 7px; color: var(--navy-700); font-size: 11.5px; font-weight: 650;
  letter-spacing: .01em;
}
.book-card__dates {
  display: flex; flex-direction: column; gap: 2px; margin-top: 8px;
  color: var(--ink-3); font-size: 12px; line-height: 1.4;
}

/* How We Work is presented as a physical shelf. The source artwork supplies
   the four ledges; the grid is a transparent overlay whose four rows land on
   those ledges while still allowing filtering and pagination to reflow books. */
.shelf-scene {
  position: relative;
  isolation: isolate;
  width: 100%;
  margin-top: 4px;
  /* The artwork is 1672x941, and holding that ratio is what keeps the painted
     ledges where the row percentages below expect them — the scene used to
     stretch the image to `100% 100%` against an arbitrary min-height, which
     slid every ledge off its row and left the books hanging in mid-air.

     But at the artwork's natural ratio the bays come out shorter than a book
     cover, so the shelf is deliberately scaled taller than that. The binding
     constraint is the *shallowest* bay, the 18% strip above the top ledge: a
     190px-wide cover is ~280px tall, so that bay needs the scene to be about
     1700px for a book to stand in it with headroom. Sizing for that is what
     lets all four bays hold books — the top one used to be left empty
     precisely because the scene was too short for a cover to fit there.

     The background still stretches to the box, which makes the bookcase read
     as taller and deeper; the ledges stay put because the row percentages
     below are relative to the same box. */
  min-height: clamp(1260px, 128vw, 1860px);
  overflow: visible;
  border: 1px solid rgba(86, 45, 18, .45);
  border-radius: 9px;
  background: #a8642b url('../img/bg-shelf.png') center / 100% 100% no-repeat;
  box-shadow: 0 18px 34px rgba(66, 35, 16, .25), inset 0 0 0 2px rgba(255, 219, 157, .18);
}

/* Each row *ends* on the top surface of a painted ledge, measured off the
   artwork itself: the four ledge faces sit at 18.0%, 39.4%, 61.5% and 88.4%
   of the image height. `align-items: end` then stands every book's base on
   that line, which is what makes a book look like it is resting on the shelf
   rather than floating above it.

   The rows are the gaps *between* those lines rather than starting at the
   top of the scene, because a book is taller than the 18% above the first
   ledge — sized that way it overflowed straight out of the top of the
   bookcase. So the first row ends on the second ledge (39.4%) and the
   shortest bay, the 18% strip above the top ledge, carries no books at all.
   Changing the artwork means re-measuring these numbers and nothing else. */
.book-grid.book-grid--shelf {
  position: absolute;
  inset: 0;
  display: grid;
  /* Five slots per bay, always. A bay holding fewer books leaves the
     right-hand slots empty rather than re-centring what is there — see
     justify-self on .book-card below. */
  grid-template-columns: repeat(5, minmax(0, 1fr));
  /* Four bays, all four holding books. Each row ends on a painted ledge —
     18.0%, 39.5%, 61.5%, 88.4% — so a row never straddles one, and the row
     heights are simply the gaps between those lines. The 11.6% plinth below
     the bottom ledge is bottom padding, so nothing is laid out on it.

     The padding is left/right ONLY, and that is load-bearing: percentage
     rows resolve against the grid's *content* box, so a bottom padding of
     11.6% shrank that box to 88.4% of the scene and pulled every row line
     short of its ledge — 18% became 15.9%, 88.4% became 78.1%, and every
     book floated above the timber instead of resting on it. The plinth is
     kept clear by the fourth row ending at 88.4% instead. */
  grid-template-rows: 18% 21.5% 22% 26.9%;
  gap: 0 1.2%;
  align-items: end;
  padding: 0 5%;
}
.book-grid--shelf .book-card {
  position: relative;
  z-index: 2;
  /* Start, not center: books line up from slot 1 leftwards, so a bay holding
     two books reads as slots 1 and 2 with three empties after them — the way
     a real shelf fills — rather than drifting to the middle of the bay. */
  justify-self: start;
  /* The row line is the ledge's *top* surface, but the painted ledge has
     thickness below it and the cover carries a drop shadow. Lifting the card
     a little stands it on the ledge instead of sinking its base into it. */
  bottom: 3px;
  /* The book keeps its own size. The shelf is what grows to fit it — the
     bays are sized off the artwork below, and the scene is scaled up until
     a bay is comfortably taller than a cover. */
  width: clamp(132px, 13vw, 184px);
  min-width: 0;
}
.book-grid--shelf .book-cover {
  width: 100%;
  min-height: 0;
  aspect-ratio: .68;
  padding: 13px 10px 10px 15px;
  border-color: rgba(28, 12, 5, .52);
  box-shadow: 0 9px 12px rgba(35, 15, 6, .4), 4px 4px 0 rgba(83, 42, 15, .72), 5px 5px 0 rgba(51, 25, 10, .45);
}
.book-grid--shelf .book-cover__spine { width: 9px; }
.book-grid--shelf .book-cover__edition { font-size: 8px; }
.book-grid--shelf .book-cover__title {
  margin-top: 9px;
  font-size: clamp(12px, 1.25vw, 18px);
  line-height: 1.13;
  -webkit-line-clamp: 6;
  /* The base cover breaks mid-word (`anywhere`) because a wide card can
     afford it. On a shelf cover the line is far shorter, and that rule
     produced "Controlle / d AI" — break on word boundaries instead. */
  overflow-wrap: break-word;
}
.book-grid--shelf .book-cover__rule { width: 24px; height: 1px; margin: 8px 0 7px; }
.book-grid--shelf .book-cover__department { font-size: 8px; }
.book-grid--shelf .book-cover__brand { font-size: 8px; }
.book-grid--shelf .book-cover__open { right: 7px; bottom: 7px; padding: 5px 7px; font-size: 9px; }

/* Metadata becomes a compact, readable tooltip. It is still in the DOM for
   screen readers and keyboard users, but never consumes shelf space. */
.book-grid--shelf .book-card__details {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 12px);
  z-index: 20;
  display: flex;
  width: min(260px, 34vw);
  min-width: 190px;
  margin: 0;
  padding: 12px 14px;
  border: 1px solid rgba(255, 230, 189, .4);
  border-radius: 8px;
  background: rgba(42, 24, 13, .96);
  box-shadow: 0 12px 24px rgba(33, 14, 4, .32);
  color: #fff7e8;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 7px);
  transition: opacity .18s ease, transform .2s ease, visibility .18s ease;
  visibility: hidden;
}
.book-grid--shelf .book-card:hover .book-card__details,
.book-grid--shelf .book-card:focus-within .book-card__details {
  opacity: 1;
  transform: translate(-50%, 0);
  visibility: visible;
}
.book-grid--shelf .book-card__details::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -6px;
  width: 11px;
  height: 11px;
  border-right: 1px solid rgba(255, 230, 189, .4);
  border-bottom: 1px solid rgba(255, 230, 189, .4);
  background: rgba(42, 24, 13, .96);
  transform: translateX(-50%) rotate(45deg);
}
.book-grid--shelf .book-card__details .book-card__title { color: #fff7e8; font-size: 13px; }
.book-grid--shelf .book-card__details .book-card__owner { color: #f2c98e; }
.book-grid--shelf .book-card__details .book-card__file { color: #fff; }
.book-grid--shelf .book-card__details .book-card__dates { color: rgba(255, 247, 232, .72); }

.bookshelf-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin-top: 18px;
}
.bookshelf-pagination .btn { display: inline-flex; align-items: center; gap: 7px; }
.bookshelf-pagination .btn .icon { width: 15px; height: 15px; }
.bookshelf-pagination__status { color: var(--ink-2); font-size: 13px; }
.bookshelf-pagination__status strong { color: var(--navy-900); }

@media (max-width: 760px) {
  /* The four-bay artwork is useful on desktop, but its five across layout
     turns every cover into a postage stamp on a phone. Use a compact single
     column here and let each item keep its book-cover identity. */
  .shelf-scene {
    min-height: 0;
    padding: 8px;
    overflow: visible;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }
  .book-grid.book-grid--shelf {
    position: relative;
    inset: auto;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    gap: 9px;
    padding: 0;
  }
  .book-grid--shelf .book-card {
    display: grid;
    grid-template-columns: clamp(58px, min(22vw, 11svh), 92px) minmax(0, 1fr);
    align-items: center;
    gap: 14px;
    width: 100%;
    min-height: 0;
    padding: 9px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--surface);
    box-shadow: var(--shadow-1);
  }
  .book-grid--shelf .book-cover {
    width: 100%;
    min-height: 0;
    padding: 8px 6px 7px 10px;
    aspect-ratio: .68;
  }
  .book-grid--shelf .book-cover__spine { width: 6px; }
  .book-grid--shelf .book-cover__edition,
  .book-grid--shelf .book-cover__department,
  .book-grid--shelf .book-cover__brand { font-size: 7px; }
  .book-grid--shelf .book-cover__title {
    margin-top: 6px;
    font-size: clamp(9px, 1.45vh, 12px);
    -webkit-line-clamp: 5;
  }
  .book-grid--shelf .book-cover__rule { width: 16px; margin: 5px 0 4px; }
  .book-grid--shelf .book-cover__open { right: 4px; bottom: 4px; padding: 3px 4px; font-size: 7px; }
  .book-grid--shelf .book-card__details {
    position: static;
    display: flex;
    width: auto;
    min-width: 0;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
    color: var(--ink-2);
    opacity: 1;
    pointer-events: auto;
    transform: none;
    visibility: visible;
  }
  .book-grid--shelf .book-card__details::after { display: none; }
  .book-grid--shelf .book-card__details .book-card__title { color: var(--navy-900); font-size: 13px; }
  .book-grid--shelf .book-card__details .book-card__owner { color: var(--ink-2); }
  .book-grid--shelf .book-card__details .book-card__file { color: var(--navy-700); }
  .book-grid--shelf .book-card__details .book-card__dates { color: var(--ink-3); }
  .bookshelf-pagination { gap: 10px; }
  .bookshelf-pagination .btn { padding-inline: 9px; }
}

/* The cue that a cover opens rather than links. It rises out of the board on
   hover, so a shelf at rest stays a shelf. */
.book-cover__open {
  position: absolute; right: 14px; bottom: 14px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .93); color: var(--navy-900);
  font-size: 11px; font-weight: 750; letter-spacing: .02em;
  opacity: 0; transform: translateY(8px);
  transition: opacity .2s ease, transform .24s cubic-bezier(.2, .9, .24, 1);
}
.book-cover__open .icon { width: 14px; height: 14px; }
.book-card:hover .book-cover__open,
.book-card:focus-visible .book-cover__open { opacity: 1; transform: none; }

/* Nothing uploaded yet: still on the shelf, but it does not pretend to open. */
.book-card--pending { cursor: default; }
.book-card--pending .book-cover { filter: saturate(.45); opacity: .72; }
.book-card--pending:hover .book-cover { transform: none; }
.book-card--pending .book-card__file { color: var(--ink-3); font-weight: 600; }

@media (max-width: 1200px) {
  .bookshelf-tools { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .bookshelf-field--search { grid-column: span 2; }
}
@media (max-width: 900px) {
  .bookshelf-tools { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  .bookshelf-tools { grid-template-columns: minmax(0, 1fr); }
  .bookshelf-field--search { grid-column: auto; }
  .bookshelf-clear { width: 100%; }
  .book-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 16px; }
  .book-cover { min-height: 0; }
  .bookshelf-status { align-items: flex-start; flex-direction: column; gap: 3px; }
}
@media (prefers-reduced-motion: reduce) {
  .book-cover { transition: none; }
  .book-card:hover .book-cover { transform: none; }
}

/* ==========================================================================
   The book reader — an uploaded PDF, read as a book
   --------------------------------------------------------------------------
   How We Work is a shelf of files, so opening one is a physical event rather
   than a navigation: the cover leaves the shelf, the room goes dark behind it,
   and the book opens where the reader is already looking.

   The whole thing is one 3D scene. .bookreader__stage owns the perspective,
   .bookreader__book is the preserve-3d space, and everything inside is placed
   on the Z axis rather than with z-index — inside preserve-3d, depth is the
   only stacking order that can be trusted:

       -8px  the case (the boards, and the shadow the book casts)
        0px  the two leaves lying still
       +4px  the leaf being turned
       +6px  the seam
       +8px  the front cover, until it has finished swinging away

   The 0.92 closed-book scale is shared with assets/js/book.js and has to stay
   in step with the flight geometry there.
   ========================================================================== */

.bookreader {
  --paper: #fbf5f0;
  --case-a: #7a1219;
  --case-b: #2c060a;
  --case-rgb: 44, 6, 10;
  --gutter-left: linear-gradient(to right, rgba(var(--case-rgb), .26), rgba(var(--case-rgb), .05) 7%, transparent 19%);
  --gutter-right: linear-gradient(to left, rgba(var(--case-rgb), .26), rgba(var(--case-rgb), .05) 7%, transparent 19%);

  position: fixed; inset: 0; z-index: 260;
  overscroll-behavior: contain;
}
.bookreader[hidden] { display: none; }

/* The page under an open book holds still. When the shelf is inside the map's
   modal it is the modal body that scrolls, so that one is held too. */
body.is-book-open { overflow: hidden; }
body.is-book-open .modal__body { overflow: hidden; }

.bookreader__scrim {
  position: absolute; inset: 0;
  background:
    radial-gradient(circle at 50% 40%, rgba(var(--case-rgb), .76), rgba(8, 8, 12, .96) 70%);
  opacity: 0;
  transition: opacity .6s ease;
}
.bookreader.is-lit .bookreader__scrim { opacity: 1; }
/* The room stays dark until the book is shut and on its way back to the
   shelf — a scrim that lifts first leaves the book floating over daylight. */
.bookreader.is-closing .bookreader__scrim { opacity: 1; }
.bookreader.is-departing .bookreader__scrim { opacity: 0; transition: opacity .32s ease .05s; }

/* --- the bar above the book -----------------------------------------------
   Floats over the stage instead of claiming its own row, so the book behind
   it can use that height too. The gradient tail is what keeps the title and
   buttons legible when a light page is sitting right underneath them. */
.bookreader__chrome {
  position: absolute; top: 0; left: 0; right: 0; z-index: 3;
  display: flex; align-items: flex-end; justify-content: space-between; gap: 18px;
  min-width: 0;
  padding: 14px clamp(12px, 4vw, 34px) 33px;
  background: linear-gradient(to bottom, rgba(10, 4, 6, .68), rgba(10, 4, 6, .32) 58%, transparent);
  pointer-events: none;
  opacity: 0; transform: translateY(-10px);
  transition: opacity .42s ease .16s, transform .52s cubic-bezier(.2, .9, .24, 1) .16s;
}
.bookreader__chrome > * { pointer-events: auto; }
.bookreader.is-lit .bookreader__chrome { opacity: 1; transform: none; }
.bookreader.is-closing .bookreader__chrome { opacity: 0; transition-delay: 0s; transition-duration: .24s; }

/* A click on the page or the margin around the book — anywhere that isn't a
   control — tucks the chrome and hud away so the page reads clean. The extra
   classes just win the specificity tie against .is-lit/.is-ready above. */
.bookreader.is-lit.is-chrome-hidden .bookreader__chrome { opacity: 0; pointer-events: none; }
/* The .16s opening delay above is for the book's own reveal; once it has
   settled, a toggle click should answer immediately in both directions. */
.bookreader.is-ready .bookreader__chrome { transition-duration: .2s; transition-delay: 0s; }

.bookreader__ident { min-width: 0; }
.bookreader__eyebrow {
  display: flex; flex-wrap: wrap; gap: 4px 9px; margin: 0;
  color: rgba(255, 236, 236, .62);
  font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
}
.bookreader__eyebrow span + span::before { content: "\00b7"; margin-right: 9px; }
.bookreader__title {
  margin: 5px 0 0;
  overflow: hidden;
  color: #fff; font-family: var(--serif); font-size: clamp(16px, 2.1vw, 22px);
  font-weight: 600; letter-spacing: -.01em; white-space: nowrap; text-overflow: ellipsis;
}

.bookreader__tools { display: flex; align-items: center; gap: 9px; flex: none; }
/* A <button>, not a link, since it opens the plain viewer rather than
   navigating to the file — the route refuses that now. The first three
   declarations are the button reset that buys back what an <a> gave free. */
.bookreader__file {
  background: none; cursor: pointer; font-family: inherit;
  display: inline-flex; align-items: center; gap: 7px;
  height: 40px; padding: 0 13px;
  border: 1px solid rgba(255, 226, 226, .26); border-radius: 999px;
  color: rgba(255, 240, 240, .88); font-size: 13px; font-weight: 620;
  transition: background-color .16s ease, border-color .16s ease, color .16s ease;
}
.bookreader__file:hover {
  background: rgba(255, 255, 255, .1); border-color: rgba(255, 226, 226, .5);
  color: #fff; text-decoration: none;
}
.bookreader__file .icon { width: 17px; height: 17px; }

/* A button that has to read as a link because it sits mid-sentence. Used by
   the book reader's failure notice, where the action opens the plain viewer
   rather than going anywhere. */
.linklike {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: inherit; text-decoration: underline; text-underline-offset: 2px;
}
.linklike:hover { text-decoration: none; }

.bookreader__close {
  display: grid; place-items: center;
  width: 44px; height: 44px; padding: 0;
  border: 1px solid rgba(255, 226, 226, .28); border-radius: 50%;
  background: rgba(255, 255, 255, .07); color: #fff; cursor: pointer;
  transition: background-color .16s ease, transform .16s ease, border-color .16s ease;
}
.bookreader__close:hover { background: var(--navy-600); border-color: var(--navy-600); transform: scale(1.06); }
.bookreader__close:focus-visible { outline: 3px solid rgba(255, 255, 255, .7); outline-offset: 2px; }
.bookreader__close .icon { width: 20px; height: 20px; }

/* --- the scene ------------------------------------------------------------
   Fills the whole reader now that the chrome and hud float on top of it
   rather than sitting in rows beside it. The padding here is the only
   remaining margin book.js's layout() budgets around, so the book reads as
   large as the window allows instead of being squeezed by two bars. */
.bookreader__stage {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  min-height: 0;
  padding: 9px clamp(9px, 3vw, 24px);
  contain: layout paint;
  /* Far enough back that a lifted page grows a little rather than looming.
     At 2800px the free edge of a turning leaf magnified past the boards. */
  perspective: 4600px; perspective-origin: 50% 48%;
}

/* The opening is one animation with four moving parts — the board's swing, the
   book sliding off its closed position, the boards widening, and the left leaf
   arriving underneath. book.js derives every compositor track from one shared
   progress curve, so none of them can drift out of step. Nothing here adds a
   competing transition; that is deliberate. */
.bookreader__book {
  position: relative;
  transform-style: preserve-3d;
  transform: scale(1) translateX(0);
  opacity: 0;
  cursor: grab;
  touch-action: none;
  -webkit-user-select: none; user-select: none;
}
.bookreader.is-ready .bookreader__book { opacity: 1; }
.bookreader__book.is-dragging { cursor: grabbing; }
.bookreader.is-handoff .bookreader__book {
  opacity: 0;
}

/* The boards keep two fixed halves. While shut, only the right one exists in
   view; the left one fades in behind the cover as it crosses the spine. The
   previous scaleX animation visibly stretched a red panel across the pages. */
.bookcase {
  position: absolute; top: -12px; right: -15px; bottom: -14px; left: -15px;
  transform: translateZ(-8px);
}
.bookcase__board {
  position: absolute; top: 0; bottom: 0; width: 50%;
  background:
    radial-gradient(circle at 76% 12%, rgba(255, 255, 255, .12), transparent 34%),
    linear-gradient(146deg, var(--case-a), var(--case-b) 72%);
  box-shadow: 0 40px 70px rgba(0, 0, 0, .55), 0 8px 22px rgba(0, 0, 0, .38);
}
.bookcase__board--left {
  left: 0; border-radius: 5px 0 0 5px;
  will-change: opacity;
}
.bookcase__board--right { right: 0; border-radius: 0 9px 9px 0; }

/* --- a leaf lying still --------------------------------------------------- */
.bookleaf {
  position: absolute; top: 0; width: 50%; height: 100%;
  overflow: hidden;
  background: var(--paper);
  backface-visibility: hidden;
}
.bookleaf--left {
  left: 0; border-radius: 3px 0 0 3px;
  box-shadow: -1px 0 0 #f3ebe9, -3px 0 0 rgba(var(--case-rgb), .12), -5px 0 0 rgba(var(--case-rgb), .18), -7px 1px 0 rgba(var(--case-rgb), .25);
}
.bookleaf--right {
  left: 50%; border-radius: 0 3px 3px 0;
  box-shadow: 1px 0 0 #f3ebe9, 3px 0 0 rgba(var(--case-rgb), .12), 5px 0 0 rgba(var(--case-rgb), .18), 7px 1px 0 rgba(var(--case-rgb), .25);
}

/* Keeping page canvases in the normal blend pipeline lets the browser retain
   them as GPU textures while a leaf turns. A full-page multiply blend forced
   the large canvas layers to be recomposited on every animation frame. */
.bookleaf canvas,
.bookflip__face canvas,
.bookcover canvas {
  display: block; width: 100%; height: 100%;
  /* PDF canvases keep the dimensions pdf.js rendered from each page's own
     viewport. Fit that content inside the shared leaf without stretching it
     when a document mixes page sizes or orientations. */
  object-fit: contain;
}
.bookleaf.is-blank canvas { display: none; }
/* A page pdf.js has not finished rendering shows plain paper and fades in
   when it arrives (book.js paint()), so a turn never waits on a slow page. */
.bookleaf canvas,
.bookflip__face canvas { transition: opacity .18s ease; }
.bookleaf.is-pending canvas,
.bookflip__face.is-pending canvas { opacity: 0; }
/* A page still on its way shows a small spinner on the paper, so it reads as
   loading rather than as a blank page. It only appears after a short delay:
   a page that arrives quickly never flashes one. */
.bookleaf.is-pending::after,
.bookflip__face.is-pending::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 22px; height: 22px; margin: -11px 0 0 -11px; box-sizing: border-box;
  border: 2px solid rgba(var(--case-rgb), .14); border-top-color: rgba(var(--case-rgb), .55);
  border-radius: 50%; opacity: 0; pointer-events: none;
  animation: bookleaf-loading-in .2s ease .3s forwards, bookreader-spin .8s linear infinite;
}
@keyframes bookleaf-loading-in { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .bookleaf canvas,
  .bookflip__face canvas { transition: none; }
  .bookleaf.is-pending::after,
  .bookflip__face.is-pending::after { animation: bookleaf-loading-in .2s ease .3s forwards; }
}

.bookleaf__gutter { position: absolute; inset: 0; pointer-events: none; }
.bookleaf--left .bookleaf__gutter { background: var(--gutter-right); }
.bookleaf--right .bookleaf__gutter { background: var(--gutter-left); }

/* The turning leaf throws a shadow across whatever it is passing over.
   Strongest at a right angle, gone at either end of the turn. */
.bookleaf__cast {
  position: absolute; inset: 0; pointer-events: none;
  opacity: 0;
}
.bookleaf--left .bookleaf__cast {
  background: linear-gradient(to left, rgba(var(--case-rgb), .55), rgba(var(--case-rgb), .12) 42%, transparent 72%);
}
.bookleaf--right .bookleaf__cast {
  background: linear-gradient(to right, rgba(var(--case-rgb), .5), rgba(var(--case-rgb), .1) 42%, transparent 72%);
}

/* --- the leaf being turned ------------------------------------------------ */
.bookflip {
  position: absolute; top: 0; width: 50%; height: 100%;
  transform-style: preserve-3d;
}
.bookflip[hidden] { display: none; }
.bookflip.is-forward { left: 50%; transform-origin: left center; }
.bookflip.is-backward { left: 0; transform-origin: right center; }

.bookflip__face {
  position: absolute; inset: 0; overflow: hidden;
  background: var(--paper);
  backface-visibility: hidden;
  box-shadow: 0 8px 22px rgba(30, 4, 7, .22);
}
.bookflip__face--front { transform: translateZ(4px); }
.bookflip__face--back { transform: translateZ(4px) rotateY(180deg); }

.bookflip.is-forward .bookflip__face--front { border-radius: 0 3px 3px 0; }
.bookflip.is-forward .bookflip__face--back { border-radius: 3px 0 0 3px; }
.bookflip.is-backward .bookflip__face--front { border-radius: 3px 0 0 3px; }
.bookflip.is-backward .bookflip__face--back { border-radius: 0 3px 3px 0; }

.bookflip.is-forward .bookflip__face--front .bookleaf__gutter,
.bookflip.is-backward .bookflip__face--back .bookleaf__gutter { background: var(--gutter-left); }
.bookflip.is-forward .bookflip__face--back .bookleaf__gutter,
.bookflip.is-backward .bookflip__face--front .bookleaf__gutter { background: var(--gutter-right); }

/* The face turning away loses its light; the face arriving picks it up. */
.bookflip__shade { position: absolute; inset: 0; pointer-events: none; }
.bookreader.is-turning .bookflip { will-change: transform; }
.bookflip__face--front .bookflip__shade {
  background: linear-gradient(to left, rgba(var(--case-rgb), .42), transparent 62%);
  opacity: 0;
}
.bookflip__face--back .bookflip__shade {
  background: linear-gradient(to right, rgba(var(--case-rgb), .5), transparent 66%);
  opacity: 1;
}
.bookflip.is-backward .bookflip__face--front .bookflip__shade {
  background: linear-gradient(to right, rgba(var(--case-rgb), .42), transparent 62%);
}
.bookflip.is-backward .bookflip__face--back .bookflip__shade {
  background: linear-gradient(to left, rgba(var(--case-rgb), .5), transparent 66%);
}

/* --- the cover ------------------------------------------------------------ */
.bookcover {
  position: absolute; top: 0; left: 50%; width: 50%; height: 100%;
  transform: translateZ(8px) rotateY(0deg);
  transform-origin: left center;
  transform-style: preserve-3d;
  pointer-events: none;
}
.bookcover[hidden] { display: none; }

.bookcover__face {
  position: absolute; inset: 0; overflow: hidden;
  background: var(--paper);
  backface-visibility: hidden;
}
.bookcover__face--front { border-radius: 0 4px 4px 0; }
.bookcover__face--back { border-radius: 4px 0 0 4px; transform: rotateY(180deg); }
.bookcover__face--back .bookleaf__gutter { background: var(--gutter-right); }

/* The clicked cover itself, cloned in. It has to forget the shelf's tile
   proportions and simply fill the board. */
.bookcover__face--front .book-cover {
  width: 100%; height: 100%;
  min-height: 0; aspect-ratio: auto;
  border: 0; border-radius: 0;
  box-shadow: none;
  transform: none;
}
.bookcover__face--front .book-cover__open { display: none; }

/* The light that falls across a raised board, and dies as it lies down. */
.bookcover__shade {
  position: absolute; inset: 0;
  transform: translateZ(1px);
  background: linear-gradient(105deg, rgba(255, 255, 255, .1) 12%, transparent 42%, rgba(28, 4, 7, .34));
  opacity: 0; pointer-events: none;
}

.bookreader__spine {
  position: absolute; top: -3px; bottom: -3px; left: calc(50% - 2px); width: 4px;
  transform: translateZ(6px);
  background: linear-gradient(90deg, rgba(var(--case-rgb), .48), rgba(var(--case-rgb), .12), rgba(var(--case-rgb), .48));
  opacity: 0; pointer-events: none;
}

/* --- the cover in flight, shelf to stage and back ------------------------- */
.bookflight {
  position: fixed; z-index: 4;
  min-height: 0; aspect-ratio: auto;
  transform-origin: center center;
  pointer-events: none;
  backface-visibility: hidden;
  will-change: transform, opacity;
  transition: none;
}

/* --- states --------------------------------------------------------------- */
.bookreader__failed {
  position: absolute; left: 50%; top: 50%;
  display: flex; align-items: center; gap: 10px;
  margin: 0; padding: 12px 16px;
  transform: translate(-50%, -50%);
  border-radius: 999px;
  background: rgba(20, 4, 6, .82);
  color: rgba(255, 240, 240, .92); font-size: 13.5px;
}
.bookreader__failed[hidden] { display: none; }
.bookreader__failed { border: 1px solid rgba(255, 160, 160, .4); }
.bookreader__failed a { color: #ffd9d9; text-decoration: underline; }

/* The reader appears immediately, while PDF.js fetches and rasterizes the
   first spread. A clear status is better than leaving the cover apparently
   frozen on a slower connection or a large document. */
/* Fixed, not absolute, and above .bookflight (z-index 4): the wait this
   reports happens *while* the cover is still flying from the shelf to the
   stage, and at z-index 2 inside the stage the flying clone sat on top of it.
   A reader watching a slow file open saw a frozen cover and no explanation. */
.bookreader__loading {
  position: fixed; left: 50%; top: 50%; z-index: 6;
  display: inline-flex; align-items: center; gap: 10px;
  margin: 0; padding: 12px 16px;
  transform: translate(-50%, -50%);
  border: 1px solid rgba(255, 240, 240, .22); border-radius: 999px;
  background: rgba(20, 4, 6, .82);
  color: rgba(255, 240, 240, .92); font-size: 13.5px; font-weight: 650;
}
.bookreader__loading[hidden] { display: none; }
.bookreader__spinner {
  width: 15px; height: 15px; box-sizing: border-box; flex: none;
  border: 2px solid rgba(255, 240, 240, .28); border-top-color: #fff;
  border-radius: 50%; animation: bookreader-spin .75s linear infinite;
}
@keyframes bookreader-spin { to { transform: rotate(360deg); } }

/* --- the strip under the book ----------------------------------------------
   Floats over the stage's bottom edge for the same reason the chrome does. */
.bookreader__hud {
  position: absolute; bottom: 0; left: 0; right: 0; z-index: 3;
  display: flex; align-items: center; justify-content: center; gap: 14px;
  padding: 24px clamp(12px, 4vw, 34px) 14px;
  background: linear-gradient(to top, rgba(10, 4, 6, .66), rgba(10, 4, 6, .28) 58%, transparent);
  pointer-events: none;
  opacity: 0;
  transition: opacity .4s ease .34s;
}

/* Layer promotion belongs to the active reader only. Keeping these hints on
   its hidden, canvas-heavy subtree makes some browsers retain GPU surfaces
   after a book closes, slowing the section modal underneath it. */
.bookreader:not([hidden]) .bookreader__scrim,
.bookreader:not([hidden]) .bookreader__hud { will-change: opacity; }
.bookreader:not([hidden]) .bookreader__chrome,
.bookreader:not([hidden]) .bookreader__book { will-change: transform, opacity; }
.bookreader:not([hidden]) .bookcover { will-change: transform; }
.bookreader__hud > * { pointer-events: auto; }
.bookreader.is-ready .bookreader__hud { opacity: 1; }
.bookreader.is-closing .bookreader__hud { opacity: 0; transition-delay: 0s; transition-duration: .2s; }
.bookreader.is-ready.is-chrome-hidden .bookreader__hud { opacity: 0; pointer-events: none; }
.bookreader.is-ready .bookreader__hud { transition-duration: .2s; transition-delay: 0s; }

.bookreader__page {
  display: grid; place-items: center;
  width: 42px; height: 42px; padding: 0;
  border: 1px solid rgba(255, 226, 226, .26); border-radius: 50%;
  background: rgba(255, 255, 255, .07); color: #fff; cursor: pointer;
  transition: background-color .16s ease, transform .16s ease, opacity .2s ease;
}
.bookreader__page:hover { background: var(--navy-600); transform: scale(1.06); }
.bookreader__page:focus-visible { outline: 3px solid rgba(255, 255, 255, .7); outline-offset: 2px; }
.bookreader__page .icon { width: 19px; height: 19px; }
.bookreader.is-first [data-book-prev],
.bookreader.is-last [data-book-next] { opacity: .28; pointer-events: none; }

.bookreader__folio {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 190px; margin: 0; text-align: center;
}
.bookreader__folio strong {
  color: #fff; font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.bookreader__folio span {
  color: rgba(255, 236, 236, .55); font-size: 11.5px;
  transition: opacity .3s ease;
}
.bookreader.has-turned .bookreader__folio span { opacity: 0; }

/* A book at either end of itself leans, and comes back. */
@keyframes book-nudge-forward {
  40% { transform: scale(1) translateX(-9px) rotateY(1.6deg); }
}
@keyframes book-nudge-back {
  40% { transform: scale(1) translateX(9px) rotateY(-1.6deg); }
}
.bookreader__book.is-nudged-forward { animation: book-nudge-forward .42s ease; }
.bookreader__book.is-nudged-back { animation: book-nudge-back .42s ease; }

@media (max-width: 860px) {
  .bookreader__stage { padding: 8px; }
  .bookreader__chrome { padding: 12px 12px 36px; }
  .bookreader__hud { padding: 26px 12px 12px; }
  .bookreader__file span { display: none; }
  .bookreader__file { padding: 0 12px; }
  .bookreader__folio { min-width: 0; }
  .bookreader__folio span { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .bookreader__scrim,
  .bookreader__chrome,
  .bookreader__hud { transition: none; }
  .bookreader__book.is-nudged-forward,
  .bookreader__book.is-nudged-back { animation: none; }
}

/* ==========================================================================
   The document viewer — how a template opens
   --------------------------------------------------------------------------
   A plain frame, not the book reader above: a template is a working file
   someone is about to reuse, and it opens the way opening a PDF anywhere
   does — the browser's own viewer, filling the body, under a thin header
   naming what it is and offering the original file to download. z-index
   matches .libdialog/.libnotice (400): all three can only ever be open one
   at a time, but share the tier that sits above the section modal (100),
   since either page can arrive fetched into it.
   ========================================================================== */

.docviewer {
  position: fixed; inset: 0; z-index: 400;
  display: flex; align-items: center; justify-content: center;
  padding: min(4vh, 27px) min(4vw, 27px);
  opacity: 0; visibility: hidden;
  transition: opacity .2s ease, visibility 0s linear .2s;
}
.docviewer[hidden] { display: none; }
.docviewer.is-open {
  opacity: 1; visibility: visible;
  transition: opacity .2s ease;
}

.docviewer__scrim { position: absolute; inset: 0; background: rgba(20, 10, 11, .74); }

.docviewer__panel {
  position: relative;
  display: flex; flex-direction: column;
  width: min(1100px, 100%); height: 100%;
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: 0 30px 80px rgba(20, 10, 11, .4);
  overflow: hidden;
  transform: translateY(14px) scale(.98);
  transition: transform .22s cubic-bezier(.19, 1, .22, 1);
}
.docviewer.is-open .docviewer__panel { transform: none; }

.docviewer__head {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 15px;
  border-bottom: 1px solid var(--line-2);
}
.docviewer__ident { min-width: 0; }
.docviewer__eyebrow {
  margin: 0 0 2px; display: flex; gap: 7px; align-items: center;
  font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-3);
}
.docviewer__title {
  margin: 0; font-size: 15.5px; color: var(--navy-900);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.docviewer__tools { margin-left: auto; display: flex; align-items: center; gap: 7px; flex: none; }
.docviewer__file {
  display: inline-flex; align-items: center; gap: 7px;
  height: 36px; padding: 0 12px; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--surface); color: var(--navy-700);
  font-size: 13.5px; font-weight: 600; text-decoration: none;
}
.docviewer__file:hover { background: var(--navy-700); border-color: var(--navy-700); color: #fff; text-decoration: none; }
.docviewer__file .icon { width: 16px; height: 16px; }
/* The `display` above beats the user-agent's `[hidden] { display: none }`,
   which is how a Download control that app.js had correctly marked hidden went
   on being painted over a How We Work module. An element that is only
   sometimes allowed to exist needs its own hidden rule, not just the
   attribute. */
.docviewer__file[hidden] { display: none; }
.docviewer__close {
  display: grid; place-items: center; width: 36px; height: 36px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink-2); cursor: pointer;
}
.docviewer__close:hover { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }
.docviewer__close .icon { width: 17px; height: 17px; }

/* The grey backdrop is the same tone a native PDF viewer's own loading state
   uses, so the wait before pdf.js has anything painted reads as "the viewer
   is working" rather than "something is broken". */
.docviewer__body { flex: 1; min-height: 0; background: #757575; }

/* --------------------------------------------------------------------------
   The PDF pane — pages pdf.js (assets/vendor/pdfjs) draws onto canvases,
   scrolled continuously rather than paginated. Not an iframe: see the
   comment above DocViewer's pdf mode in assets/js/app.js for why owning the
   render ourselves, rather than handing a PDF to the browser's own plugin,
   is what keeps this viewer's Download button the only one in it.
   -------------------------------------------------------------------------- */

.docpdf {
  position: relative;
  height: 100%; overflow-y: auto; overflow-x: hidden;
}
.docpdf[hidden] { display: none; }

.docpdf__pages {
  display: flex; flex-direction: column; align-items: center; gap: 15px;
  padding: 19px 14px 30px;
  min-height: 100%;
}
.docpdf__page {
  width: 100%; max-width: 900px;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
  line-height: 0;                        /* no gap under the canvas */
}
.docpdf__page canvas { display: block; width: 100%; height: auto; }

.docpdf__status {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  color: #fff; font-size: 14px;
  background: #757575;
  text-align: center; padding: 0 19px;
}
.docpdf__status[hidden] { display: none; }
.docpdf__status .spinner { width: 20px; height: 20px; border-width: 2px; border-top-color: #fff; }
.docpdf__status .spinner[hidden] { display: none; }

/* --------------------------------------------------------------------------
   The spreadsheet grid — xlsx/xls/ods/csv, read as an actual grid rather
   than a paginated PDF export. Parsed off the main thread by
   assets/js/spreadsheet-worker.js and drawn here as a windowed grid — only
   the rows scrolled into view are ever real DOM nodes — ported from
   MyBackUp's spreadsheet viewer (assets/css/explorer.css .sheet-*) with this
   app's own color tokens in place of its --sheet-* ones.
   -------------------------------------------------------------------------- */

.docsheet {
  display: flex; flex-direction: column;
  height: 100%; background: var(--surface);
}
.docsheet[hidden] { display: none; }

.docsheet__formula {
  flex: 0 0 38px; height: 38px; display: flex; align-items: center;
  border-bottom: 1px solid var(--line); background: var(--surface); font-size: 12px;
}
.docsheet__formula[hidden] { display: none; }
.docsheet__namebox {
  width: 80px; align-self: stretch; display: flex; align-items: center; justify-content: center;
  border-right: 1px solid var(--line); color: var(--navy-900);
  font-weight: 700; font-variant-numeric: tabular-nums;
}
.docsheet__fx {
  width: 42px; align-self: stretch; display: flex; align-items: center; justify-content: center;
  color: var(--ink-3); border-right: 1px solid var(--line); font-weight: 700; font-style: italic;
}
.docsheet__formula-value {
  flex: 1; min-width: 0; padding: 0 10px; overflow: hidden;
  white-space: nowrap; text-overflow: ellipsis; color: var(--ink);
}

.docsheet__stage { flex: 1; min-height: 0; position: relative; overflow: hidden; }
.docsheet__status {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 7px; color: var(--ink-2); font-size: 14px; text-align: center; padding: 19px;
  background: var(--surface);
}
.docsheet__status[hidden] { display: none; }

.docsheet__grid {
  position: absolute; inset: 0; overflow: auto; outline: none;
  background: var(--surface); color: var(--ink); overscroll-behavior: contain;
}
.docsheet__grid:focus-visible { box-shadow: inset 0 0 0 2px var(--navy-600); }
.docsheet__canvas { position: relative; min-width: 100%; }

.docsheet__col-heads {
  position: sticky; top: 0; z-index: 5; height: 30px;
  display: grid; background: var(--navy-050); border-bottom: 1px solid var(--line);
}
.docsheet__col-head {
  height: 30px; display: flex; align-items: center; justify-content: center;
  border-right: 1px solid var(--line-2); color: var(--ink-2);
  font-size: 11px; font-weight: 700; user-select: none;
}
.docsheet__corner { position: sticky; left: 0; z-index: 7; background: var(--navy-050); }

.docsheet__rows { position: absolute; top: 30px; left: 0; will-change: transform; }
.docsheet__row { height: 28px; display: grid; }
.docsheet__row-head {
  position: sticky; left: 0; z-index: 3;
  height: 28px; display: flex; align-items: center; justify-content: flex-end;
  padding-right: 7px; background: var(--navy-050); color: var(--ink-2);
  border-right: 1px solid var(--line); border-bottom: 1px solid var(--line-2);
  font-size: 11px; font-variant-numeric: tabular-nums; user-select: none;
}
.docsheet__cell {
  position: relative; height: 28px; padding: 5px 7px;
  overflow: hidden; white-space: nowrap; text-overflow: clip;
  border-right: 1px solid var(--line-2); border-bottom: 1px solid var(--line-2);
  font-size: 12px; line-height: 17px; cursor: cell; background: var(--surface);
}
.docsheet__cell.is-selected {
  overflow: visible; z-index: 2;
  box-shadow: inset 0 0 0 2px var(--navy-600); background: var(--navy-050);
}

.docsheet__tabs {
  display: flex; min-width: 0; overflow-x: auto; flex: 0 0 39px;
  align-items: stretch; padding-left: 7px;
  border-top: 1px solid var(--line); background: var(--navy-050);
}
.docsheet__tabs[hidden] { display: none; }
.docsheet__tab {
  position: relative; min-width: 72px; max-width: 180px; padding: 0 12px;
  border: 0; border-right: 1px solid var(--line); background: transparent; color: var(--ink-2);
  font: inherit; font-size: 12px; overflow: hidden; white-space: nowrap;
  text-overflow: ellipsis; cursor: pointer;
}
.docsheet__tab:hover { background: rgba(255, 255, 255, .6); }
.docsheet__tab.is-active { background: var(--surface); color: var(--navy-900); font-weight: 650; }
.docsheet__tab.is-active::after {
  content: ""; position: absolute; left: 10px; right: 10px; bottom: 0; height: 3px;
  border-radius: 3px 3px 0 0; background: var(--navy-600);
}
.docsheet__tab:focus-visible { outline: 2px solid var(--navy-600); outline-offset: -3px; }

body.is-doc-open { overflow: hidden; }

@media (max-width: 760px) {
  .docviewer { padding: 0; }
  .docviewer__panel { border-radius: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .docviewer, .docviewer__panel { transition: none; }
}

/* ==========================================================================
   Learn — Editorial Learning Studio landing
   --------------------------------------------------------------------------
   A curated destination rather than a departmental directory. The page head
   answers "what should I do right now" with a search, and two views below it
   split the catalogue into Explore and Required. Every course is a card whose
   cover comes from the same illustrated system. */

/* The header search sits in the pagehead__actions slot — a quiet, usable
   input on the page background, twin to the one inside the catalogue tools. */
/* This sits in .pagehead__actions beside the Create Course / Delete buttons,
   so it takes the same control height they do — it was 46px against their
   32px, which read as two rows of controls pretending to be one. */
.learn-search { position: relative; min-width: 260px; }
.learn-search input {
  width: 100%; height: var(--ui-control-h); padding: 0 12px 0 30px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink); font: inherit; font-size: var(--ui-text-md);
  box-shadow: var(--shadow-1);
  outline: none; transition: border-color .15s ease, box-shadow .15s ease;
}
.learn-search input::placeholder { color: var(--ink-3); }
.learn-search input:focus { border-color: var(--navy-600); box-shadow: 0 0 0 3px var(--navy-100); }
.learn-search .icon {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: var(--ui-icon); height: var(--ui-icon); color: var(--ink-3);
}

/* The rails — equal widths at every size, no horizontal scrolling. */
.learn-nav { margin-top: 22px; }
.learn-nav__list {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 9px;
  border-bottom: 1px solid var(--line);
}
.learn-tab {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 41px; padding: 9px 12px;
  border: 0; border-bottom: 3px solid transparent; border-radius: var(--r) var(--r) 0 0;
  background: transparent; color: var(--ink-2); font: inherit; font-size: 13.5px; font-weight: 680;
  cursor: pointer; white-space: nowrap;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.learn-tab:hover { background: var(--surface); color: var(--navy-800); }
.learn-tab:focus-visible { z-index: 1; outline: 2px solid var(--navy-600); outline-offset: -3px; }
.learn-tab.is-active { border-bottom-color: var(--navy-600); background: var(--surface); color: var(--navy-900); }
.learn-tab .icon { width: 18px; height: 18px; color: var(--ink-3); transition: color .15s ease; }
.learn-tab.is-active .icon { color: var(--navy-600); }
.learn-tab__label { line-height: 1.2; }
.learn-tab__sub {
  display: inline-block; margin-left: 2px;
  padding: 2px 7px; border-radius: 999px; background: var(--line-2);
  color: var(--ink-3); font-size: 11px; font-weight: 620;
}
.learn-tab.is-active .learn-tab__sub { background: var(--navy-100); color: var(--navy-700); }

.learn-panel { padding-top: 14px; }
.learn-panel[hidden] { display: none; }

.learn-section { margin-top: 12px; scroll-margin-top: 88px; }
.learn-section > .learn-section__head { margin-bottom: 15px; }
.learn-section__head { display: flex; align-items: baseline; gap: 16px; justify-content: space-between; }
.learn-section__head .eyebrow { margin: 0 0 6px; }
.learn-section__head h2 { font-size: 18.5px; }
.learn-section__head--standalone { align-items: flex-start; }
.learn-section__lede { max-width: 62ch; margin: 7px 0 0; color: var(--ink-2); font-size: 13.5px; line-height: 1.55; }
.learn-section__link {
  flex: none; display: inline-flex; align-items: center; gap: 7px;
  color: var(--navy-700); font-size: 13px; font-weight: 700; white-space: nowrap;
}
.learn-section__link .icon { width: 15px; height: 15px; transition: transform .15s ease; }
.learn-section__link:hover .icon { transform: translateX(2px); }

/* --- course grid + cards ------------------------------------------------- */

.course-grid { display: grid; gap: 15px; }
.course-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.course-grid > [hidden] { display: none; grid-column: 1 / -1; }

.course-card {
  position: relative;
  display: flex; flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--surface); color: var(--ink); box-shadow: var(--shadow-1);
  text-decoration: none;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.course-card:hover { transform: translateY(-3px); border-color: var(--line); box-shadow: var(--shadow-2); text-decoration: none; }
.course-card:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }
.course-card.is-done { border-color: var(--green-100); }
.course-card__body { display: flex; flex-direction: column; gap: 6px; padding: 13px 14px 7px; }
.course-card__dept { color: var(--ink-3); font-size: 10px; font-weight: 750; letter-spacing: .07em; text-transform: uppercase; }
.course-card__title { color: var(--navy-900); font-size: 14.5px; line-height: 1.32; }
.course-card__blurb { color: var(--ink-2); font-size: 13px; line-height: 1.5; }
.course-card__note {
  display: flex; gap: 7px; align-items: flex-start;
  margin-top: 2px; padding: 7px 9px;
  border: 1px solid var(--line-2); border-radius: var(--r-sm);
  background: var(--navy-050); color: var(--navy-700); font-size: 12px; font-weight: 600; line-height: 1.45;
}
.course-card__note .icon { width: 15px; height: 15px; flex: none; margin-top: 1px; color: var(--amber-600); }
.course-card__facts {
  display: flex; flex-wrap: wrap; gap: 4px 7px;
  margin-top: 7px; padding-top: 8px; border-top: 1px solid var(--line-2);
  color: var(--ink-3); font-size: 11.5px;
}
.course-card__facts span + span::before { content: "·"; margin-right: 7px; opacity: .6; }
.course-card__progress { margin-top: 4px; }
.course-card__progress-row { display: flex; justify-content: space-between; gap: 9px; margin-bottom: 5px; color: var(--ink-3); font-size: 11px; }
.course-card__progress .bar { display: block; }
.course-card__cta {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  margin: 10px 14px 14px; padding: 8px 10px;
  border-radius: 10px; background: var(--navy-100); color: var(--navy-700);
  font-size: 12.5px; font-weight: 750;
  transition: background-color .15s ease, color .15s ease;
}
.course-card__cta .icon { width: 15px; height: 15px; transition: transform .15s ease; }
.course-card.is-new .course-card__cta { background: var(--navy-700); color: #fff; }
.course-card:hover .course-card__cta { background: var(--navy-600); color: #fff; }
.course-card.is-new:hover .course-card__cta { background: var(--navy-800); }
.course-card:hover .course-card__cta .icon { transform: translateX(2px); }
.course-card.is-done .course-card__cta { background: var(--green-100); color: var(--green-700); }
.course-card.is-done:hover .course-card__cta { background: var(--green-600); color: #fff; }

/* --- covers — illustrated 16:9 art, one accent palette per subject family. */
.cover {
  position: relative; display: block; width: 100%; aspect-ratio: 16 / 9;
  overflow: hidden;
  background: linear-gradient(135deg, var(--cover-tint, var(--navy-050)), #fff 60%, var(--cover-tint, var(--navy-050)));
  color: var(--navy-900);
}
.cover__art { position: absolute; inset: 0; width: 100%; height: 100%; }
.cover__dot { fill: var(--cover-accent, var(--navy-600)); fill-opacity: .14; }
.cover__dot--line { fill: none; stroke: var(--cover-accent, var(--navy-600)); stroke-opacity: .4; stroke-width: .8; }
.cover__inner { position: relative; z-index: 1; height: 100%; display: flex; flex-direction: column; justify-content: space-between; padding: 11px 13px 10px; }
.cover__top { display: flex; align-items: center; justify-content: space-between; }
.cover__brand {
  padding: 3px 7px; border-radius: 5px;
  background: var(--navy-600); color: #fff;
  font-size: 9px; font-weight: 800; letter-spacing: .12em;
}
.cover__mark { display: grid; place-items: center; width: 22px; height: 22px; border-radius: 7px; background: rgba(255, 255, 255, .55); }
.cover__mark .icon { width: 13px; height: 13px; color: var(--cover-accent, var(--navy-600)); }
.cover__bottom { display: flex; flex-direction: column; gap: 2px; }
.cover__eyebrow { color: var(--cover-accent, var(--navy-600)); font-size: 9px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; }
.cover__title {
  font-family: var(--serif); font-size: clamp(14px, 2vw, 16px); font-weight: 600;
  line-height: 1.16; letter-spacing: 0; text-wrap: balance;
}
.cover__meta { color: var(--ink-3); font-size: 10px; font-weight: 600; }

.cover--benefits       { --cover-accent: var(--tag-blue-fg);      --cover-tint: var(--tag-blue-bg); }
.cover--risk           { --cover-accent: var(--tag-indigo-fg);    --cover-tint: var(--tag-indigo-bg); }
.cover--private-client { --cover-accent: var(--tag-purple-fg);    --cover-tint: var(--tag-purple-bg); }
.cover--claims         { --cover-accent: var(--tag-teal-fg);      --cover-tint: var(--tag-teal-bg); }
.cover--communication  { --cover-accent: var(--tag-cyan-fg);      --cover-tint: var(--tag-cyan-bg); }
.cover--finance        { --cover-accent: var(--tag-amber-fg);     --cover-tint: var(--tag-amber-bg); }
.cover--people         { --cover-accent: var(--tag-stone-fg);     --cover-tint: var(--tag-stone-bg); }
.cover--technology     { --cover-accent: var(--tag-slate-fg);     --cover-tint: var(--tag-slate-bg); }
.cover--general        { --cover-accent: var(--navy-600);         --cover-tint: var(--navy-050); }

/* Compact cover sizes for the hero Continue card and path steps. */
.cover--sm .cover__inner { padding: 7px 7px 6px; }
.cover--sm .cover__brand { padding: 2px 5px; font-size: 7px; }
.cover--sm .cover__mark { width: 16px; height: 16px; border-radius: 5px; }
.cover--sm .cover__title { font-size: 9px; font-weight: 700; line-height: 1.2; }
.cover--sm .cover__eyebrow { font-size: 7px; }
.cover--sm .cover__meta { display: none; }
.cover--sm { border-radius: 10px; }
.cover--thumb .cover__inner { padding: 6px 7px 5px; }
.cover--thumb .cover__brand { padding: 2px 4px; font-size: 6px; }
.cover--thumb .cover__mark, .cover--thumb .cover__eyebrow, .cover--thumb .cover__meta { display: none; }
.cover--thumb .cover__title { font-size: 8px; line-height: 1.25; }
.cover--thumb { border-radius: 8px; }

/* --- catalogue tools: search, filters, sort, chips ---------------------- */

.learn-catalog { scroll-margin-top: 88px; }
.course-tools {
  --tools-control-h: 36px;
  display: flex; flex-wrap: wrap; gap: 10px 9px; align-items: flex-end;
  padding: 12px; border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--shadow-1);
}
.course-tools__search { position: relative; flex: 1 1 260px; min-width: 230px; }
.course-tools__search input {
  width: 100%; height: var(--tools-control-h); padding: 0 12px 0 30px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--surface);
  color: var(--ink); font: inherit; font-size: var(--ui-text-md); outline: none;
  transition: border-color .15s ease;
}
.course-tools__search input:focus { border-color: var(--navy-600); }
.course-tools__search .icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--ink-3); }
.course-sheet { display: contents; }
.course-tools__field { display: flex; flex-direction: column; gap: 5px; width: 152px; }
.course-tools__field label {
  color: var(--ink-3); font-size: 10px; font-weight: 750; letter-spacing: .07em; text-transform: uppercase;
}
/* The date filter has to be listed alongside the select or it inherits
   nothing: it was rendering at the user-agent default — 21px tall, browser
   font, no border — beside a 42px styled select in the same row. */
.course-tools__field select,
.course-tools__field input[type="date"] {
  width: 100%; height: var(--tools-control-h); padding: 0 10px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--surface);
  color: var(--ink); font: inherit; font-size: var(--ui-text-md); outline: none; cursor: pointer;
  transition: border-color .15s ease;
}
.course-tools__field select { padding-right: 24px; }
.course-tools__field select:focus,
.course-tools__field input[type="date"]:focus { border-color: var(--navy-600); }
.course-tools__actions { display: flex; align-items: flex-end; gap: 7px; margin-left: auto; }
.course-tools__actions .btn { height: var(--tools-control-h); }
.course-filters-toggle { display: none; }
.course-filters-toggle__count {
  display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 999px; background: var(--navy-700); color: #fff; font-size: 10.5px; font-weight: 800;
}

.course-chips { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; margin: 12px 2px 0; }
.course-chips[hidden] { display: none; }
.course-chips__label { color: var(--ink-3); font-size: 12px; }
.chip-filter {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 10px; border: 1px solid transparent; border-radius: 999px;
  background: var(--navy-100); color: var(--navy-800);
  font: inherit; font-size: 12px; font-weight: 650; cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}
.chip-filter:hover { border-color: var(--navy-600); }
.chip-filter::after { content: "×"; font-size: 14px; line-height: 1; color: var(--navy-600); }

.course-status { display: flex; align-items: baseline; gap: 10px; margin-top: 15px; }
.course-status strong { color: var(--navy-800); font-size: 14px; }
.course-status span { color: var(--ink-3); font-size: 12.5px; }
.course-empty {
  margin-top: 14px; padding: 21px 16px; text-align: center;
  border: 1px dashed var(--line); border-radius: var(--r-lg);
  background: var(--surface); color: var(--ink-2); font-size: 13.5px;
}

/* --- Required tab --------------------------------------------------------- */

.required-status { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 7px; margin-bottom: 2px; }
.required-status span {
  padding: 7px 10px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--ink-3); font-size: 11.5px; white-space: nowrap;
}
.required-status strong { color: var(--navy-800); font-size: 13px; }
.required-group { margin-top: 24px; }
.required-group:first-of-type { margin-top: 14px; }
.required-group__head { display: flex; align-items: baseline; gap: 9px; margin-bottom: 10px; }
.required-group__head h3 { font-size: 15.5px; }
.required-group__head span { color: var(--ink-3); font-size: 12px; }
.required-group__list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }

/* Mobile filter sheet backdrop. */
.course-sheet-backdrop {
  position: fixed; inset: 0; z-index: 69;
  background: rgba(43, 22, 24, .38);
  opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
.learn-catalog.has-js.is-sheet-open .course-sheet-backdrop { opacity: 1; pointer-events: auto; }



/* ==========================================================================
   Learn — inside a course
   ========================================================================== */

/* Where you are in the course is the first thing the page owes the reader, so
   it is a block of its own rather than one number in a four-across strip. */
.courseprogress {
  display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; gap: 16px;
  align-items: center;
  padding: 15px 18px;
  border: 1px solid var(--line); border-left: 3px solid var(--navy-600);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
.courseprogress__ring { display: grid; place-items: center; }
.courseprogress__label {
  margin: 0 0 2px; color: var(--ink-3); font-size: 10.5px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
}
.courseprogress__value { margin: 0; color: var(--ink); font-size: 15px; }
.courseprogress__value strong { font-size: 17px; font-weight: 750; }
.courseprogress__note { margin: 8px 0 0; color: var(--ink-3); font-size: 12.5px; }

.courseprogress__facts {
  display: grid; grid-auto-flow: column; gap: 21px;
  margin: 0; padding-left: 19px; border-left: 1px solid var(--line-2);
}
.courseprogress__facts dt {
  color: var(--ink-3); font-size: 10.5px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase;
}
.courseprogress__facts dd {
  margin: 4px 0 0; color: var(--navy-800); font-size: 14px; font-weight: 600; white-space: nowrap;
}

/* The course as a catalogue entry — the facts a reader uses to decide whether
   it is for them, kept separate from the working state above it. */
.course-identity {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px;
  margin: 14px 0 0; padding: 0;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--line); overflow: hidden;
}
.course-identity > div {
  min-width: 0; padding: 13px 15px;
  background: var(--surface);
}
.course-identity dt {
  color: var(--ink-3); font-size: 10.5px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase;
}
.course-identity dd { margin: 5px 0 0; color: var(--navy-800); font-size: 14px; font-weight: 640; line-height: 1.4; }
.course-identity__chips { display: flex; flex-wrap: wrap; gap: 5px; }
.course-identity__chips .badge { padding: 4px 8px; font-size: 11.5px; font-weight: 640; }
.course-identity__chips a.badge:hover { text-decoration: none; box-shadow: var(--shadow-1); }
.course-identity__none { color: var(--ink-3); font-weight: 540; }

.quizpanel { display: grid; gap: 14px; }
.quizpanel__head { display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 11px; align-items: start; }
.quizpanel__icon {
  width: 42px; height: 42px; display: grid; place-items: center;
  border-radius: 11px; background: var(--navy-100); color: var(--navy-700);
}
.quizpanel__head h3 { margin-bottom: 4px; font-size: 14px; }
.quizpanel__state {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding-top: 13px; border-top: 1px solid var(--line-2);
}
.quizpanel__state .btn { margin-left: auto; }

.dept-submit-spinner {
  width: 14px; height: 14px;
  border-width: 2px;
  border-color: rgba(255,255,255,.45);
  border-top-color: #fff;
  vertical-align: -2px;
}
.course-card-wrap { position: relative; min-width: 0; }
.course-card-wrap .course-card { height: 100%; }
.course-card__edit { position: absolute; top: 9px; right: 9px; z-index: 2; }

/* --- Lessons as a locked shelf -------------------------------------------
   Two books per row, read top to bottom like a stack rather than chosen
   from like a shelf. Everything past the one a reader has earned sits under
   a lock until its check is passed. */
.book-grid--lessons { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: none; }

/* Course detail pages use the full viewport; keep the lesson shelf fluid as
   well so its cards do not leave an artificial empty rail on wide screens. */
.course-page .book-grid--lessons { width: 100%; }
@media (min-width: 1450px) {
  .course-page .book-grid--lessons { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .course-page .book-grid--lessons { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .course-page .book-grid--lessons { grid-template-columns: minmax(0, 1fr); }
}

.lesson-book.is-locked .book-cover,
.lesson-book.is-pending .book-cover { cursor: default; }
.lesson-book.is-locked:hover .book-cover,
.lesson-book.is-pending:hover .book-cover { transform: none; box-shadow: 0 14px 24px rgba(44, 20, 22, .18), 5px 5px 0 #eadfda, 7px 7px 0 #cbbdb8; }
.lesson-book.is-locked .book-cover { filter: grayscale(1) brightness(.7); }
.lesson-book.is-locked .book-cover__open,
.lesson-book.is-pending .book-cover__open { display: none; }

.lesson-lock {
  display: none;
  position: absolute; inset: 0; z-index: 2;
  border: 0; margin: 0; padding: 0;
  align-items: center; justify-content: center;
  background: rgba(10, 6, 7, .3);
  color: #fff; cursor: default;
}
.lesson-book.is-locked .lesson-lock,
.lesson-book.is-pending .lesson-lock { display: flex; }
.lesson-book.is-pending .lesson-lock { cursor: pointer; background: rgba(10, 6, 7, .2); }
.lesson-lock .icon { width: 30px; height: 30px; opacity: .95; transition: transform .15s ease; }
.lesson-book.is-pending .lesson-lock:hover .icon,
.lesson-book.is-pending .lesson-lock:focus-visible .icon { transform: scale(1.1); }
.lesson-lock:focus-visible { outline: 2px solid #fff; outline-offset: -4px; }

.lesson-lock__tip {
  position: absolute; left: 50%; bottom: 14px; transform: translate(-50%, 4px);
  width: 88%;
  padding: 6px 8px;
  border-radius: 8px;
  background: rgba(10, 6, 7, .94); color: #fff;
  font-size: 10.5px; font-weight: 650; line-height: 1.3; text-align: center;
  opacity: 0; pointer-events: none;
  transition: opacity .15s ease, transform .15s ease;
}
.lesson-lock:hover .lesson-lock__tip,
.lesson-lock:focus-visible .lesson-lock__tip { opacity: 1; transform: translate(-50%, 0); }

/* --- The lesson-check modal ----------------------------------------------
   Reuses .modal/.modal__backdrop/.modal__dialog for the shell (same fade
   and focus-trap contract as the section modal) but as a centred card
   rather than an edge-to-edge dialog. */
.quizmodal-overlay { display: flex; align-items: center; justify-content: center; padding: 16px; }
.quizmodal-overlay .modal__dialog {
  position: relative; inset: auto; top: auto; left: auto; right: auto; bottom: auto;
  width: min(660px, 100%);
  max-height: min(760px, calc(100dvh - 40px));
  margin: auto;
  border-radius: var(--r-lg);
  overflow: hidden;
}
.quizmodal-overlay.is-open .modal__dialog {
  animation: quizmodal-in .28s cubic-bezier(.2, .8, .3, 1) both;
}

@keyframes quizmodal-in {
  from { opacity: 0; transform: translateY(14px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

.quizmodal__body {
  padding: 19px 22px 21px;
  border-color: transparent;
}
.quizmodal__intro { margin: 0 0 16px; color: var(--ink-2); font-size: 13.5px; line-height: 1.5; }
.quizmodal__questions { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.quizmodal__q { padding: 13px 15px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.quizmodal__q.is-flagged { border-color: var(--tag-red-fg); }
.quizmodal__q-text { margin: 0 0 10px; font-size: 13.5px; font-weight: 640; color: var(--navy-800); line-height: 1.4; }
.quizmodal__q-n { color: var(--ink-3); font-weight: 700; margin-right: 3px; }
.quizmodal__options { display: grid; gap: 7px; }
.quizmodal__option {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 10px; border: 1px solid var(--line-2); border-radius: var(--r-sm);
  font-size: 13px; color: var(--ink); cursor: pointer;
  transition: border-color .15s, background .15s;
}
.quizmodal__option:hover { border-color: var(--navy-600); }
.quizmodal__option input { margin: 0; accent-color: var(--navy-700); flex: none; }
.quizmodal__option:has(input:checked) { border-color: var(--navy-600); background: var(--navy-050); }

.quizmodal__hint { color: var(--tag-red-fg); margin: 0 0 9px; }
.quizmodal__actions { display: flex; justify-content: flex-end; margin-top: 7px; }

.quizmodal__result { text-align: center; padding: 7px 7px 16px; }
.quizmodal__result-icon {
  width: 52px; height: 52px; margin: 0 auto 10px; display: grid; place-items: center;
  border-radius: 50%;
}
.quizmodal__result.is-pass .quizmodal__result-icon { background: var(--tag-green-bg); color: var(--tag-green-fg); }
.quizmodal__result.is-fail .quizmodal__result-icon { background: var(--tag-red-bg); color: var(--tag-red-fg); }
.quizmodal__result-icon .icon { width: 28px; height: 28px; display: none; }
.quizmodal__result.is-pass .quizmodal__result-icon--pass,
.quizmodal__result.is-fail .quizmodal__result-icon--fail { display: block; }
.quizmodal__result h3 { margin: 0 0 6px; }
.quizmodal__result-actions { display: flex; gap: 9px; justify-content: center; margin-top: 15px; flex-wrap: wrap; }

.quizmodal__history { margin-top: 19px; padding-top: 15px; border-top: 1px solid var(--line-2); }
.quizmodal__history h4 {
  margin: 0 0 9px; font-size: 11.5px; font-weight: 750; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}
.quizmodal__history table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.quizmodal__history th, .quizmodal__history td { padding: 7px 7px; text-align: left; border-bottom: 1px solid var(--line-2); color: var(--ink-2); }
.quizmodal__history th { font-weight: 700; color: var(--ink-3); font-size: 10.5px; text-transform: uppercase; letter-spacing: .03em; }
.quizmodal__history td.is-pass { color: var(--tag-green-fg); font-weight: 650; }
.quizmodal__history td.is-fail { color: var(--tag-red-fg); font-weight: 650; }

@media (max-width: 640px) {
  .quizmodal-overlay { padding: 12px; }
  .quizmodal__body { padding: 18px 16px 20px; }
  .quizmodal__history table { display: block; overflow-x: auto; white-space: nowrap; }
}

@media (max-width: 1120px) {
  .course-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .required-group__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .learn-search { min-width: 0; flex: 1 1 260px; }
  .courseprogress { grid-template-columns: 44px minmax(0, 1fr); }
  .courseprogress__facts {
    grid-column: 1 / -1;
    padding: 13px 0 0; border-left: 0; border-top: 1px solid var(--line-2);
  }
  .course-identity { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 760px) {
  .learn-search { width: 100%; min-width: 0; }
  .learn-panel { padding-top: 24px; }
  .learn-section { margin-top: 32px; }
  .learn-section__head { flex-wrap: wrap; gap: 10px 16px; }
  .required-status { justify-content: flex-start; }
  .learn-nav__list { gap: 6px; }
  .learn-tab { min-height: 50px; padding: 9px 8px; gap: 7px; }
  .learn-tab .icon, .learn-tab__sub { display: none; }
  .learn-tab__label { font-size: 13px; }
  .course-grid--3 { grid-template-columns: minmax(0, 1fr); }
  .required-group__list { grid-template-columns: minmax(0, 1fr); }
  .course-tools { padding: 12px; }
  .course-tools__field { width: 100%; }
  .course-sheet { display: none; }
  .learn-catalog.has-js .course-sheet {
    display: grid; gap: 12px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 70;
    max-height: 72vh; overflow: auto; padding: 20px 20px 26px;
    border-radius: 18px 18px 0 0;
    background: var(--surface); box-shadow: 0 -10px 40px rgba(43, 22, 24, .22);
    transform: translateY(105%); transition: transform .22s ease;
  }
  .learn-catalog.has-js .course-sheet::before {
    content: ""; display: block; width: 44px; height: 4px; margin: 0 auto 6px;
    border-radius: 999px; background: var(--line);
  }
  .learn-catalog.has-js .course-sheet.is-open { transform: translateY(0); }
  .learn-catalog.has-js .course-tools__actions { flex: 1 1 100%; justify-content: flex-end; }
  .course-filters-toggle { display: inline-flex; }
  .courseprogress__facts { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; }
  .course-identity { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  .learn-search input, .learn-tab, .course-card, .course-card__cta,
  .course-card__cta .icon, .course-tools__search input, .course-tools__field select,
  .chip-filter, .course-sheet,
  .course-sheet-backdrop { transition: none; }
  .course-card:hover, .course-card:hover .course-card__cta,
  .course-card:hover .course-card__cta .icon, .learn-section__link:hover .icon { transform: none; }
}

/* ==========================================================================
   Module modal
   --------------------------------------------------------------------------
   One overlay, reused for every section. The map stays visible behind it, and
   the section's own <main> is dropped into .modal__body — which is the only
   thing that scrolls while the modal is open.
   ========================================================================== */

.modal {
  position: fixed;
  inset: 0;
  /* Above .map-intro (200): the first-login reveal is still mid-animation on
     its own timers when the Welcome hand-off opens this modal, and a section
     opened by direct link force-hides the intro rather than waiting for it,
     so there's no guarantee the intro is done painting by the time this is
     visible. Higher stacking makes that race harmless instead of racing it. */
  z-index: 250;
  padding: 0;
}
.modal[hidden] { display: none; }

.modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(43, 22, 24, .38);
  opacity: 0;
  transition: opacity .35s cubic-bezier(.22, .61, .36, 1);
}
.modal.is-open .modal__backdrop { opacity: 1; }

/* --- morph: the dialog rests as a card inset from the viewport (the map
   stays visible in the margin around it), and is born as the exact rect of
   the four-circle HUD tool cluster (data-morph-source) — app.js runs the
   grow/shrink as a Web Animations API animation on transform + border-radius, since that
   guarantees precise start/end frames (a plain CSS-transition toggled via
   inline styles was unreliable: this same file used to do that and the
   "born small" frame never reliably painted before the transition fired). */
.modal__dialog {
  position: fixed;
  top: 12px; left: 12px; right: 12px; bottom: 12px;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: 16px;
  box-shadow: 0 4px 10px rgba(43, 22, 24, .16), 0 40px 90px -20px rgba(43, 22, 24, .55);
  overflow: hidden;
}
.modal.is-morphing .modal__dialog { will-change: transform, border-radius; }

/* During the reverse morph, keep the expensive page body out of the paint
   path. Social pages can contain several live cross-origin iframes; scaling
   those surfaces while they continue painting is what made closing sometimes
   hitch at the top of the screen. The dialog shell still morphs visibly into
   the four HUD circles, while focus returns only after the animation ends. */
.modal.is-closing .modal__body {
  opacity: 0;
  content-visibility: hidden;
  pointer-events: none;
  transition: opacity .12s ease;
}

/* content trails the shape by a beat and eases in on its own curve, rather
   than a hard opacity cut synced 1:1 to the transform — that stagger is
   what makes the morph read as fluid instead of mechanical */
/* `transform: none` at rest, not translateY(0). Any transform — even an
   identity one — makes the element a containing block for position:fixed
   descendants, and .modal__body is a direct child here. That turned every
   dialog opened from inside the modal (Create Course, the upload and delete
   dialogs, the lesson picker) into a box fixed to the *scrollport* rather
   than the viewport: they measured their max-height in dvh against the
   window but were centred inside a shorter box, so they sat off-centre and
   ran off the bottom edge with no margin. `none` still animates to and from
   translateY(6px) below — the browser interpolates it as the identity
   matrix — so the stagger is unchanged. */
.modal__dialog > * {
  opacity: 1;
  transform: none;
  transition: opacity .22s cubic-bezier(.22, .61, .36, 1) .08s,
              transform .22s cubic-bezier(.22, .61, .36, 1) .08s;
}
.modal.is-morphing.is-first-text-open .modal__dialog > * {
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .15s ease, transform .15s ease;
}

.modal__head {
  display: flex; align-items: center; gap: var(--ui-space-md);
  flex: none;
  padding: 9px 12px 9px 18px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.modal__heading { min-width: 0; }
.modal__eyebrow {
  margin: 0;
  font-size: var(--ui-text-2xs); font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3);
}
.modal__title {
  font-size: var(--ui-text-xl);
  margin: 1px 0 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.modal__tools { margin-left: auto; display: flex; align-items: center; gap: var(--ui-space-sm); flex: none; }

.modal__close {
  display: grid; place-items: center;
  font: inherit;
  width: var(--ui-control-h); height: var(--ui-control-h);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink-2);
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.modal__close:hover { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }
.modal__close:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }

.modal__body {
  /* relative, so it is the offsetParent that layout-metric measurements
     inside the modal (the org chart's fit-to-view) can walk up to. Safe for
     the dialogs above it: position:relative is a containing block for
     absolute descendants, never for fixed ones. */
  position: relative;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.modal__body:focus { outline: none; }

/* The module modal's body is a dashboard canvas, not another white sheet —
   every page dropped into it (.card, .panel, .list, .cover-panel, etc.)
   already declares its own var(--surface) background, so this alone is
   enough to make them read as cards floating on the canvas. Scoped to
   #module-modal specifically: the lesson/quiz modal's .modal__body keeps the
   plain white it had (see the .is-quiz-open precedent just below for this
   same #module-modal scoping pattern). .modal__head stays white too — a
   white toolbar over a grey canvas is the standard pairing for this. */
#module-modal .modal__body { background: var(--surface-canvas); }

/* the section's own page scaffolding, tightened up now that the modal header
   carries the title bar */
.modal__body .page { padding-top: var(--ui-page-pad-top); }
.modal__body .sidenav { top: 8px; }

/* No dialog-specific --measure/--wide-pull override here any more: both are
   now formulas over the .article-page container's own inline size (cqw), not
   the viewport, so they already resolve correctly against whatever box this
   shell is laid out in — the full window on the standalone page, or the
   dialog (12px in from every edge; see .modal__dialog) here. A flat cap used
   to live at this selector for exactly the case cqw now handles on its own. */

body.is-modal-open { overflow: hidden; }

/* The quiz's own lock, not is-modal-open: overflow:hidden alone leaves
   keyboard/programmatic scroll free to move the body underneath a
   position:fixed dialog, which is what made it read as "stuck at the top"
   rather than centred over whatever the reader was looking at. Freezing the
   body in place at its own scroll offset (JS sets `top`) blocks every path
   at once and means nothing visually jumps when the check opens or closes. */
body.is-quiz-open { position: fixed; left: 0; right: 0; overflow: hidden; }

/* A course can also sit inside the section modal, where the modal's own body —
   not the document body — is what scrolls. Freeze that scroller the same way
   app.js does the page body, so the check stays over the lesson that asked for
   it instead of losing its place. */
#module-modal .modal__body.is-quiz-open { overflow: hidden; }

/* --- loading and error states ------------------------------------------- */

.modalstate {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 6px;
  min-height: min(58vh, 313px);
  padding: 30px 19px;
  text-align: center;
}
.modalstate__title { margin: 6px 0 0; font-size: 14.5px; font-weight: 600; color: var(--navy-800); }
.modalstate__icon {
  width: 46px; height: 46px; border-radius: 12px;
  display: grid; place-items: center;
  background: var(--navy-100); color: var(--navy-700);
}
.modalstate__actions { display: flex; gap: 9px; flex-wrap: wrap; justify-content: center; margin-top: 12px; }

.spinner {
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 3px solid var(--line);
  border-top-color: var(--navy-600);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* The site footer's styles went with the footer itself — every page that
   could have rendered one is now either the map or a full-viewport takeover,
   and all of them suppress it. See app/Views/layouts/footer.php. */

/* prototype ribbon */
.protonote {
  background: #fdeceb; border-bottom: 1px solid #f3c8c9; color: #8e1b22;
  font-size: 12.5px; padding: 7px 0; text-align: center;
}

/* ==========================================================================
   Welcome journey — article layout
   The six onboarding steps are read start to finish, so they get an editorial
   shell instead of the dashboard furniture the rest of the app uses: one
   measure for the prose, a quiet contents rail, numbered sections, and
   hairlines where the app would otherwise reach for another card.
   ========================================================================== */

.article-page {
  --rail: 190px;
  --gutter: clamp(24px, 3cqw, 48px);
  /* Used to be a flat 800px, then a clamp(720px, 62cqw, 1180px) — both still
     left real width on the table at the widths this app actually runs at
     (a ~1900px monitor, or the section-preview dialog at nearly that size):
     62cqw of a ~1876px container is only ~1163px, capped further to 1180px
     regardless, against a column that had roughly 1638px to give — around
     460px of the right side going unused every time. This app does not
     stake anything on a classic ~90-character prose measure; using the page
     it was given reads better here than a narrow reading column floating in
     spare width, so the multiplier and ceiling below both go high enough
     that --measure reaches the actual column width at ordinary desktop
     sizes and only the ceiling's own headroom is left unclaimed. The floor
     is what still keeps a small container (see the breakpoint further down)
     from reading as a single run-on line. */
  --measure: clamp(720px, 92cqw, 1600px);
  /* How far a figure marked .is-wide may grow past the measure: the rest of
     the article's own column, right up to the page edge. One-sided now —
     the rail sits flush against the page's left padding by construction
     (.article-shell's second track is what flexes, not a fixed pair being
     recentred), so there is no spare margin on the left to reclaim any
     more, only the room this formula measures on the right. Usually at or
     near 0 now that --measure itself is tuned to reach the column's actual
     width — is-wide mainly still matters on a container wide enough to hit
     --measure's 1600px ceiling before the column does. */
  --wide-pull: max(0px, calc(100cqw - var(--rail) - var(--gutter) - var(--measure)));
  padding-block: 21px 52px;

  /* These pages are almost always read inside the section modal, whose
     dialog is a good deal narrower than the window. Sizing --measure and
     --wide-pull off the container rather than the viewport is what makes
     both resolve correctly in either place with nothing dialog-specific to
     reconcile — the same reason the rail's own collapse below was moved
     off a viewport media query onto this container query. Safe here:
     nothing inside an .article-page is positioned fixed, so the
     containment this introduces has nothing to trap. */
  container-type: inline-size;
  container-name: article;
}

.article-shell {
  display: grid;
  /* A fixed track for the rail, one flexible track for the article. The old
     shape gave the article a fixed measure-wide track too and centred the
     pair as a unit, which is what turned any extra width the monitor had
     into two empty margins outside it instead of space the page used. A
     flexible second track lets the shell fill the page edge to edge — the
     rail lands against the page's own padding on the left, where a rail
     belongs — while --measure above is what keeps prose from stretching
     the rest of the way with it. */
  grid-template-columns: var(--rail) minmax(0, 1fr);
  gap: 0 var(--gutter);
  align-items: start;
}

/* Prose is capped at the measure so a paragraph never runs the full width of
   the flexible column. A figure that needs more room (the org chart, the
   company timeline, the portrait grid) opts out with .is-wide and grows into
   the rest of the column on its own right edge — see --wide-pull above. */
.article-main { min-width: 0; max-width: var(--measure); }
.article-section {
  margin-top: 38px;
  scroll-margin-top: 96px;
}
.article-section > .is-wide { margin-right: calc(var(--wide-pull) * -1); }

/* --- header ---------------------------------------------------------------- */

.article-head { padding-bottom: 21px; border-bottom: 1px solid var(--line); }
.article-head__back {
  display: inline-flex; align-items: center; gap: 7px;
  margin-bottom: 16px;
  color: var(--ink-3); font-size: 13px; font-weight: 550;
}
.article-head__back .icon { width: 15px; height: 15px; }
.article-head__back:hover { color: var(--navy-700); text-decoration: none; }
.article-head__kicker {
  display: flex; align-items: center; gap: 8px; margin-bottom: 10px;
  color: var(--navy-700); font-size: 11.5px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
}
.article-head__kicker::before {
  content: ""; width: 22px; height: 2px; border-radius: 999px; background: var(--navy-600);
}
/* Both run to the measure. Capping them shorter than the body only produced
   two- and three-word lines under a column that was already narrow. */
.article-head h1 {
  font-family: var(--serif);
  font-size: clamp(25px, 4vw, 33px);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -.02em;
}
.article-head__deck {
  margin: 12px 0 0;
  color: var(--ink-2); font-size: 17px; line-height: 1.55;
}
.article-head__meta {
  display: flex; align-items: center; gap: 7px 12px; flex-wrap: wrap;
  margin-top: 16px;
  color: var(--ink-3); font-size: 12.5px;
}
.article-head__meta span { display: inline-flex; align-items: center; gap: 6px; }
.article-head__meta .icon { width: 14px; height: 14px; }
.article-head__meta .article-head__dot {
  width: 3px; height: 3px; padding: 0; border-radius: 50%; background: var(--ink-3); opacity: .55;
}

/* --- contents rail --------------------------------------------------------- */

/* Sits in the rail's own fixed track, flush against the page's left padding —
   there is no longer a centred pair to back off from, so the gap to the
   leftmost content is always exactly one gutter, wide figures or not. */
.article-toc {
  position: sticky; top: 112px;
  width: 100%; max-height: calc(100vh - 136px);
  justify-self: end;
  overflow-y: auto; scrollbar-width: thin;
}
.modal__body .article-toc { top: 8px; max-height: calc(100dvh - 104px); }
.article-toc__title {
  margin: 0 0 10px; padding-bottom: 10px; border-bottom: 1px solid var(--line);
  color: var(--ink-3); font-size: 10.5px; font-weight: 700;
  letter-spacing: .11em; text-transform: uppercase;
}
.article-toc__list { list-style: none; margin: 0; padding: 0; }
.article-toc__list a {
  display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 7px;
  padding: 7px 0 7px 10px;
  border-left: 2px solid var(--line);
  color: var(--ink-2); font-size: 13px; line-height: 1.4;
}
.article-toc__list a:hover { border-left-color: var(--ink-3); color: var(--ink); text-decoration: none; }
.article-toc__list a.is-active {
  border-left-color: var(--navy-600); color: var(--navy-800); font-weight: 650;
}
.article-toc__n { color: var(--ink-3); font-size: 11px; font-variant-numeric: tabular-nums; }
.article-toc__list a.is-active .article-toc__n { color: var(--navy-600); }

.article-toc__progress { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.article-toc__progress-label {
  margin: 0 0 7px; color: var(--ink-3); font-size: 11px;
  letter-spacing: .04em; text-transform: uppercase;
}
.article-toc__progress-bar { height: 4px; border-radius: 999px; background: var(--line); overflow: hidden; }
.article-toc__progress-bar span {
  display: block; height: 100%; width: 0; border-radius: inherit;
  background: var(--navy-600); transition: width .2s linear;
}

/* --- section heads --------------------------------------------------------- */

.article-section__head { margin-bottom: 14px; }
.article-section__kicker {
  display: flex; align-items: center; gap: 8px; margin: 0 0 7px;
  color: var(--ink-3); font-size: 11px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
}
.article-section__n {
  color: var(--navy-600); font-variant-numeric: tabular-nums;
}
.article-section__n::after {
  content: ""; display: inline-block; width: 14px; height: 1px;
  margin: 0 0 4px 8px; background: var(--line); vertical-align: middle;
}
.article-section__head h2 {
  font-family: var(--serif); font-size: 22.5px; font-weight: 600; line-height: 1.2;
  letter-spacing: -.01em;
}
.article-section__head h3 { margin-top: 4px; }

/* --- prose ----------------------------------------------------------------- */

/* 16px against --measure's 720–1600px range lands somewhere between 90 and
   nearly 200 characters a line depending on how much room the page has — well
   past the comfortable band at the wide end, but that trade is the point of
   --measure reaching for the column's actual width instead of a fixed prose
   measure: see the comment on it above .article-page. */
.article-prose { color: var(--ink-read); font-size: 16px; line-height: 1.75; }
.article-prose > p { margin: 0; }
.article-prose > p:last-child { margin-bottom: 0; }
.article-prose strong { color: var(--ink); font-weight: 650; }
.article-prose a { text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px; }
.article-prose > p.article-prose__aside {
  color: var(--ink-3); font-size: 14px; line-height: 1.65;
}
.article-prose ul, .article-prose ol { margin: 0 0 14px; padding-left: 0; list-style: none; }
.article-prose li { position: relative; padding-left: 21px; margin-bottom: 9px; }
.article-prose li:last-child { margin-bottom: 0; }
.article-prose ul > li::before {
  content: ""; position: absolute; left: 4px; top: .68em;
  width: 6px; height: 6px; border-radius: 50%; background: #e0bcbf;
}
.article-prose ol { counter-reset: article-ol; }
.article-prose ol > li { counter-increment: article-ol; }
.article-prose ol > li::before {
  content: counter(article-ol, decimal-leading-zero);
  position: absolute; left: 0; top: 0;
  color: var(--navy-600); font-size: 12.5px; font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 2.1;
}

/* An aside explains, so it gets a rule and a tint rather than a boxed card —
   the point is that the eye can skip it and come back, not that it stops. */
.article-note {
  margin: 18px 0 0; padding: 12px 15px;
  border-left: 3px solid var(--tag-blue-fg);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: #f2f6fd;
}
.article-note__title {
  display: flex; align-items: center; gap: 7px; margin: 0 0 5px;
  color: var(--tag-blue-fg); font-size: 12px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase;
}
.article-note__title .icon { width: 15px; height: 15px; }
.article-note p { margin: 0; color: var(--ink-2); font-size: 14px; line-height: 1.65; }

/* A worked example is the payoff of a section, so it reads as a framed extract
   on the page wash instead of another white card in a stack of white cards. */
.article-example {
  margin-top: 4px; padding: 18px 19px;
  border: 1px solid var(--line); border-top: 3px solid var(--navy-600);
  border-radius: 0 0 var(--r) var(--r);
  background: var(--surface);
}
.article-example__label {
  margin: 0 0 9px; color: var(--navy-700); font-size: 11px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
}
.article-example h3 { margin-bottom: 9px; font-family: var(--serif); font-size: 17px; font-weight: 600; line-height: 1.35; }
.article-example p { color: var(--ink-read); font-size: 14.5px; line-height: 1.7; }
.article-example p + p { margin-top: 10px; }
.article-example__footnote { color: var(--ink-3); font-size: 13.5px; }

/* Definition-style Q&A. Hairlines, not cards — an FAQ at the end of an article
   is a list of short answers, not a grid of tiles. */
.article-qa { display: grid; }
.article-qa__item { padding: 15px 0; border-top: 1px solid var(--line); }
.article-qa__item:last-child { border-bottom: 1px solid var(--line); }
.article-qa__q {
  display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 9px;
  margin-bottom: 7px; color: var(--navy-800); font-size: 15px; font-weight: 650;
}
.article-qa__q::before {
  content: "Q"; color: var(--navy-600); font-size: 12px; font-weight: 800;
  letter-spacing: .06em; line-height: 1.85;
}
.article-qa__a { margin: 0 0 0 27px; color: var(--ink-2); font-size: 14px; line-height: 1.7; }

/* Structured blocks keep their card, because they are things you operate or
   scan in columns rather than read in sentences. */
.article-card {
  padding: 16px 18px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface);
}
.article-card__intro { margin: 0 0 10px; color: var(--ink-3); font-size: 13.5px; }
.article-card__intro:last-child { margin-bottom: 0; }
.article-card .checkrow { font-size: 14px; padding: 10px 0; }

/* Display-only first-week checklist. The empty squares are visual list markers,
   not controls, so the content reads consistently without suggesting saved or
   interactive completion state. */
.article-checklist {
  margin-top: 16px;
  padding: 2px clamp(15px, 3vw, 19px) 18px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
.article-checklist__group {
  padding: 18px 0;
  border-bottom: 1px solid var(--line);
}
.article-checklist__group h3 {
  color: var(--navy-800);
  font-size: 15.5px;
}
.article-checklist__group ul {
  display: grid;
  gap: 8px;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}
.article-checklist__group li {
  position: relative;
  padding-left: 22px;
  color: var(--ink-read);
  font-size: 14.5px;
  line-height: 1.6;
}
.article-checklist__group li::before {
  content: "";
  position: absolute;
  top: .38em;
  left: 1px;
  width: 14px;
  height: 14px;
  border: 1.5px solid #d5b5b7;
  border-radius: 3px;
  background: var(--surface);
}
.article-checklist__note {
  margin: 0;
  padding: 16px 0 0;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.7;
}

.article-figure { margin: 0; }
.article-figure__caption {
  margin: 10px 0 0; color: var(--ink-3); font-size: 12.5px; line-height: 1.6;
}

/* Sub-heads inside a numbered section: smaller than the section head, and
   sans, so the reader can tell a part from a whole at a glance. */
.article-subhead {
  margin: 25px 0 10px;
  color: var(--navy-800); font-size: 14px; font-weight: 700;
  letter-spacing: .02em;
}
.article-subhead::before {
  content: ""; display: block; width: 26px; height: 2px; margin-bottom: 8px;
  border-radius: 999px; background: #e6c7c9;
}

/* A charter, a mission, a definition — one sentence the section is built
   around. Serif and indented, so it reads as quoted rather than asserted. */
.article-quote {
  margin: 18px 0 0; padding: 4px 0 4px 18px;
  border-left: 3px solid var(--navy-600);
  color: var(--navy-900); font-family: var(--serif); font-size: 19px;
  font-style: normal; line-height: 1.45;
}
.article-quote cite {
  display: block; margin-top: 10px;
  color: var(--ink-3); font-family: var(--font); font-size: 12.5px;
  font-style: normal; letter-spacing: .02em;
}

/* Situation / guidance / action / outcome. A definition list beats a numbered
   list here: the labels are the point, not the ordering. */
.article-scenario { display: grid; gap: 0; margin: 4px 0 0; }
.article-scenario dt {
  padding-top: 12px; color: var(--navy-700); font-size: 11px; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase;
}
.article-scenario dd {
  margin: 5px 0 0; padding-bottom: 12px; border-bottom: 1px solid var(--line-2);
  color: var(--ink-read); font-size: 14.5px; line-height: 1.65;
}
.article-scenario dd:last-child { padding-bottom: 0; border-bottom: 0; }

.article-section > .list,
.article-section > .tablewrap { margin-top: 4px; }
.article-section > .flow { margin-top: 4px; }

/* --- footer nav ------------------------------------------------------------ */

.article-nav {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px;
  margin-top: 41px; padding-top: 19px; border-top: 1px solid var(--line);
}
.article-nav__link {
  display: grid; gap: 4px; padding: 13px 15px;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); color: var(--ink);
}
.article-nav__link:hover { border-color: #e4aaae; background: var(--navy-050); text-decoration: none; }
.article-nav__link--next { text-align: right; }
.article-nav__dir {
  display: flex; align-items: center; gap: 6px;
  color: var(--ink-3); font-size: 11px; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase;
}
.article-nav__link--next .article-nav__dir { justify-content: flex-end; }
.article-nav__dir .icon { width: 13px; height: 13px; }
.article-nav__title { font-family: var(--serif); font-size: 15.5px; font-weight: 600; color: var(--navy-800); }
.article-nav__link.is-disabled {
  opacity: .55; cursor: not-allowed; pointer-events: none; background: transparent;
}
.article-nav__status {
  grid-column: 1 / -1; margin: 0; color: var(--ink-3); font-size: 12.5px; text-align: center;
}

/* --- per-step figures ------------------------------------------------------ */

/* Fourteen subjects with the same one-line description each form a compact
   card wall. The cards are bounded rather than stretched across a short row,
   so a group with only one department still reads as one destination instead
   of a full-width panel. */
.subject-group__note { margin: 0 0 12px; color: var(--ink-3); font-size: 13.5px; }
.subject-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 360px));
  gap: 12px; margin-bottom: 7px;
}
.subject-grid__item {
  display: grid; grid-template-columns: 34px minmax(0, 1fr) 16px; gap: 10px;
  align-items: center; min-height: 58px; padding: 11px 13px;
  border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--shadow-1);
  background: var(--surface); color: var(--ink); text-decoration: none;
  transition: border-color .2s ease, background-color .2s ease, box-shadow .2s ease, transform .2s ease;
}
.subject-grid__item:hover {
  border-color: #e4aaae; background: var(--navy-050);
  box-shadow: var(--shadow-2); text-decoration: none; transform: translateY(-1px);
}
.subject-grid__item:focus-visible {
  position: relative; z-index: 1;
  outline: 2px solid var(--navy-600); outline-offset: 2px;
}
.subject-grid__icon {
  width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 9px; background: var(--navy-100); color: var(--navy-700);
}
.subject-grid__icon .icon { width: 17px; height: 17px; }
.subject-grid__body { min-width: 0; }
.subject-grid__body strong { display: block; font-size: 13.5px; font-weight: 620; }
.subject-grid__body small { color: var(--ink-3); font-size: 12px; }
.subject-grid__go { color: var(--ink-3); display: grid; }
.subject-grid__go .icon { width: 16px; height: 16px; }
.subject-grid__item:hover .subject-grid__go { color: var(--navy-600); }

@media (prefers-reduced-motion: reduce) {
  .subject-grid__item { transition: none; }
  .subject-grid__item:hover { transform: none; }
}

/* Step 4 uses the same hand-off grammar as the organization waterfall. The
   fixed centred measure keeps the staircase itself centred even while each
   successive card moves to the right. */
.waterfall--learning {
  --wf-indent: clamp(18px, 3vw, 38px);
  max-width: 820px;
  margin-inline: auto;
}
.learning-path__card {
  grid-template-columns: 26px 34px minmax(0, 1fr) auto;
  align-items: center;
  min-height: 52px;
  box-shadow: var(--shadow-1);
}
.learning-path__icon {
  width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 9px; background: var(--wf-tint); color: var(--wf-accent);
}
.learning-path__icon .icon { width: 17px; height: 17px; }
.learning-path__body { min-width: 0; }
.learning-path__body p { max-width: 48ch; }
.learning-path__meta {
  align-self: center; white-space: nowrap;
  border-radius: 999px; padding: 4px 8px;
  background: var(--line-2); color: var(--ink-3);
  font-size: 11.5px; font-weight: 700;
}
.learning-path__meta.is-future {
  background: var(--tag-purple-bg); color: var(--tag-purple-fg);
}
.waterfall--learning + .article-figure__caption { text-align: center; }

/* Two category panels reveal the information architecture before the reader
   scans fourteen links. Each destination remains a full-width, 44px+ target. */
.subject-catalog {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 15px;
  margin-top: 19px;
}
.subject-catalog__group {
  --subject-accent: var(--tag-blue-fg);
  --subject-tint: var(--tag-blue-bg);
  align-self: start; overflow: hidden;
  border: 1px solid var(--line); border-top: 3px solid var(--subject-accent);
  border-radius: var(--r-lg); background: var(--surface);
  box-shadow: var(--shadow-1);
}
.subject-catalog__group--capability {
  --subject-accent: var(--tag-teal-fg);
  --subject-tint: var(--tag-teal-bg);
}
.subject-catalog__head {
  display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 10px;
  align-items: center; padding: 16px 16px 7px;
}
.subject-catalog__icon {
  width: 42px; height: 42px; display: grid; place-items: center;
  border-radius: 11px; background: var(--subject-tint); color: var(--subject-accent);
}
.subject-catalog__icon .icon { width: 20px; height: 20px; }
.subject-catalog__eyebrow {
  margin: 0 0 1px; color: var(--subject-accent);
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
}
.subject-catalog__head h3 { color: var(--navy-900); font-size: 16px; }
.subject-catalog__note {
  margin: 0; padding: 0 16px 14px;
  color: var(--ink-2); font-size: 13px; line-height: 1.55;
}
.subject-catalog__list { border-top: 1px solid var(--line); }
.subject-catalog__item {
  min-height: 39px; display: grid; grid-template-columns: minmax(0, 1fr) 18px; gap: 10px;
  align-items: center; padding: 9px 14px 9px 16px;
  border-bottom: 1px solid var(--line-2); color: var(--ink);
  text-decoration: none;
  transition: background-color .2s ease, color .2s ease;
}
.subject-catalog__item:last-child { border-bottom: 0; }
.subject-catalog__item:hover { background: var(--subject-tint); text-decoration: none; }
.subject-catalog__item:focus-visible {
  position: relative; z-index: 1;
  outline: 2px solid var(--subject-accent); outline-offset: -3px;
}
.subject-catalog__body { min-width: 0; }
.subject-catalog__body strong { display: block; font-size: 14px; font-weight: 650; }
.subject-catalog__body small { display: block; color: var(--ink-3); font-size: 11.5px; }
.subject-catalog__go {
  display: grid; color: var(--ink-3);
  transition: color .2s ease, transform .2s ease;
}
.subject-catalog__go .icon { width: 16px; height: 16px; }
.subject-catalog__item:hover .subject-catalog__go {
  color: var(--subject-accent); transform: translateX(2px);
}
.subject-catalog__more {
  display: grid; grid-template-columns: minmax(0, 1fr) 18px; gap: 10px;
  align-items: center; padding: 10px 14px 10px 16px;
  border-top: 1px solid var(--line);
  color: var(--subject-accent); font-size: 13px; font-weight: 700;
  text-decoration: none;
  transition: background-color .2s ease;
}
.subject-catalog__more:hover { background: var(--subject-tint); }
.subject-catalog__more .subject-catalog__go { color: var(--subject-accent); }
.subject-catalog__more:hover .subject-catalog__go { transform: translateX(2px); }

@media (max-width: 780px) {
  .waterfall--learning { --wf-indent: 0px; }
}

/* Five portraits plus their gaps and the panel padding have to fit the widest
   the figure ever gets, which at 1280px is the bare measure with no bleed. */
.article-page .leadership-directory { --leader-portrait: clamp(104px, 9vw, 156px); }
.article-page .company-timeline__card { min-height: 154px; }
.article-page .mission-card { box-shadow: none; }

/* Measured on the article's own container, not the window: below this the
   two tracks plus the gutter no longer leave the article a readable column,
   so the rail stops being a rail and becomes a box above it. Squeezing it was
   never an option — "Frequently Asked Questions" over three lines in a 100px
   sliver is what this exists to prevent.

   Unlike the old fixed-measure version of this layout, the content track
   itself (minmax(0, 1fr)) can never fail to fit beside the rail's fixed
   190px — it just narrows. What actually matters here is whether that
   narrower column still reads as an article next to a rail rather than two
   competing columns of similar width. At 1080, rail(190) + gutter leave the
   column ~850px, nowhere near cramped — this threshold has plenty of margin
   before the two-column shape stops being comfortable, on purpose: it
   should give way once the rail starts crowding the article, not the
   moment --measure's own ceiling stops being reachable. */
@container article (max-width: 1080px) {
  .article-page { --wide-pull: 0px; }
  /* .article-main's own max-width (the measure) still caps the prose here —
     this track only needs to stop being a second column and hand the whole
     row to it, the same flexible shape .article-shell uses above the
     breakpoint. */
  .article-shell { grid-template-columns: minmax(0, 1fr); }
  .mission-card--wide { margin-inline: 0; }
  .article-toc {
    position: static; max-height: none; overflow: visible;
    width: auto; justify-self: stretch;
    margin-bottom: 25px; padding: 14px 15px;
    border: 1px solid var(--line); border-radius: var(--r); background: var(--surface);
  }
  .article-toc__list { columns: 2; column-gap: 18px; }
  .article-toc__list li { break-inside: avoid; }
}
@container article (max-width: 620px) {
  .article-toc__list { columns: 1; }
}

@media (max-width: 640px) {
  .article-page { padding-block: 18px 52px; }
  .article-head__deck { font-size: 17px; }
  .article-section { margin-top: 42px; }
  .article-prose { font-size: 16px; }
  .article-nav { grid-template-columns: minmax(0, 1fr); }
  .article-nav__link--next { text-align: left; }
  .article-nav__link--next .article-nav__dir { justify-content: flex-start; }
  .learning-path__card {
    grid-template-columns: 26px 34px minmax(0, 1fr);
    padding-inline: 14px;
  }
  .learning-path__meta {
    grid-column: 3; justify-self: start; margin-top: 3px;
  }
  .subject-catalog { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .subject-catalog__note { min-height: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .subject-catalog__item,
  .subject-catalog__go { transition: none; }
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 1080px) {
  .grid--4 { grid-template-columns: repeat(2, 1fr); }
  .stats { grid-template-columns: repeat(min(var(--stat-cols, 2), 2), minmax(0, 1fr)); }
  .split, .split--right { grid-template-columns: 1fr; }
  .sidenav { position: static; }

  .iconbtn--wide span { display: none; }
}

@media (max-width: 900px) {
  .company-timeline { grid-template-columns: 1fr; gap: 0; padding: 0; }
  .company-timeline::before {
    top: 8px; right: auto; bottom: 12px; left: 10px;
    width: 3px; height: auto;
    background: linear-gradient(180deg, #7a0b12, #8a5a10 20%, #566b14 40%, #0f6f63 60%, #2b4fa8 80%, #7b3a9e);
  }
  .company-timeline::after {
    right: auto; bottom: 5px; left: 5px;
    border-top: 9px solid #7b3a9e; border-right: 6px solid transparent;
    border-bottom: 0; border-left: 6px solid transparent;
  }
  .company-timeline__item {
    grid-template-rows: auto; grid-template-columns: 22px 64px minmax(0, 1fr);
    grid-template-areas: "marker year card"; gap: 8px; align-items: center;
    padding-bottom: 16px; text-align: left;
  }
  .company-timeline__card-wrap { grid-area: card; padding-top: 0; }
  .company-timeline__card {
    min-height: 0; padding: 16px 16px 16px 62px;
    border: 1px solid var(--line); border-left: 3px solid var(--milestone);
    border-radius: var(--r); background: var(--milestone-wash, var(--navy-050)); clip-path: none;
  }
  .company-timeline__icon {
    top: 14px; left: 14px; width: 38px; height: 38px;
    border-width: 0; transform: none; box-shadow: none;
  }
  .company-timeline__icon .icon-lg { width: 18px; height: 18px; }
  .company-timeline__card h3 { margin-bottom: 5px; }
  .company-timeline__marker { grid-area: marker; width: 14px; height: 14px; }
  .company-timeline__year { grid-area: year; }
  .leadership-directory { --leader-portrait: 124px; }
  .leadership-row { flex-wrap: wrap; width: 100%; }
}

@media (max-width: 760px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }
  .identity__grid { grid-template-columns: repeat(2, 1fr); }
  .list__side { display: none; }

  .welcome-metrics { grid-template-columns: 1fr; }

  /* The map still opens with the whole island in view here; drag-to-pan and
     pinch-to-zoom (app.js) are how you reach and enlarge the rest. */
  .mapchrome { padding: 10px 12px; gap: 8px; }
  .mapchrome__brand {
    left: max(12px, env(safe-area-inset-left));
    bottom: max(12px, env(safe-area-inset-bottom));
    padding: 0;
  }
  .mapchrome__brand-logo { width: min(145px, 42vw); height: auto; }
  .mapchrome__tools { gap: 6px; }
  .map-building__label,
  .map-building:hover .map-building__label,
  .map-building:focus-visible .map-building__label,
  .map-building.is-intro-highlight .map-building__label {
    grid-template-rows: auto 0fr;
    width: var(--tip-rest-width, max-content);
    padding: 3px 8px;
    border-radius: 999px;
    font-size: 11px;
  }
  .map-building__description-wrap { display: none; }

  .modal__dialog { top: 8px; left: 8px; right: 8px; bottom: 8px; border-radius: 14px; }
  .modal__head { padding: 11px 12px 11px 16px; gap: 10px; }
  .modal__title { font-size: 16.5px; }
  .modal__eyebrow { display: none; }

  .mission-card { grid-template-columns: 1fr; }
  .leadership-directory { gap: 24px; }
  .leadership-row { display: grid; grid-template-columns: minmax(0, 390px); gap: 24px; }
  .leadership-person { width: 100%; }
  .leadership-person__portrait { max-height: 330px; }
  /* One portrait per row here, so every bubble can centre; the edge rules that
     keep end portraits inside the panel have nothing to correct for. */
  .leadership-person:first-child:not(:last-child) .leader-quote,
  .leadership-person:last-child:not(:first-child) .leader-quote {
    left: 50%; right: auto; transform: translate(-50%, 6px);
  }
  .leadership-person:first-child:not(:last-child):hover .leader-quote,
  .leadership-person:first-child:not(:last-child):focus-within .leader-quote,
  .leadership-person:last-child:not(:first-child):hover .leader-quote,
  .leadership-person:last-child:not(:first-child):focus-within .leader-quote {
    transform: translate(-50%, 0);
  }
  .leadership-person:first-child:not(:last-child) .leader-quote::after,
  .leadership-person:last-child:not(:first-child) .leader-quote::after {
    left: 50%; right: auto; transform: translateX(-50%) rotate(45deg);
  }
}

/* A pulsing glow is decoration; the pointer cursor, label and focus ring are
   what actually say "this is a button". */
@media (prefers-reduced-motion: reduce) {
  .mapchrome__brand { transition: none; }
  .mapchrome__brand:hover { transform: none; }
  .leadership-person,
  .leader-quote { transition: none; }
  .leader-quote__typed::after { animation: none; }
  .map-intro__logo { animation: none; opacity: 1; }
  .map-intro__logo-layer { transition-duration: .08s; }
  .map-intro__cloudscape,
  .map-intro__cloud { transition: opacity .18s ease; }
  .map-intro.is-clouds-away .map-intro__cloud { transform: none; }
  .takeover-transition .map-intro__logo-layer,
  .takeover-transition .map-intro__cloudscape,
  .takeover-transition .map-intro__cloud {
    transition-duration: .18s !important;
    transition-delay: 0s !important;
  }
  .takeover-transition .map-intro__cloud,
  .takeover-transition.is-covered .map-intro__cloud,
  .is-takeover-arrival .takeover-transition .map-intro__cloud,
  .is-takeover-arrival .takeover-transition.is-leaving .map-intro__cloud { transform: none; }
  .map-building.is-intro-highlight {
    animation: none;
  }
  .map-building.is-intro-highlight img,
  .map-building.is-intro-highlight .map-building__glow { animation: none; }
  .map-building,
  .map-building img,
  .map-building__label,
  .map-building__description-wrap,
  .map-building__go { transition: none; }
  .map-building__glow { animation: none; opacity: .12; }
  .map-building.is-active .map-building__glow { animation: none; opacity: .9; }
  .map-building:hover, .map-building:focus-visible,
  .map-building.is-active, .map-building.is-intro-highlight {
    transform: translateX(-50%) rotate(var(--rot, 0deg));
  }
  .modal__backdrop, .modal__dialog > * { transition: none; }
  .quizmodal-overlay.is-open .modal__dialog { animation: none; }
  .spinner { animation-duration: 2s; }
}

/* ==========================================================================
   Template Library (Templates page)
   --------------------------------------------------------------------------
   Full width, search-first tools bar, a department carousel, then one grid
   per format. Default state shows that browse layout; any search or filter
   collapses it into one unified results grid. See assets/js/app.js
   initTemplateLibrary and initTemplateCarousel for the behaviour.
   ========================================================================== */

.tpl-search {
  display: flex; align-items: center; gap: 9px;
  width: 100%; max-width: 920px; height: 64px; margin: 22px auto 0; padding: 0 10px 0 19px;
  border: 1px solid var(--line); border-radius: 18px;
  background: var(--surface); box-shadow: var(--shadow-1);
  transition: border-color .15s, box-shadow .15s;
}
.tpl-search:focus-within { border-color: var(--navy-600); box-shadow: 0 0 0 3px var(--navy-100); }
.tpl-search .icon { width: 21px; height: 21px; flex: none; color: var(--ink-3); }
.tpl-search input {
  flex: 1; min-width: 0; height: 100%;
  border: 0; outline: 0; background: transparent; color: var(--ink);
  font: inherit; font-size: 15.5px;
}
.tpl-search input::-webkit-search-cancel-button,
.tpl-search input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.tpl-search__clear {
  display: none; align-items: center; justify-content: center;
  width: 32px; height: 32px; flex: none; border: 0; border-radius: 999px;
  background: var(--navy-050); color: var(--ink-3); cursor: pointer;
}
.tpl-search__clear .icon { width: 15px; height: 15px; }
.tpl-search__clear:hover { background: var(--navy-100); color: var(--navy-700); }
.tpl-search.has-value .tpl-search__clear { display: inline-flex; }

.tpl-filter-row {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 9px; max-width: 960px; margin: 15px auto 0;
}
.tpl-tools__field { min-width: 0; }
.tpl-tools__field select,
.tpl-tools__field input[type="date"] {
  height: 42px; padding: 0 14px; min-width: 0;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--ink-2);
  font: inherit; font-size: 13.5px; font-weight: 550; cursor: pointer;
}
.tpl-tools__field select:hover,
.tpl-tools__field input[type="date"]:hover { border-color: #d8a6a9; }
.tpl-tools__field select:focus-visible,
.tpl-tools__field input[type="date"]:focus-visible { border-color: var(--navy-600); outline: 2px solid rgba(143, 20, 27, .18); outline-offset: 1px; }
.tpl-tools__actions { display: flex; align-items: center; gap: 7px; }
.tpl-filters-toggle { display: none; }
.tpl-filters-toggle__count {
  display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 4px;
  border-radius: 999px; background: var(--navy-600); color: #fff; font-size: 10.5px; font-weight: 750;
}
.tpl-filters-toggle__count[hidden] { display: none; }
.tpl-sheet { display: contents; }
.tpl-sheet-backdrop { display: none; }

.tpl-chips { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; justify-content: center; margin: 15px auto 0; max-width: 960px; }
.tpl-chips[hidden] { display: none; }
.tpl-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 9px 5px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  font: inherit; font-size: 12.5px; color: var(--ink-2); cursor: pointer;
}
.tpl-chip:hover { border-color: var(--navy-600); color: var(--navy-700); }
.tpl-chip::after { content: "\00d7"; font-size: 14px; line-height: 1; color: var(--navy-600); }
.tpl-chips__clear {
  border: 0; background: none; color: var(--navy-700); font: inherit; font-size: 12.5px;
  font-weight: 650; cursor: pointer; padding: 5px 4px;
}
.tpl-chips__clear:hover { text-decoration: underline; }

.tpl-browse { margin-top: 38px; }

/* Department carousel — one horizontal row of large stacked-preview cards.
   The whole card is the "view all" affordance (data-tpl-view-all-department
   in the view, handled in initTemplateLibrary), so there is no separate link. */
.tpl-dept-carousel { margin-bottom: 44px; }
.tpl-carousel { position: relative; margin-top: 16px; }
.tpl-carousel__track {
  display: flex; gap: 18px; overflow-x: auto; scroll-snap-type: x proximity;
  padding: 4px 2px 9px; margin: -4px -2px -9px;
  scrollbar-width: none;
}
.tpl-carousel__track::-webkit-scrollbar { display: none; }
.tpl-carousel__nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 5;
  display: grid; place-items: center; width: 44px; height: 44px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface); color: var(--navy-700);
  box-shadow: var(--shadow-2); cursor: pointer; transition: opacity .15s, border-color .15s;
}
.tpl-carousel__nav:hover { border-color: var(--navy-600); color: var(--navy-800); }
.tpl-carousel__nav:disabled { opacity: 0; pointer-events: none; }
.tpl-carousel__nav--prev { left: -22px; }
.tpl-carousel__nav--next { right: -22px; }
.tpl-carousel__nav .icon { width: 20px; height: 20px; }

.tpl-dept-card {
  flex: 0 0 260px; scroll-snap-align: start;
  display: flex; flex-direction: column; color: inherit; text-decoration: none;
}
.tpl-dept-card:hover, .tpl-dept-card:focus-visible { text-decoration: none; }
.tpl-dept-card:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 4px; border-radius: 16px; }

.tpl-dept-card__stack { position: relative; height: 190px; margin: 0 15px 25px; }
.tpl-dept-card__layer {
  position: absolute; inset: 0; display: grid; place-items: center;
  border-radius: 16px; border: 3px solid var(--surface); overflow: hidden;
  box-shadow: var(--shadow-1); transition: transform .2s ease;
}
.tpl-dept-card__layer--1 { transform: rotate(-9deg) translate(-22px, 12px); z-index: 1; }
.tpl-dept-card__layer--2 { transform: rotate(7deg) translate(20px, 8px); z-index: 2; }
.tpl-dept-card__layer--3 { transform: none; z-index: 3; box-shadow: var(--shadow-2); }
.tpl-dept-card:hover .tpl-dept-card__layer--1 { transform: rotate(-13deg) translate(-30px, 16px); }
.tpl-dept-card:hover .tpl-dept-card__layer--2 { transform: rotate(10deg) translate(28px, 10px); }
.tpl-dept-card:hover .tpl-dept-card__layer--3 { transform: translateY(-4px); }
.tpl-dept-card__layer-icon { width: 34px; height: 34px; opacity: .34; color: var(--navy-900); }
/* A real render of the template's first page — object-fit: cover so a tall
   page fills the (roughly square) layer like a photo in the stack, rather
   than floating in the middle of it the way the fallback icon does. Anchored
   to the top, since that is where a document's identity lives. */
.tpl-dept-card__thumb { width: 100%; height: 100%; object-fit: cover; object-position: top center; }

.tpl-dept-card__name { color: var(--navy-900); font-size: 15.5px; font-weight: 650; line-height: 1.3; }
.tpl-dept-card__count { margin-top: 3px; color: var(--ink-3); font-size: 13px; }

/* Format sections — a plain grid each, not a carousel. */
.tpl-format-section { margin-top: 38px; }
.tpl-format-section:first-of-type { margin-top: 0; }
.tpl-format-section__footer { display: flex; justify-content: center; margin-top: 21px; }
.tpl-format-section__footer .btn .icon { width: 15px; height: 15px; }

.tpl-results { margin-top: 38px; }
.tpl-results[hidden] { display: none; }
.tpl-results__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px; flex-wrap: wrap;
  margin-bottom: 18px; padding-bottom: 12px; border-bottom: 1px solid var(--line);
}
.tpl-results__head h2 { font-size: 20px; }
.tpl-results__head span { color: var(--ink-3); font-size: 13px; }

.tpl-empty {
  margin: 9px 0 27px; padding: 25px 16px; text-align: center;
  border: 1px dashed #d8a6a9; border-radius: var(--r-lg); background: var(--navy-050);
}
.tpl-empty[hidden] { display: none; }
.tpl-empty h3 { margin-bottom: 6px; }
.tpl-empty p { color: var(--ink-2); font-size: 13.5px; }
.tpl-empty .btn { margin-top: 12px; }

/* Card grid — large cards, up to 6 per row on very large screens. */
.tpl-grid { display: grid; gap: 21px; grid-template-columns: repeat(4, 1fr); }

/* Format sections get their own, bigger card at a fixed 3 per row — the
   .tpl-grid.tpl-grid--format specificity keeps this from being overridden by
   .tpl-grid's own width-based column counts below. */
.tpl-grid.tpl-grid--format { grid-template-columns: repeat(3, 1fr); gap: 24px; }

/* Card: one shape for every format. The preview area fakes a document
   without pretending to be a real thumbnail: a tinted plate sized to the
   page's own proportions (wide for a deck, tall for anything paginated,
   square for a sheet or an archive), plus the format's glyph. */
.tpl-card {
  display: block; color: inherit; text-decoration: none;
  border: 1px solid var(--line); border-radius: 16px; overflow: hidden;
  background: var(--surface); box-shadow: var(--shadow-1);
  transition: box-shadow .15s, transform .15s, border-color .15s;
}
.tpl-card:hover, .tpl-card:focus-visible {
  text-decoration: none; border-color: #eaacb0; box-shadow: var(--shadow-2); transform: translateY(-3px);
}
.tpl-card:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }

.tpl-card__preview {
  position: relative; aspect-ratio: 16 / 10; overflow: hidden;
  display: grid; place-items: center;
  background: var(--navy-050);
}
.tpl-card__preview--powerpoint { background: #f9e3da; }
.tpl-card__preview--word       { background: #f9e4e2; }
.tpl-card__preview--excel      { background: #f7e0dc; }
.tpl-card__preview--pdf        { background: #fbd7d9; }
.tpl-card__preview--other      { background: #f0e7e4; }

.tpl-card__page {
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .8); border-radius: 8px;
  box-shadow: 0 1px 3px rgba(74, 5, 9, .1);
}
.tpl-card__page-icon { width: 36px; height: 36px; opacity: .38; color: var(--navy-900); }
.tpl-card__page--landscape { width: 78%; aspect-ratio: 16 / 9; }
.tpl-card__page--portrait  { height: 84%; aspect-ratio: 3 / 4; }
.tpl-card__page--sheet     { width: 82%; height: 72%; }
.tpl-card__page--block     { width: 54%; aspect-ratio: 1 / 1; }

/* A real render of the file's first page, in place of the fake-page glyph
   above. Fills the preview box edge to edge — the same treatment the
   department stack's layers use — rather than floating in the middle of it
   with the tinted background showing through as a margin. */
.tpl-card__thumb {
  width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
  background: #fff;
}

.tpl-badge {
  position: absolute; top: 12px; left: 12px;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px; border-radius: 999px;
  font-size: 11px; font-weight: 800; letter-spacing: .03em;
  background: var(--navy-100); color: var(--navy-700);
}
.tpl-badge .icon { width: 12px; height: 12px; }
.tpl-badge--PPTX { background: #f9e3da; color: #9a4a25; }
.tpl-badge--DOCX { background: #f9e4e2; color: #a3382b; }
.tpl-badge--XLSX { background: #f7e0dc; color: #94402e; }
.tpl-badge--PDF  { background: #fbd7d9; color: #a80f18; }
.tpl-badge--ZIP  { background: #f0e7e4; color: #75574f; }
.tpl-badge--HTML { background: #f5e2e1; color: #8a3230; }

.tpl-card__hover {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 7px;
  background: rgba(43, 22, 24, .5); color: #fff; font-size: 13.5px; font-weight: 650;
  opacity: 0; transition: opacity .15s;
}
.tpl-card__hover .icon { width: 16px; height: 16px; }
.tpl-card:hover .tpl-card__hover, .tpl-card:focus-visible .tpl-card__hover { opacity: 1; }

.tpl-card__loading {
  position: absolute; inset: 0; z-index: 2;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 14px;
  background: rgba(43, 22, 24, .72); color: #fff;
  font-size: 13.5px; font-weight: 700; text-align: center;
  opacity: 0; visibility: hidden;
  transition: opacity .15s ease, visibility 0s linear .15s;
}
.tpl-card__loading .spinner {
  width: 20px; height: 20px; flex: none;
  border-width: 2px; border-top-color: #fff;
}
.tpl-card.is-preparing .tpl-card__loading {
  opacity: 1; visibility: visible;
  transition: opacity .15s ease;
}

.tpl-card__body { display: flex; flex-direction: column; gap: 5px; padding: 14px 15px 16px; }
.tpl-card__dept {
  color: var(--ink-3); font-size: 10.5px; font-weight: 750; letter-spacing: .06em; text-transform: uppercase;
}
.tpl-card__title { color: var(--navy-900); font-size: 15.5px; line-height: 1.35; }
.tpl-card__meta { display: flex; gap: 10px; flex-wrap: wrap; color: var(--ink-3); font-size: 13px; margin-top: 3px; }

/* The format sections' bigger card — same shape, more of everything. */
.tpl-card--lg { border-radius: 18px; }
.tpl-card--lg .tpl-card__page-icon { width: 46px; height: 46px; }
.tpl-card--lg .tpl-badge { padding: 5px 10px; font-size: 12px; }
.tpl-card--lg .tpl-badge .icon { width: 13px; height: 13px; }
.tpl-card--lg .tpl-card__hover { font-size: 14px; }
.tpl-card--lg .tpl-card__hover .icon { width: 18px; height: 18px; }
.tpl-card--lg .tpl-card__body { padding: 16px 18px 19px; gap: 6px; }
.tpl-card--lg .tpl-card__dept { font-size: 11.5px; }
.tpl-card--lg .tpl-card__title { font-size: 17.5px; }
.tpl-card--lg .tpl-card__meta { font-size: 14px; gap: 12px; margin-top: 4px; }

@media (min-width: 1560px) {
  .tpl-grid { grid-template-columns: repeat(6, 1fr); }
}

@media (max-width: 1180px) {
  .tpl-grid { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 900px) {
  .tpl-search { height: 58px; margin-top: 20px; }
  .tpl-dept-card { flex: 0 0 220px; }
  .tpl-dept-card__stack { height: 160px; }
}

@media (max-width: 820px) {
  .tpl-grid { grid-template-columns: repeat(2, 1fr); }
  .tpl-grid.tpl-grid--format { grid-template-columns: repeat(2, 1fr); gap: 24px; }
}

@media (max-width: 760px) {
  .tpl-filter-row { justify-content: flex-start; }
  .tpl-sheet { display: none; }
  .tpl-library.has-js .tpl-sheet {
    display: grid; gap: 12px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 70;
    max-height: 72vh; overflow: auto; padding: 20px 20px 26px;
    border-radius: 18px 18px 0 0;
    background: var(--surface); box-shadow: 0 -10px 40px rgba(43, 22, 24, .22);
    transform: translateY(105%); transition: transform .22s ease;
  }
  .tpl-library.has-js .tpl-sheet::before {
    content: ""; display: block; width: 44px; height: 4px; margin: 0 auto 6px;
    border-radius: 999px; background: var(--line);
  }
  .tpl-library.has-js .tpl-sheet.is-open { transform: translateY(0); }
  .tpl-library.has-js .tpl-sheet .tpl-tools__field { display: block; width: 100%; }
  .tpl-library.has-js .tpl-sheet .tpl-tools__field select,
  .tpl-library.has-js .tpl-sheet .tpl-tools__field input[type="date"] { width: 100%; }
  .tpl-filters-toggle { display: inline-flex; }
  .tpl-library.has-js.is-sheet-open .tpl-sheet-backdrop {
    display: block; position: fixed; inset: 0; z-index: 60; background: rgba(43, 22, 24, .35);
  }
  .tpl-carousel__nav { display: none; }
  .tpl-browse { margin-top: 40px; }
  .tpl-dept-carousel { margin-bottom: 44px; }
  .tpl-format-section { margin-top: 44px; }
  .tpl-results { margin-top: 44px; }
}

@media (max-width: 560px) {
  .tpl-grid { grid-template-columns: 1fr; }
  .tpl-grid.tpl-grid--format { grid-template-columns: 1fr; }
  .tpl-dept-card { flex: 0 0 78vw; }
}

@media (prefers-reduced-motion: reduce) {
  .tpl-card, .tpl-card__hover, .tpl-sheet, .tpl-search, .tpl-dept-card__layer, .tpl-carousel__nav { transition: none; }
  .tpl-card:hover, .tpl-dept-card:hover .tpl-dept-card__layer { transform: none; }
}

/* ==========================================================================
   Leadership & Management — whole-company organization map

   This is deliberately a wide set of operating lanes, not a pyramid. The
   leadership trunk establishes company authority once; the three lanes then
   preserve department context all the way down to teams and sample workers.
   ========================================================================== */

.leadership-page {
  --chart-line: #ddcfd0;
  --chart-line-strong: #cbb7b9;
  --chart-dot: #eadfe0;
  padding-bottom: 54px;
}

.org-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(112px, 160px)) minmax(240px, 1fr);
  align-items: center;
  gap: 0;
  margin-bottom: 19px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}
.org-summary > div {
  min-height: 52px;
  display: grid; align-content: center;
  padding: 10px 15px;
  border-right: 1px solid var(--line);
}
.org-summary strong {
  color: var(--navy-800);
  font-size: 20px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.org-summary span { margin-top: 6px; color: var(--ink-3); font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.org-summary > p { margin: 0; padding: 14px 16px; color: var(--ink-3); font-size: 12.5px; line-height: 1.5; }

.company-org {
  padding: clamp(15px, 2.4vw, 25px);
  border: 1px solid var(--line);
  border-radius: calc(var(--r) + 4px);
  background:
    radial-gradient(circle, var(--chart-dot) 1px, transparent 1.1px) 0 0 / 24px 24px,
    linear-gradient(180deg, #fefdfd, #faf7f7);
  box-shadow: var(--shadow-1);
}
.company-org__heading { margin-bottom: 24px; }
.company-org__heading .eyebrow { margin-bottom: 4px; color: var(--navy-600); }
.company-org__heading h2 { font-size: clamp(19px, 2vw, 23.5px); }
.org-department__head a:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }

.org-trunk { display: grid; justify-items: center; }
.org-person {
  position: relative;
  width: min(100%, 350px);
  padding: 13px 15px;
  border: 1px solid var(--line);
  border-top: 3px solid var(--org-accent, var(--navy-600));
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-1);
  text-align: center;
}
.org-person--governance { --org-accent: var(--navy-800); }
.org-person--chief { --org-accent: var(--navy-600); width: min(100%, 400px); }
.org-person__level,
.org-person__reports {
  display: block;
  color: var(--org-accent, var(--navy-600));
  font-size: 9.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
}
.org-person h3 { margin-top: 4px; font-size: 14px; }
.org-person p { margin: 2px 0 0; color: var(--ink-2); font-size: 12.5px; font-weight: 600; }
.org-person small { display: block; margin-top: 6px; color: var(--ink-3); font-size: 11.5px; line-height: 1.4; }
.org-person__reports { margin-top: 9px; padding-top: 7px; border-top: 1px solid var(--line-2); color: var(--ink-3); letter-spacing: .02em; text-transform: none; }

.org-connector { display: block; background: var(--chart-line-strong); }
.org-connector--vertical { width: 2px; height: 22px; }
.org-executives-wrap { position: relative; padding-top: 34px; }
.org-connector--drop {
  position: absolute; top: 0; left: 50%;
  width: 2px; height: 24px;
}
.org-executives-wrap::after {
  content: "";
  position: absolute; top: 23px; left: 10%; right: 10%;
  height: 2px; background: var(--chart-line-strong);
}
.org-executives {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(9px, 1.3vw, 15px);
}
.org-person--executive { width: auto; min-width: 0; padding: 12px; text-align: left; }
.org-person--executive::before {
  content: "";
  position: absolute; top: -27px; left: 50%;
  width: 2px; height: 25px; background: var(--chart-line-strong);
}

.org-tone--blue  { --org-accent: var(--tag-blue-fg);  --org-tint: var(--tag-blue-bg); }
.org-tone--teal  { --org-accent: var(--tag-teal-fg);  --org-tint: var(--tag-teal-bg); }
.org-tone--amber { --org-accent: var(--tag-amber-fg); --org-tint: var(--tag-amber-bg); }

.org-branch-divider { height: 58px; position: relative; }
.org-branch-divider::before {
  content: ""; position: absolute; top: 0; left: 50%;
  width: 2px; height: 28px; background: var(--chart-line-strong);
}
.org-branch-divider span {
  position: absolute; top: 27px; left: calc(16.6667% - 1px); right: calc(16.6667% - 1px);
  height: 2px; background: var(--chart-line-strong);
}

.org-branches {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(10px, 1.5vw, 18px);
  align-items: start;
}
.org-branch {
  position: relative;
  min-width: 0;
  scroll-margin-top: 92px;
}
.org-branch::before {
  content: ""; position: absolute; top: -31px; left: 50%;
  width: 2px; height: 31px; background: var(--chart-line-strong);
}
.org-department__label {
  margin: 0 0 3px;
  color: var(--org-accent);
  font-size: 9.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
}

.org-departments { display: grid; gap: 15px; }
.org-department {
  position: relative;
  min-width: 0;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: rgba(255, 255, 255, .96);
  box-shadow: var(--shadow-1);
}
.org-department::before {
  content: ""; position: absolute; top: -29px; left: 50%;
  width: 2px; height: 28px; background: var(--chart-line);
}
.org-department__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 9px; }
.org-department__head h4 { font-size: 14px; line-height: 1.35; }
.org-department__head h4 a { color: var(--navy-900); }
.org-department__head h4 a:hover { color: var(--org-accent); text-decoration: underline; }
.org-department__head .badge { flex: none; }

.org-manager {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  gap: 9px;
  margin-top: 12px;
  padding: 10px;
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--org-accent);
  border-radius: var(--r-sm);
  background: var(--org-tint);
}
.org-manager--director { background: var(--surface); }
.org-avatar {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--org-accent); color: #fff;
  font-size: 12px; font-weight: 800;
}
.org-manager strong { display: block; color: var(--ink); font-size: 12.5px; }
.org-manager span:not(.org-avatar) { display: block; color: var(--ink-2); font-size: 11px; line-height: 1.4; }
.org-manager em { color: var(--org-accent); font-size: 9px; font-style: normal; font-weight: 800; text-transform: uppercase; }
.org-manager small { display: block; margin-top: 4px; color: var(--ink-3); font-size: 10px; }
.org-department__stem { display: block; width: 2px; height: 10px; margin-inline: auto; background: var(--chart-line); }

.org-teams {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px;
  margin-top: 16px;
  padding-top: 15px;
  border-top: 2px solid var(--chart-line);
}
.org-team { position: relative; min-width: 0; padding: 10px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.org-team::before { content: ""; position: absolute; top: -20px; left: 50%; width: 2px; height: 18px; background: var(--chart-line); }
.org-team header > span { color: var(--org-accent); font-size: 8.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; }
.org-team h5 { margin: 1px 0 0; color: var(--navy-900); font-size: 12px; line-height: 1.35; }
.org-team__lead { display: grid; grid-template-columns: 27px minmax(0, 1fr); gap: 7px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line-2); }
.org-avatar--small { width: 27px; height: 27px; font-size: 10px; }
.org-team__lead p { margin: 0; }
.org-team__lead strong { display: block; font-size: 10.5px; }
.org-team__lead span, .org-team__lead small { display: block; color: var(--ink-3); font-size: 8.5px; line-height: 1.4; }

.org-workers { list-style: none; display: grid; gap: 5px; margin: 9px 0 0; padding: 0; }
.org-workers li { display: grid; grid-template-columns: 23px minmax(0, 1fr); gap: 7px; align-items: center; padding-top: 5px; border-top: 1px solid var(--line-2); }
.org-workers li > span { width: 23px; height: 23px; display: grid; place-items: center; border-radius: 50%; background: var(--line-2); color: var(--ink-2); font-size: 9px; font-weight: 800; }
.org-workers p { min-width: 0; margin: 0; line-height: 1.25; }
.org-workers strong { display: block; overflow-wrap: anywhere; font-size: 9.5px; }
.org-workers small { display: block; color: var(--ink-3); font-size: 8px; }

@media (max-width: 1180px) {
  .org-executives { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .org-executives-wrap::after,
  .org-person--executive::before { display: none; }
  .org-executives-wrap { padding-top: 22px; }
  .org-connector--drop { height: 28px; }
  .org-teams { grid-template-columns: minmax(0, 1fr); }
  .org-team + .org-team { margin-top: 7px; }
}

@media (max-width: 900px) {
  .org-summary { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .org-summary > div:nth-child(3) { border-right: 0; }
  .org-summary > p { grid-column: 1 / -1; border-top: 1px solid var(--line); }
  .org-executives { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .org-branches { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .org-branch-divider { height: 28px; }
  .org-branch-divider span { display: none; }
  .org-branch-divider::before { height: 28px; }
  .org-branch::before { display: none; }
  .org-departments { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
  .org-department::before { display: none; }
}

@media (max-width: 760px) {
  .leadership-page { padding-inline: 16px; }
  .org-summary { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .org-summary > div { min-height: 68px; padding-inline: 10px; text-align: center; }
  .org-summary strong { font-size: 21px; }
  .org-summary span { font-size: 9px; }
  .company-org { padding: 16px; }
  .org-executives { grid-template-columns: minmax(0, 1fr); }
  .org-person--executive { text-align: center; }
  .org-departments { grid-template-columns: minmax(0, 1fr); }
  .org-teams { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .org-team + .org-team { margin-top: 0; }
}

@media (max-width: 430px) {
  .org-summary { grid-template-columns: minmax(0, 1fr); }
  .org-summary > div { border-right: 0; border-bottom: 1px solid var(--line); }
  .org-summary > p { border-top: 0; }
  .org-teams { grid-template-columns: minmax(0, 1fr); }
  .org-team + .org-team { margin-top: 8px; }
}

/* Portrait organization chart. It deliberately mirrors the portrait, name and
   title treatment used in Welcome -> Meet NCIA while extending that visual
   language to every level below it.

   The chart draws three levels of the tree at a time — a root card, a row of
   its direct reports, and a row under each of those reports — and re-roots
   itself on the person whose team is opened. So there are only ever two rows
   to style, and every number below is written per row rather than per person:
   nothing here counts the seven directors, and nothing changes when there are
   eight of them.

   Two sets of sizes, one per view. Without .is-focused the chart is rooted at
   the top of the company and steps founder -> officer -> director; with it,
   it is rooted further down and steps director -> team lead -> employee. The
   card classes carry the typography for each of those five treatments; the
   widths, gaps and connector lengths all come from the --tier* variables
   below, which is what lets one row implementation serve both views. */
.leadership-page--portraits {
  --people-line: #dfd1d2;
  --people-card: clamp(122px, 10.4vw, 150px);
  --leadership-card: clamp(224px, 20vw, 270px);
  --people-gap: clamp(12px, 1.4vw, 22px);
}

.people-summary {
  display: flex; gap: 7px; flex-wrap: wrap;
  margin-bottom: 18px;
}
.people-summary span {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 7px 10px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--ink-3);
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
}
.people-summary strong { color: var(--navy-700); font-size: 14px; font-variant-numeric: tabular-nums; }

.portrait-org {
  --primary-gap: clamp(14px, 2vw, 26px);
  --reports-gap: 48px;

  /* Level 0 — the card the view is rooted at. */
  --tier0-card: var(--leadership-card);
  /* Level 1 — that person's direct reports. --drop is the stem down from the
     root card, --stub the drop from the connector bar to each card. */
  --tier1-card: var(--leadership-card);
  --tier1-gap: var(--primary-gap);
  --tier1-drop: 20px;
  --tier1-stub: 20px;
  /* Level 2 — a level-1 card's own direct reports. */
  --tier2-card: var(--people-card);
  --tier2-gap: var(--people-gap);
  --tier2-drop: var(--reports-gap);
  --tier2-stub: 26px;

  margin: 0;
  padding: clamp(15px, 2.5vw, 25px);
  /* deeper at the foot than the other three sides: the last row of cards
     carries controls below it, and they need to land inside the panel */
  padding-bottom: clamp(26px, 3.4vw, 38px);
  border: 1px solid var(--line);
  border-radius: calc(var(--r) + 4px);
  background:
    radial-gradient(circle, #f0e5e6 1.1px, transparent 1.2px) 0 0 / 24px 24px,
    linear-gradient(180deg, #fdfbfb, #faf6f6);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}
.portrait-org__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) max-content;
  column-gap: clamp(19px, 4vw, 44px);
  align-items: end;
  margin-bottom: 21px;
}
.portrait-org__head > .eyebrow,
.portrait-org__head > h1,
.portrait-org__head > [data-org-intro] { grid-column: 1; }
.portrait-org__head .eyebrow { margin-bottom: 4px; color: var(--navy-600); }
.portrait-org__head h1 { font-size: clamp(19px, 2vw, 23.5px); }
.portrait-org__head > [data-org-intro] { max-width: 720px; margin-top: 7px; color: var(--ink-3); font-size: 12.5px; }
.portrait-org__head .people-summary {
  grid-column: 2;
  grid-row: 1 / 4;
  justify-self: end;
  margin: 0;
}
.portrait-org__toolbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  min-height: 30px;
  margin: -7px 0 19px;
}
.portrait-org__toolbar[hidden] { display: none; }
.portrait-org__status { margin: 0; color: var(--ink-2); font-size: 12.5px; font-weight: 650; }
.portrait-org.is-transitioning { pointer-events: none; }

.people-card {
  position: relative;
  width: 100%;
  min-width: 0;
  overflow: hidden;
  border: 1px solid #eadfe0;
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--shadow-1);
  text-align: center;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.people-card:is(button) {
  display: block;
  padding: 0;
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}
.people-card:hover { border-color: #d3c1c3; box-shadow: var(--shadow-2); }
.people-card:is(button):hover { border-color: var(--navy-600); }
.people-card:is(button):focus-visible {
  z-index: 2;
  outline: 3px solid var(--navy-600);
  outline-offset: 3px;
}
.people-card__portrait {
  display: block;
  position: relative;
  width: 100%; aspect-ratio: 1;
  overflow: hidden;
  background: #fff;
}
.people-card__portrait img {
  display: block;
  width: 100%; height: 100%;
  object-fit: contain; object-position: center bottom;
}
/* No reserved height: a caption is as tall as its own words. Cards on a row
   still line up, because the row stretches them all to the tallest one — so
   the only blank under a name is what a longer name beside it needs, not
   room set aside for a chip the card may not carry. */
.people-card__caption {
  display: grid; align-content: start;
  padding: 7px 6px 9px;
  line-height: 1.3;
}
.people-card__caption strong { color: var(--ink); font-size: 11px; font-weight: 750; overflow-wrap: anywhere; }
.people-card__caption > span { margin-top: 3px; color: var(--ink-2); font-size: 9.5px; overflow-wrap: anywhere; }
.people-card__caption small {
  justify-self: center;
  margin-top: 6px; padding: 1px 6px;
  border-radius: 999px;
  background: var(--navy-050); color: var(--navy-600);
  font-size: 8px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
}
.people-card__caption .people-card__action {
  display: inline-flex; align-items: center; gap: 4px;
  justify-self: center;
  margin-top: 7px; padding: 1px 6px;
  border-radius: 999px;
  background: var(--navy-100); color: var(--navy-700);
  font-size: 8px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
}
/* Edit Mode turns the whole card into a set of controls, and a control
   cannot sit inside a button — so the chip that opened the team becomes the
   button instead, wearing exactly what the chip wore. */
.people-card__action--btn { border: 0; font-family: inherit; line-height: 1.3; cursor: pointer; }
.people-card__action--btn:hover { background: var(--navy-050); }
.people-card__action .icon { width: 10px; height: 10px; }
.people-card.is-mock .people-card__portrait { background: var(--navy-050); }
.people-card--founder,
.people-card--primary {
  display: grid;
  grid-template-columns: 108px minmax(0, 1fr);
  text-align: left;
}
.people-card--founder .people-card__portrait,
.people-card--primary .people-card__portrait {
  width: 108px;
  height: 108px;
  aspect-ratio: auto;
}
.people-card--founder .people-card__caption,
.people-card--primary .people-card__caption {
  min-height: 73px;
  align-content: center;
  padding: 10px;
}
.people-card--director { scroll-margin-top: 150px; }
.people-card--team-lead .people-card__caption,
.people-card--employee .people-card__caption { padding-inline: 4px; }
.people-card--team-lead .people-card__caption strong,
.people-card--employee .people-card__caption strong { font-size: 9.5px; }
.people-card--team-lead .people-card__caption > span,
.people-card--employee .people-card__caption > span { font-size: 8px; }
.people-card--team-lead .people-card__caption small,
.people-card--employee .people-card__caption small { font-size: 7px; }

/* ---- the tree ----------------------------------------------------------

   A branch is a person and, beneath them, the row of their own direct
   reports. Branches sit side by side on a row, each one exactly as wide as
   it needs to be, so a person is always centred over their own team and two
   teams can never grow into each other. That is the whole layout: a row of
   branches, and inside each branch another row of branches.

   Every measurement is per row, never per person. A track is a grid of
   content-width columns that centres itself, so nothing below counts the
   people on a row: the stem drops from the middle of the row, which is where
   the parent card centres itself, and the bar is measured off the first and
   last branch by layoutConnectors() in assets/js/app.js. The insets below
   are what the page draws before that runs, and without it.

   One scroller wraps the whole tree rather than one per row, so a chart too
   wide for the page scrolls as a piece and its lines stay joined. */
.portrait-org__tree {
  overflow-x: auto;
  overflow-y: hidden;
  /* the script sets an explicit height to match the scaled stage */
  /* Flex-centred rather than relying on the stage stretching to full width.
     The stage carries negative margins that trim its box back to what the
     scale actually paints, and a block box with a definite width answers a
     negative left margin by *moving* left, not by shrinking — which is what
     pushed a focused team's cards off-centre by exactly that margin. As a
     flex item the margins only shorten its outer size, and `safe center`
     centres that without clipping the left edge once a zoomed-in chart grows
     past the box. */
  display: flex;
  justify-content: safe center;
  align-items: flex-start;
  scrollbar-width: thin;
  /* Reserves room inside the scrolling box for what hangs past a card — the
     end note below it, the Edit Mode controls just outside its corners —
     without adding any of it to the page. The air belongs to the scroller
     rather than to the stage: --card-x below is measured from the stage's
     own edge, and a padding on the stage would put half a centimetre between
     that edge and the one a percentage in `left` resolves against. */
  padding: 0 9px 24px;
  /* Only the horizontal reserve is cancelled. The bottom one is real space:
     it is what the Edit Mode "+" control and the "No direct reports shown"
     note hang into, and pulling it back up with a negative margin left the
     deepest row of cards all but touching the panel's edge. */
  margin: 0 -9px 0;
}
.portrait-org__stage {
  position: relative;
  width: max-content;
  flex: none;
  /* The fit-to-view scale. The script writes --org-scale and the negative
     margin that goes with it: a transform paints smaller but still reserves
     its full width in the scroller, so the margin pulls the stage's *box* in
     to match what is actually drawn and the horizontal scrollbar disappears
     once the chart fits. Layout is untouched, which is what keeps
     layoutConnectors() — which measures offsetLeft, not screen rectangles —
     correct at every scale. */
  transform: scale(var(--org-scale, 1));
  transform-origin: top center;
}

/* ---- fit / zoom control -------------------------------------------------- */

.portrait-org { position: relative; }

/* Sticky, not pinned to the top of the chart: a deep team view is taller than
   the window, and a control that scrolls away is a control you have to scroll
   back up to reach. It rides the top of the scroller at every level of the
   tree. Above the focused view's "Back to leadership" bar (z-index 8), which
   sticks to the same edge on the opposite side. */
.portrait-org__zoom {
  position: sticky;
  top: 8px;
  z-index: 9;
  /* right-aligned without a float — a floated box does not stick reliably —
     and pulled back up by its own height so it overlays the chart's top
     corner instead of pushing the chart down a row */
  width: max-content;
  margin-left: auto;
  margin-right: 10px;
  margin-bottom: -30px;
  display: flex; align-items: center; gap: 2px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
.portrait-org__zoom[hidden] { display: none; }
.portrait-org__zoom-btn,
.portrait-org__zoom-level {
  display: grid; place-items: center;
  height: 24px;
  border: 0; border-radius: 999px;
  background: transparent; color: var(--ink-2);
  font: inherit; font-weight: 700;
  cursor: pointer;
}
.portrait-org__zoom-btn { width: 24px; font-size: 15px; line-height: 1; }
.portrait-org__zoom-level {
  min-width: 46px; padding: 0 6px;
  font-size: var(--ui-text-xs); font-variant-numeric: tabular-nums;
}
.portrait-org__zoom-btn:hover,
.portrait-org__zoom-level:hover { background: var(--navy-100); color: var(--navy-800); }
.portrait-org__zoom-btn:disabled { opacity: .35; cursor: default; background: transparent; }
.portrait-org__zoom-btn:focus-visible,
.portrait-org__zoom-level:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 1px; }

.portrait-tier { position: relative; display: flex; justify-content: center; }
.portrait-tier--root { width: var(--tier0-card); margin-inline: auto; }

.portrait-row { position: relative; padding-top: var(--org-drop); }
.portrait-row--t1 {
  --org-card: var(--tier1-card); --org-gap: var(--tier1-gap);
  --org-drop: var(--tier1-drop); --org-stub: var(--tier1-stub);
}
.portrait-row--t2 {
  --org-card: var(--tier2-card); --org-gap: var(--tier2-gap);
  --org-drop: var(--tier2-drop); --org-stub: var(--tier2-stub);
}
/* The stem drops from wherever the card above it sits, which is the middle
   of the row until layoutConnectors() works out something better — see
   assets/js/app.js, and --card-x below. */
.portrait-row::before {
  content: "";
  position: absolute; top: 0; left: calc(var(--stem-x, 50%) - 1px);
  width: 2px; height: var(--org-drop); background: var(--people-line);
}
.portrait-row__track {
  position: relative;
  display: grid; grid-auto-flow: column; grid-auto-columns: max-content;
  align-items: start;
  gap: var(--org-gap);
  width: max-content;
  margin-inline: auto;
  padding-top: var(--org-stub);
}
.portrait-row__track::before {
  content: "";
  position: absolute; top: 0;
  left: var(--bar-left, calc(var(--org-card) / 2));
  right: var(--bar-right, calc(var(--org-card) / 2));
  height: 2px; background: var(--people-line);
}
.portrait-branch {
  position: relative;
  display: grid; justify-items: center; align-content: start;
}
/* --card-x is where this branch's own card sits inside it: the middle until
   layoutConnectors() puts it over the middle of its children instead, which
   is what keeps a parent balanced between the people reporting to them.
   Unset — no script — it resolves to 50% and everything stays centred, which
   is right for every branch whose sides weigh the same. */
.portrait-branch > .portrait-node {
  position: relative;
  left: calc(var(--card-x, 50%) - 50%);
  width: var(--org-card);
}
.portrait-org__stage > .portrait-tier--root {
  position: relative;
  left: calc(var(--card-x, 50%) - 50%);
}
.portrait-row__track > .portrait-branch::before {
  content: "";
  position: absolute; top: calc(var(--org-stub) * -1); left: calc(var(--card-x, 50%) - 1px);
  width: 2px; height: var(--org-stub); background: var(--people-line);
}
.portrait-node { position: relative; min-width: 0; }
.portrait-node__end {
  position: absolute;
  top: calc(100% + 7px);
  left: 0;
  width: 100%;
  display: block;
  color: var(--ink-3); font-size: 9px; font-weight: 750;
  letter-spacing: .05em; text-align: center; text-transform: uppercase;
}

/* A team view: the same two rows at the three smaller card treatments. */
.portrait-org.is-focused {
  --tier0-card: var(--people-card);
  --tier1-card: 146px;
  --tier1-gap: 24px;
  --tier1-drop: 48px;
  --tier1-stub: 22px;
  --tier2-card: clamp(104px, 9vw, 128px);
  --tier2-gap: 10px;
  --tier2-drop: 28px;
  --tier2-stub: 16px;
}
.portrait-org.is-focused .portrait-org__toolbar {
  position: sticky;
  top: 70px;
  z-index: 8;
  width: max-content;
  max-width: 100%;
  padding: 7px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .94);
  box-shadow: var(--shadow-1);
}
/* The rows a team view opens with arrive rather than appear — the same
   entrance the department view has always used. is-revealed is added once
   the card that was clicked has finished morphing into its new place. */
.portrait-org.is-focused .portrait-org__stage > .portrait-row {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .3s ease, transform .38s cubic-bezier(.2, .8, .2, 1);
}
.portrait-org.is-focused.is-revealed .portrait-org__stage > .portrait-row { opacity: 1; transform: none; }

/* ---- Edit Mode: the controls on a card ---------------------------------

   Only rendered for an administrator with the switch on, so with it off the
   chart is exactly the cards and the lines. Both controls sit over the card
   rather than beside it, which is what keeps a row's spacing — and so every
   connector — identical whether or not anyone is editing. */
.portrait-node__add,
.portrait-node__remove {
  position: absolute;
  z-index: 3;
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  padding: 0;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface);
  cursor: pointer;
  box-shadow: var(--shadow-1);
}
.portrait-node__add { right: -7px; bottom: -7px; color: var(--navy-700); }
.portrait-node__remove { right: -7px; top: -7px; margin: 0; color: var(--ink-3); }
.portrait-node__add:hover { background: var(--navy-100); border-color: var(--navy-600); }
.portrait-node__remove:hover { background: var(--tag-red-bg); color: var(--tag-red-fg); }
.portrait-node__add .icon,
.portrait-node__remove .icon { width: 12px; height: 12px; }

/* Click the portrait to replace it — the same control the Culture and Social
   Media pages use, sized for a card. */
.people-card__photo {
  position: absolute; inset: auto 0 0 0;
  z-index: 2;
  display: flex; justify-content: center;
  padding: 4px;
  cursor: pointer;
}
.people-card__photo > span {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 7px;
  border-radius: 999px;
  background: rgba(23, 33, 56, .82); color: #fff;
  font-size: 8px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
}
.people-card__photo:hover > span { background: var(--navy-700); }
.people-card__photo .icon { width: 9px; height: 9px; }

@media (max-width: 1180px) {
  .leadership-page--portraits { --people-card: clamp(108px, 10.5vw, 132px); --people-gap: 10px; }
  .people-card__caption strong { font-size: 10px; }
  .people-card__caption > span { font-size: 8.5px; }
}

@media (max-width: 900px) {
  .leadership-page--portraits { --people-card: 146px; }
  .portrait-org__head { display: block; }
  .portrait-org__head .people-summary {
    width: 100%;
    justify-self: stretch;
    margin-top: 16px;
  }
  /* The two wide cards become portrait cards at this width, so the first two
     levels take the same width as the third. */
  .portrait-org { --tier0-card: var(--people-card); --tier1-card: var(--people-card); }
  .people-card--founder,
  .people-card--primary {
    display: block;
    text-align: center;
  }
  .people-card--founder .people-card__portrait,
  .people-card--primary .people-card__portrait {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
  }
  .people-card--founder .people-card__caption,
  .people-card--primary .people-card__caption {
    min-height: 72px;
    align-content: start;
    padding: 8px 6px 10px;
  }
}

@media (max-width: 640px) {
  .leadership-page--portraits { --people-card: min(142px, calc((100vw - 76px) / 2)); }
  .people-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .people-summary span {
    min-width: 0;
    justify-content: center;
    flex-wrap: wrap;
    padding-inline: 6px;
    font-size: 8px;
    text-align: center;
  }
  .portrait-org { padding: 16px; --tier1-gap: 12px; --tier2-gap: 10px; }
  .people-card--team-lead .people-card__caption strong,
  .people-card--employee .people-card__caption strong { font-size: 10px; }
  .people-card--team-lead .people-card__caption > span,
  .people-card--employee .people-card__caption > span { font-size: 8.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .people-card,
  .portrait-org.is-focused .portrait-org__stage > .portrait-row { transition: none; }
}

/* ==========================================================================
   Edit Mode — the administrator's in-place editing

   Everything below is scoped to .is-edit-mode, and the markup it styles is
   only emitted for an administrator with the switch on. With it off there
   is neither the class nor the markup, so the pages are untouched.

   The editable fields are marked with an outline rather than a border:
   outlines sit outside the layout, so turning Edit Mode on does not move
   anything by a pixel.
   ========================================================================== */

.iconbtn--edit[aria-pressed="true"] {
  background: var(--navy-050);
  border-color: #edb9bc;
  color: var(--navy-700);
}

/* The HUD sizes every iconbtn to a 40px circle; this one carries a label. */
.mapchrome .iconbtn--edit { width: auto; padding: 0 10px; }

.is-edit-mode [data-edit-key] {
  outline: 1px dashed #d8a6a9;
  outline-offset: 3px;
  border-radius: var(--r-sm);
}
.is-edit-mode [data-edit-key]:hover {
  outline-color: var(--navy-600);
  background: var(--navy-050);
}
.is-edit-mode [data-edit-key]:focus {
  outline: 2px solid var(--navy-600);
  outline-offset: 3px;
  background: var(--surface);
}

/* An empty inline field (a freshly added row) collapses to zero size, so
   its dashed outline never draws — nothing on screen shows there is
   something to click into. Giving it an inline-block box and a min-width
   keeps the outline visible until the administrator types. */
.is-edit-mode [data-edit-key]:empty {
  display: inline-block;
  min-width: 140px;
  min-height: 1.4em;
}
.is-edit-mode [data-edit-key]:empty::before {
  content: 'Click to add…';
  color: var(--ink-3);
  font-style: italic;
}

/* The type pill becomes the control, so it keeps the badge's own colours
   and only gains a caret. */
.badge-select {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  padding-right: 15px;
  font: inherit;
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: .01em;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5'%3E%3Cpath d='M1 1l3 3 3-3' fill='none' stroke='%23635456' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 6px center;
}
.badge-select:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 1px; }

/* Reading time: a number and a unit, sized to sit inline in a row rather
   than in a filter bar. Follows the .bookshelf-field select recipe. */
.edit-duration { display: inline-flex; align-items: center; gap: 5px; vertical-align: middle; }
.edit-duration__n,
.edit-duration__u {
  min-height: 18px;
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 12.5px;
}
.edit-duration__n { width: 56px; }
.edit-duration__n:hover,
.edit-duration__u:hover { border-color: #d8a6a9; }
.edit-duration__n:focus-visible,
.edit-duration__u:focus-visible {
  border-color: var(--navy-600);
  outline: 2px solid rgba(143, 20, 27, .18);
  outline-offset: 1px;
}

/* While editing, a listing row is a box rather than one big link, so the
   controls in it are reachable. It has to lay out exactly as before. */
.list__row--edit { cursor: default; }
.list__rowlink {
  display: flex;
  flex: 1;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}
.list__rowlink:hover { text-decoration: none; }

/* Remove and add */
.is-edit-mode .edit-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-left: 7px;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
  vertical-align: middle;
}
.is-edit-mode .edit-remove:hover { background: var(--tag-red-bg); color: var(--tag-red-fg); }
.is-edit-mode .edit-remove .icon { width: 13px; height: 13px; }
.is-edit-mode .article-qa__item { position: relative; }
.is-edit-mode .article-qa__item .edit-remove { position: absolute; top: 0; right: 0; margin: 0; }
.is-edit-mode .edit-add { margin-top: 10px; }
/* .edit-remove sets its own display, which otherwise beats the [hidden]
   attribute's UA rule on specificity — the departments dialog's repeater
   rows toggle this while there is only one row left to remove. */
.is-edit-mode .edit-remove[hidden] { display: none; }

/* The "Add New Department" dialog's two section labels (Section 1: the
   wall entry; Section 2: the department page) and its two repeaters —
   Responsibilities (one field per row) and FAQs (a question/answer pair
   per row). Both repeaters are composed entirely client-side before the
   form ever submits, so they borrow .libfield's own input styling and only
   add the row layout — a field (or two) beside the same .edit-remove used
   everywhere else a row can be taken back out. */
.is-edit-mode .deptdialog__section {
  margin: 0;
  padding-top: 12px;
  border-top: 1px solid var(--line-2);
  font-size: 13px;
  font-weight: 700;
  color: var(--navy-900);
}
.is-edit-mode .deptdialog__section:first-of-type { padding-top: 0; border-top: 0; }
.is-edit-mode .deptrepeat { display: grid; gap: 7px; }
.is-edit-mode .deptrepeat-row { display: flex; align-items: center; gap: 7px; }
.is-edit-mode .deptrepeat-row .edit-remove { flex: none; margin-left: 0; }
.is-edit-mode .deptrepeat-row--faq { align-items: flex-start; }
.is-edit-mode .deptrepeat-row--faq .edit-remove { margin-top: 8px; }
.is-edit-mode .deptrepeat-row__fields { flex: 1; min-width: 0; display: grid; gap: 6px; }

/* Step 2's dynamic rows. The cards keep their exact layout — the remove
   button floats at the card's corner instead of adding a control row. */
.is-edit-mode .company-timeline__card { position: relative; }
.is-edit-mode .company-timeline__item .edit-remove {
  position: absolute; top: 8px; right: 8px; margin: 0; z-index: 2;
}
.is-edit-mode .waterfall__card { position: relative; }
.is-edit-mode .waterfall__card .edit-remove {
  position: absolute; top: 12px; right: 12px; margin: 0;
}
.is-edit-mode .waterfall__card .edit-remove + * { padding-right: 0; }
.is-edit-mode .waterfall__card strong,
.is-edit-mode .waterfall__card p { padding-right: 16px; }

/* The org chart's department rows become editable name lines rather than
   links, wearing the same row and border the links use when the mode is
   off, so the card's rhythm does not change. */
.is-edit-mode .org-group__depts li { position: relative; }
.is-edit-mode .org-group__deptname {
  display: flex; align-items: center; justify-content: space-between; gap: 7px;
  padding: 7px 0; border-bottom: 1px solid var(--line-2);
  color: var(--ink); font-size: 13.5px; font-weight: 600;
}
.is-edit-mode .org-group__depts li:last-child .org-group__deptname { border-bottom: 0; }
.is-edit-mode .org-group__depts li .edit-remove {
  position: absolute; top: 50%; right: 0; margin: 0; transform: translateY(-50%);
}
.is-edit-mode .org-group__depts li .org-group__deptname { padding-right: 21px; }

/* The "+ Add Department" title row that appears inside the group card. */
.is-edit-mode .org-group__adddept {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 0; border-bottom: 1px solid var(--line-2);
}
.is-edit-mode .org-group__adddept input {
  flex: 1; min-width: 0;
  min-height: 22px; padding: 3px 7px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 13px;
}
.is-edit-mode .org-group__adddept input:focus-visible {
  border-color: var(--navy-600);
  outline: 2px solid rgba(143, 20, 27, .18);
  outline-offset: 1px;
}
.is-edit-mode .org-group__adddept-cancel {
  --iconbtn-size: 28px;
  width: 28px; height: 28px;
}

/* Step 5's editable rows: the KPI table and the meeting rhythm list. Both
   keep their read-mode layout — the remove button floats at the row's edge
   instead of adding a column or a control row. */
.is-edit-mode table.data td { position: relative; }
.is-edit-mode table.data tr .edit-remove {
  position: absolute; top: 50%; right: 4px; margin: 0; transform: translateY(-50%);
}
.is-edit-mode table.data tr td:last-child { padding-right: 24px; }

.meeting-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 14px; border-bottom: 1px solid var(--line-2);
  position: relative;
}
.meeting-row:last-child { border-bottom: 0; }
.meeting-row__name { font-weight: 600; font-size: 13.5px; color: var(--navy-800); }
.meeting-row__rhythm { color: var(--ink-3); font-size: 13.5px; text-align: right; }
.is-edit-mode .meeting-row { padding-right: 25px; }
.is-edit-mode .meeting-row .edit-remove {
  position: absolute; top: 50%; right: 4px; margin: 0; transform: translateY(-50%);
}

/* The saving / saved tell. Fixed, so it never affects the layout and is
   visible whether the edit happened on the page or in the modal. */
.edit-status {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 90;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  color: var(--ink-2);
  font-size: 13px;
}
.edit-status.is-error { border-color: var(--tag-red-fg); color: var(--tag-red-fg); }
.edit-status .spinner { width: 14px; height: 14px; border-width: 2px; }

/* --------------------------------------------------------------------------
   Rich text — the Quill surface behind an editable field

   Quill's Snow theme is loaded from assets/vendor/quill/, and everything
   below is the bridge between its markup and this stylesheet's tokens: the
   theme draws a grey-blue Bootstrap-ish chrome by default, which would be
   the one thing on the page not wearing the brand.

   Two rules run through all of it:

     · the editing surface must keep the typography it inherited. Quill
       sets its own font-size and line-height on .ql-editor, so those are
       given back to `inherit` — an <h2> being edited has to look like the
       <h2> it is, which is the property the plaintext-only contenteditable
       had and the reason the fields were built in place.

     · nothing may move when Edit Mode comes on. The toolbar is absolutely
       fixed at the viewport edge rather than stacked in the flow, so a
       page in Edit Mode has the same layout as a page without it.

   Read mode never sees any of this: the markup only exists while an
   administrator has the switch on.
   -------------------------------------------------------------------------- */

.richtext { position: relative; }

/* The field the editor replaced keeps its box in the layout, so the
   surrounding spacing is unchanged; it is the hidden original that holds
   data-edit-key for the save path. */
.is-edit-mode [data-edit-rich][hidden] { display: none; }

/* A resize is content layout, not temporary editor chrome. The server emits
   the saved dimensions in both modes and app.js applies them; these guards
   keep a desktop size inside its current responsive container. */
[data-edit-layout] {
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
}

/* The surface itself wears the page's own classes (rich-text.js copies
   them across), so it inherits the type it is standing in for. */
/* The editing surface keeps the page's own type.

   Quill puts .ql-container on the element it is given — which here is the
   surface, already wearing the page's classes (.article-prose at 16px, or
   .small .muted on a step's blurb at 12px). Its theme sets
   `.ql-container { font-size: 13px }` on that same element, so without a
   stronger rule every field is flattened to 13px whatever the page says:
   a prose body shrinks, a small blurb grows, and the paragraph gap — set
   in em, and so measured against this — comes out wrong in both.

   Leaving the size undeclared does not work either: Quill's stylesheet is
   appended to <head> at runtime, so it comes *after* this file, and at
   equal specificity the later rule wins — .article-prose is one class and
   so is .ql-container. The declaration has to be made here, on a selector
   carrying more class names than Quill's, and it has to name a real
   length rather than a keyword (`inherit` takes the shell's size and
   ignores the classes on this element; `revert` drops to the browser
   default — both flattened every field to the 13.5px body size).

   So each size is restated once, matched to the class the surface wears.
   Two entries, because the fields are two shapes: prose, and the small
   meta copy a step's blurb is set in. */
.richtext .richtext__surface.ql-container {
  border: 0;
}
.richtext .richtext__surface.article-prose {
  font-size: 16px;
  line-height: 1.75;
}
.richtext .richtext__surface.small {
  font-size: var(--ui-text-sm);
}
.richtext .ql-editor {
  padding: 0;
  /* Inherited from the surface, which carries the page's own classes —
     see the .ql-container rule above. Quill sets line-height:1.42 on
     .ql-editor, so that one does have to be taken back explicitly; the
     size is simply left alone. */
  line-height: inherit;
  color: inherit;
  outline: 1px dashed #d8a6a9;
  outline-offset: 3px;
  border-radius: var(--r-sm);
  min-height: 1.4em;
  /* A pasted URL or an unbroken string must not push the column wider
     than the layout allows. */
  overflow-wrap: break-word;
  word-break: break-word;
}
.is-edit-mode .richtext--full .ql-editor {
  min-height: 1.4em;
  max-height: min(60vh, 480px);
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  overflow: auto;
  resize: both;
}
/* Accordion rows size to their own content, so a second resize handle on the
   editor inside would compete with the panel's own expand/collapse. */
.is-edit-mode .cover-accordion .richtext--full .ql-editor {
  resize: none;
  max-height: none;
  overflow-y: visible;
}
.richtext .ql-editor:hover { outline-color: var(--navy-600); background: var(--navy-050); }
.richtext .ql-editor:focus {
  outline: 2px solid var(--navy-600);
  outline-offset: 3px;
  background: var(--surface);
}
.richtext .ql-editor.ql-blank::before {
  left: 0; right: 0;
  color: var(--ink-3);
  font-style: italic;
}

/* Paragraph rhythm: proportional to the text, not a fixed pixel count.

   A paragraph carries no gap of its own, in the editor or on the page.
   Enter is how a new line is made here — the line-height is the whole of
   the separation, so what the administrator types is what the reader gets.
   Earlier this was a 14px gap in read mode and half of that while typing;
   both read as a blank line had been inserted, and the two differing meant
   a field never looked the way it would publish.

   The rule is declared here rather than left to the page because
   .article-prose > p only matches a *direct child* of .article-prose, and
   inside the editor the paragraphs are children of .ql-editor. */
.richtext .ql-editor > p { margin: 0; }
.richtext .ql-editor > p:last-child { margin-bottom: 0; }

/* Quill draws its own list marker through .ql-ui and its own counter, and
   the surface wears .article-prose — which already draws a marker of its
   own (a dot, and decimal-leading-zero numbers in the brand red). Left
   alone the two stack up. Quill's is the one that gives way, so what is
   being edited looks exactly like what will be read.

   Scoped to .ql-editor's own list items rather than to li::before, so the
   page's marker is untouched: it is the same selector that draws the
   marker in read mode. */
.richtext .ql-editor li > .ql-ui { display: none; }
.richtext .ql-editor ol,
.richtext .ql-editor ul { padding-left: 0; counter-reset: article-ol; }

/* The box the marker is positioned against. .article-prose sets this on
   its own items, but the editor attaches to fields that are not prose —
   a step's blurb, a note body — and there the marker had nothing to
   anchor to. Same values, so a prose list is unchanged. */
.richtext .ql-editor li { position: relative; padding-left: 21px; }

/* Quill 2 writes *every* list as <ol> and tells the two apart with
   data-list on the item — so inside the editor a bulleted item is an
   <ol><li data-list="bullet">, and .article-prose's ol > li::before
   counter would number it. Read mode never sees this: what is stored is a
   real <ul> (getSemanticHTML() converts it back), so this correction is
   needed only while the editor is open.

   Bulleted items get the dot .article-prose draws for a <ul>, and
   numbered ones keep the page's own counter — which has to be restarted
   here, since it is now being driven from the item rather than the list. */
/* The page increments its counter on ol > li, which inside the editor is
   every item of either kind — so an ordered item is numbered by its
   position among *all* of them. Both are corrected here: a bullet stops
   counting, and an ordered item counts on its own, which is what makes a
   list that follows bullets start at 01 again. */
.richtext .ql-editor li[data-list="bullet"] { counter-increment: none; }
.richtext .ql-editor li[data-list="ordered"] { counter-increment: article-ol; }
.richtext .ql-editor li[data-list="bullet"]::before {
  content: "";
  position: absolute; left: 4px; top: .68em;
  width: 6px; height: 6px; border-radius: 50%;
  background: #e0bcbf;
}

/* The number is drawn here rather than left to the page.

   .article-prose supplies `ol > li::before { content: counter(...) }`, but
   it is the only field that does — a step's blurb is .small, a note body
   is neither, and in those the marker was hidden with .ql-ui above and
   nothing took its place, so a numbered list simply lost its numbers while
   being edited. Restating the page's own marker here makes the editor
   correct in every field it can be attached to, whatever classes that
   field happens to wear.

   Matches .article-prose's design exactly: decimal-leading-zero in the
   brand red, tabular figures so 01 and 10 occupy the same width. */
.richtext .ql-editor li[data-list="ordered"]::before {
  content: counter(article-ol, decimal-leading-zero);
  position: absolute; left: 0; top: 0;
  color: var(--navy-600);
  font-size: 12.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 2.1;
}

/* ---- the toolbar ---- */

.richtext .ql-toolbar.ql-snow {
  position: absolute;
  bottom: calc(100% + 8px);
  left: -6px;
  z-index: 40;
  display: none;
  flex-wrap: wrap;
  align-items: center;
  gap: 1px;
  max-width: min(560px, calc(100vw - 32px));
  padding: 5px 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  font-family: var(--font);
}

/* Shown for the current editor only, so a page in Edit Mode is not a wall
   of toolbars. The active shell is managed by rich-text.js and remains the
   owner until another editable field is deliberately clicked or focused. */
.richtext--toolbar-active { z-index: 60; }
.richtext--toolbar-active .ql-toolbar.ql-snow { display: flex; }

/* A field near the top of the scroller has no room above it. Dead in
   practice today — every toolbar floats (richtext--floating-editor is added
   unconditionally in rich-text.js) — but kept for a future non-floating
   editor rather than deleted. */
.richtext--flip .ql-toolbar.ql-snow { bottom: auto; top: calc(100% + 8px); }

/* ---- the floating toolbar, portaled to <body> ----

   rich-text.js moves the toolbar out of its field and onto document.body
   the moment its shell becomes active (activateShell()/portalToolbar()),
   so it always paints in the root stacking context. Before this it stayed a
   descendant of the field, which meant a card with its own z-index — the
   About nav cards' arrow button is the confirmed case — could paint over it
   even though the toolbar itself carried a very high z-index: that z-index
   only ever won *inside* the field's own stacking context, never against a
   sibling that out-stacked the field as a whole.

   Once portaled, the toolbar is no longer a .richtext descendant, so its
   appearance and visibility cannot rely on the .richtext-scoped rules above
   — both are restated here instead. z-index: 600 clears every real overlay
   in this app: the header (200/500 — see the top of this file), the section
   modal (250, .modal), fullscreen overlays (400) and the About takeover
   transition (500), since rich-text fields are edited inside all of them. */
.ql-toolbar.ql-snow.richtext-toolbar--floating {
  display: none;
  position: fixed;
  z-index: 600;
  flex-wrap: wrap;
  align-items: center;
  gap: 1px;
  max-width: min(560px, calc(100vw - 32px));
  padding: 5px 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  font-family: var(--font);
  pointer-events: auto;
}
.ql-toolbar.ql-snow.richtext-toolbar--floating.richtext-toolbar--active { display: flex; }

.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-formats {
  display: inline-flex;
  align-items: center;
  margin: 0 3px 0 0;
  padding-right: 3px;
  border-right: 1px solid var(--line-2);
}
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-formats:last-child { border-right: 0; margin-right: 0; }

.ql-toolbar.ql-snow.richtext-toolbar--floating button {
  width: 26px; height: 26px;
  padding: 4px;
  border-radius: var(--r-sm);
  color: var(--ink-2);
}
.ql-toolbar.ql-snow.richtext-toolbar--floating button:hover { background: var(--navy-050); }
.ql-toolbar.ql-snow.richtext-toolbar--floating button.ql-active { background: var(--navy-100); }

.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-stroke { stroke: var(--ink-2); }
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-fill { fill: var(--ink-2); }
.ql-toolbar.ql-snow.richtext-toolbar--floating button:hover .ql-stroke,
.ql-toolbar.ql-snow.richtext-toolbar--floating button.ql-active .ql-stroke,
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker-label:hover .ql-stroke { stroke: var(--navy-600); }
.ql-toolbar.ql-snow.richtext-toolbar--floating button:hover .ql-fill,
.ql-toolbar.ql-snow.richtext-toolbar--floating button.ql-active .ql-fill,
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker-label:hover .ql-fill { fill: var(--navy-600); }

.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker { height: 26px; color: var(--ink-2); font-size: 12.5px; }
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker-label { padding: 0 16px 0 6px; border-radius: var(--r-sm); border: 0; }
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker-label:hover { background: var(--navy-050); color: var(--navy-600); }
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker.ql-expanded .ql-picker-label { border: 0; background: var(--navy-050); }
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker-options {
  padding: 4px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--shadow-2);
}
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker-item { padding: 4px 7px; border-radius: var(--r-sm); color: var(--ink-2); }
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker-item:hover { background: var(--navy-050); color: var(--navy-600); }
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-picker-item.ql-selected { color: var(--navy-600); }

.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-color-picker .ql-picker-options { width: 160px; padding: 5px; }
.ql-toolbar.ql-snow.richtext-toolbar--floating .ql-color-picker .ql-picker-item { width: 17px; height: 17px; margin: 1px; border-radius: 3px; }

.richtext .ql-toolbar.ql-snow .ql-formats {
  display: inline-flex;
  align-items: center;
  margin: 0 3px 0 0;
  padding-right: 3px;
  border-right: 1px solid var(--line-2);
}
.richtext .ql-toolbar.ql-snow .ql-formats:last-child { border-right: 0; margin-right: 0; }

.richtext .ql-toolbar.ql-snow button {
  width: 26px; height: 26px;
  padding: 4px;
  border-radius: var(--r-sm);
  color: var(--ink-2);
}
.richtext .ql-toolbar.ql-snow button:hover { background: var(--navy-050); }
.richtext .ql-toolbar.ql-snow button.ql-active { background: var(--navy-100); }

/* The theme colours its icons with hard-coded hex; the tokens win. */
.richtext .ql-snow .ql-stroke { stroke: var(--ink-2); }
.richtext .ql-snow .ql-fill { fill: var(--ink-2); }
.richtext .ql-snow button:hover .ql-stroke,
.richtext .ql-snow button.ql-active .ql-stroke,
.richtext .ql-snow .ql-picker-label:hover .ql-stroke { stroke: var(--navy-600); }
.richtext .ql-snow button:hover .ql-fill,
.richtext .ql-snow button.ql-active .ql-fill,
.richtext .ql-snow .ql-picker-label:hover .ql-fill { fill: var(--navy-600); }

/* The dropdowns (heading, size, alignment). */
.richtext .ql-snow .ql-picker { height: 26px; color: var(--ink-2); font-size: 12.5px; }
.richtext .ql-snow .ql-picker-label { padding: 0 16px 0 6px; border-radius: var(--r-sm); border: 0; }
.richtext .ql-snow .ql-picker-label:hover { background: var(--navy-050); color: var(--navy-600); }
.richtext .ql-snow .ql-picker.ql-expanded .ql-picker-label { border: 0; background: var(--navy-050); }
.richtext .ql-snow .ql-picker-options {
  padding: 4px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--shadow-2);
}
.richtext .ql-snow .ql-picker-item { padding: 4px 7px; border-radius: var(--r-sm); color: var(--ink-2); }
.richtext .ql-snow .ql-picker-item:hover { background: var(--navy-050); color: var(--navy-600); }
.richtext .ql-snow .ql-picker-item.ql-selected { color: var(--navy-600); }

/* The two colour pickers open a swatch grid, which the theme sizes for a
   wider toolbar than this one. */
.richtext .ql-snow .ql-color-picker .ql-picker-options { width: 160px; padding: 5px; }
.richtext .ql-snow .ql-color-picker .ql-picker-item { width: 17px; height: 17px; margin: 1px; border-radius: 3px; }

/* The link tooltip. */
.richtext .ql-snow .ql-tooltip {
  z-index: 50;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  color: var(--ink-2);
  font-family: var(--font);
  font-size: 12.5px;
}
.richtext .ql-snow .ql-tooltip input[type="text"] {
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 4px 7px;
  font-family: inherit;
  font-size: 12.5px;
  color: var(--ink);
}
.richtext .ql-snow .ql-tooltip input[type="text"]:focus-visible {
  border-color: var(--navy-600);
  outline: 2px solid rgba(143, 20, 27, .18);
  outline-offset: 1px;
}
.richtext .ql-snow .ql-tooltip a.ql-action,
.richtext .ql-snow .ql-tooltip a.ql-remove { color: var(--navy-600); }

/* A one-line field's editor must not become a text area: no wrapping to a
   second line, and the toolbar carries no block formats to make one with. */
.richtext--inline .ql-editor { white-space: nowrap; overflow-x: auto; }
.richtext--inline .ql-editor::-webkit-scrollbar { height: 0; }

/* Phones: the toolbar is the one thing here that cannot simply shrink, so
   it spans the field and scrolls sideways rather than wrapping into a
   stack that would cover the text being edited. */
@media (max-width: 720px) {
  .richtext .ql-toolbar.ql-snow,
  .ql-toolbar.ql-snow.richtext-toolbar--floating {
    left: 0;
    max-width: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .richtext .ql-toolbar.ql-snow::-webkit-scrollbar,
  .ql-toolbar.ql-snow.richtext-toolbar--floating::-webkit-scrollbar { height: 0; }
  .richtext .ql-toolbar.ql-snow .ql-formats,
  .ql-toolbar.ql-snow.richtext-toolbar--floating .ql-formats { flex: 0 0 auto; }
}

/* --------------------------------------------------------------------------
   Rich text — reading

   What an administrator formatted has to render the same way wherever it
   is read, without letting a pasted style break the column it sits in.
   Scoped to the elements that carry stored content rather than applied
   globally, so nothing outside the editable fields is touched.
   -------------------------------------------------------------------------- */

/* Nothing is restated for .article-prose's own lists. It already styles
   ul/ol with list-style:none and its own ::before markers (the numbered
   ones are decimal-leading-zero in the brand red) — a list the editor
   writes is the same markup that section always used, so it inherits that
   design and must not be given a second, competing one here. */

/* Quill writes alignment and indentation as classes, so reading them back
   needs the same classes defined outside the editor. */
.ql-align-center { text-align: center; }
.ql-align-right { text-align: right; }
.ql-align-justify { text-align: justify; }
.ql-size-small { font-size: .82em; }
.ql-size-large { font-size: 1.3em; }
.ql-size-huge { font-size: 1.8em; }
.ql-indent-1 { padding-left: 3em; }
.ql-indent-2 { padding-left: 6em; }
.ql-indent-3 { padding-left: 9em; }
.ql-indent-4 { padding-left: 12em; }
.ql-indent-5 { padding-left: 15em; }
.ql-indent-6 { padding-left: 18em; }
.ql-indent-7 { padding-left: 21em; }
.ql-indent-8 { padding-left: 24em; }

/* A long URL pasted as a link, or a long unbroken word, must wrap rather
   than widen the page. */
.article-prose a,
.article-prose p { overflow-wrap: break-word; word-break: break-word; }

@media (max-width: 720px) {
  /* Deep indentation is unreadable in a phone column — the steps stay
     distinguishable but stop eating the line. */
  .ql-indent-1 { padding-left: 1.5em; }
  .ql-indent-2 { padding-left: 3em; }
  .ql-indent-3 { padding-left: 4.5em; }
  .ql-indent-4,
  .ql-indent-5,
  .ql-indent-6,
  .ql-indent-7,
  .ql-indent-8 { padding-left: 6em; }
}

/* ==========================================================================
   About NCIA — Community (about/community): the noticeboard
   --------------------------------------------------------------------------
   The fourth About section, and the only one whose styles live here rather
   than in a stylesheet of its own: it is an ordinary page, so the map's
   section modal fetches it with ?partial=1 and a partial response never gets
   to add a <link>. Same reason its behaviour sits in initCommunity() inside
   app.js instead of a community.js.

   The metaphor is the board by the pantry door. Cork, prints pinned a degree
   or two off square, a coloured pin per category. Choosing a print lifts it
   off the board: .community.is-viewing hides the stage and shows one story
   sheet in its place, which is what keeps this working inside the modal —
   there is no second overlay anywhere, only the page swapping what it shows.
   ========================================================================== */

.community {
  /* cork. Warm enough to sit beside the brand's maroon without competing,
     desaturated enough that eight photographs can lie on it at once. */
  --board: #e6dccd;
  --board-edge: #cbb9a0;
  --paper: #fffdf8;
  /* every print and chip carries a tone-* class; this is what it sets, and
     what the pin, the chip dot and the sheet's rule all read from */
  --tone: var(--navy-600);
  --tone-soft: var(--navy-100);
}

/* The tone ring. One rule per palette entry rather than a colour baked into
   each part, so a category invented tomorrow (see community_category_class()
   in app/Data/about.php) only has to name one of these. */
.community .tone-slate  { --tone: var(--tag-slate-fg);  --tone-soft: var(--tag-slate-bg); }
.community .tone-stone  { --tone: var(--tag-stone-fg);  --tone-soft: var(--tag-stone-bg); }
.community .tone-red    { --tone: var(--tag-red-fg);    --tone-soft: var(--tag-red-bg); }
.community .tone-amber  { --tone: var(--tag-amber-fg);  --tone-soft: var(--tag-amber-bg); }
.community .tone-lime   { --tone: var(--tag-lime-fg);   --tone-soft: var(--tag-lime-bg); }
.community .tone-green  { --tone: var(--tag-green-fg);  --tone-soft: var(--tag-green-bg); }
.community .tone-teal   { --tone: var(--tag-teal-fg);   --tone-soft: var(--tag-teal-bg); }
.community .tone-cyan   { --tone: var(--tag-cyan-fg);   --tone-soft: var(--tag-cyan-bg); }
.community .tone-blue   { --tone: var(--tag-blue-fg);   --tone-soft: var(--tag-blue-bg); }
.community .tone-indigo { --tone: var(--tag-indigo-fg); --tone-soft: var(--tag-indigo-bg); }
.community .tone-purple { --tone: var(--tag-purple-fg); --tone-soft: var(--tag-purple-bg); }
.community .tone-pink   { --tone: var(--tag-pink-fg);   --tone-soft: var(--tag-pink-bg); }

/* ---- what the company cares about ---------------------------------------- */

.community-commitments {
  list-style: none;
  margin: 0 0 6px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
.community-commitment {
  display: flex;
  gap: 10px;
  padding: 13px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.community-commitment__icon {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px;
  border-radius: 10px;
  background: var(--navy-050);
  color: var(--navy-600);
}
.community-commitment__title { font-size: 14px; margin-bottom: 3px; }
.community-commitment p { margin: 0; }

/* ---- the board ----------------------------------------------------------- */

.community-board {
  position: relative;
  padding: 21px 18px 24px;
  border-radius: 14px;
  background:
    /* the speckle. Two offset dot grids at low opacity read as cork grain
       without a texture file; a single grid reads as a pattern. */
    radial-gradient(circle at 1px 1px, rgba(90, 66, 42, .14) 1px, transparent 1.6px) 0 0 / 11px 11px,
    radial-gradient(circle at 1px 1px, rgba(90, 66, 42, .09) 1px, transparent 1.4px) 5px 7px / 17px 17px,
    linear-gradient(160deg, #ece2d3, var(--board) 55%, #ddd0bd);
  border: 1px solid var(--board-edge);
  /* the frame: a hairline of wood inside the edge, and the shadow the board
     casts inward onto itself */
  box-shadow:
    inset 0 0 0 3px rgba(141, 111, 82, .22),
    inset 0 2px 14px rgba(74, 46, 20, .16),
    var(--shadow-1);
}

/* Columns rather than a grid: a pinboard's prints are different heights and
   fill downward, which is what columns do and what a row-aligned grid cannot.
   Filtering hides prints with display:none (initFilterChips), and columns
   reflow around that on their own. */
.community-notes {
  columns: 3;
  column-gap: 16px;
}

/* Nothing pinned yet — the board's own "nothing here" idiom, same muted
   one-line message library_admin.php's .libset__empty uses for an empty
   vocabulary list, sized up for a full-width board instead of a small panel. */
.community-board__empty {
  margin: 24px 0;
  padding: 16px;
  text-align: center;
  font-size: 13.5px;
  color: var(--ink-3);
}

/* ---- a pinned print ------------------------------------------------------ */

.community-note {
  display: block;
  break-inside: avoid;
  margin: 0 0 18px;
  padding: 22px 8px 4px;      /* the top band is the pin's, see __pin below */
  position: relative;
  background: var(--paper);
  border: 1px solid rgba(43, 22, 24, .09);
  border-radius: 3px;                      /* paper, not an app card */
  color: var(--ink);
  text-decoration: none;
  transform: rotate(var(--tilt, 0deg));
  transform-origin: 50% 15px;              /* it swings from its pin */
  box-shadow: 0 1px 2px rgba(74, 46, 20, .18), 0 10px 20px -12px rgba(74, 46, 20, .5);
  transition: transform .28s cubic-bezier(.22, .72, .24, 1),
              box-shadow .28s ease;
}
.community-note:hover,
.community-note:focus-visible {
  transform: rotate(0deg) translateY(-5px) scale(1.014);
  box-shadow: 0 2px 4px rgba(74, 46, 20, .16), 0 26px 40px -18px rgba(74, 46, 20, .55);
  text-decoration: none;
  z-index: 2;
}
.community-note:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 3px; }

/* The pin. A dome with a highlight and the shadow it drops on the paper —
   drawn rather than imaged so it can take the category's colour. It sits
   wholly inside the paper: see the note on padding above for why nothing here
   may overflow the print. */
.community-note__pin {
  position: absolute;
  top: 6px; left: 50%;
  width: 18px; height: 18px;
  margin-left: -9px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 33% 30%, rgba(255, 255, 255, .85), rgba(255, 255, 255, 0) 46%),
    var(--tone);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset,
              0 3px 5px -1px rgba(74, 46, 20, .5);
  z-index: 3;
}
/* the needle's shadow, cast down the paper */
.community-note__pin::after {
  content: "";
  position: absolute;
  top: 13px; left: 50%;
  width: 3px; height: 9px;
  margin-left: -1px;
  border-radius: 0 0 2px 2px;
  background: linear-gradient(rgba(74, 46, 20, .35), rgba(74, 46, 20, 0));
}

.community-note__shot {
  display: block;
  overflow: hidden;
  border-radius: 2px;
  background: var(--navy-050);
}
.community-note__shot img {
  display: block;
  width: 100%;
  height: auto;                            /* the width/height attributes map to a
                                              presentational height hint, which beats
                                              `auto` and would defeat aspect-ratio */
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform .5s cubic-bezier(.22, .72, .24, 1);
}
.community-note:hover .community-note__shot img { transform: scale(1.04); }

.community-note__body { display: block; padding: 10px 5px 9px; }

.community-note__tags {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  margin-bottom: 7px;
}
.community-note__when { font-size: 12px; color: var(--ink-3); }

.community-note__title {
  font-size: 15.5px;
  margin-bottom: 5px;
  color: var(--navy-900);
}
.community-note__summary {
  margin: 0 0 9px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-2);
}

.community-note__foot {
  display: block;
  padding-top: 8px;
  border-top: 1px dashed rgba(43, 22, 24, .14);
  font-size: 12.5px;
}
.community-note__where { display: block; color: var(--ink-3); }
/* the number is the point of the entry — it gets the category's colour and
   the only bold weight on the print */
.community-note__impact {
  display: block;
  margin-top: 3px;
  font-weight: 650;
  color: var(--tone);
}

/* ---- the spotlight print ------------------------------------------------- */

.community-spotlight-section .community-note--spotlight {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 0;
  padding: 22px 9px 9px;
  margin: 0;
  transform-origin: 50% 16px;
}
/* Edge to edge, a ratio alone makes the spotlight photograph half a screen
   tall, so it is capped and the crop takes up the slack. */
.community-note--spotlight .community-note__shot img { aspect-ratio: 16 / 10; max-height: 330px; }
.community-note--spotlight .community-note__body {
  display: flex;
  flex-direction: column;
  padding: 14px 15px 12px 18px;
}
.community-note--spotlight .community-note__title { font-size: 20px; margin-bottom: 7px; }
.community-note--spotlight .community-note__summary { font-size: 14px; }
.community-note--spotlight .community-note__foot { margin-top: auto; }
.community-note__more {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 10px;
  font-size: 13px; font-weight: 600;
  color: var(--navy-700);
}
.community-note--spotlight:hover .community-note__more { text-decoration: underline; }
.community-note__more .icon { width: 15px; height: 15px; transition: transform .25s ease; }
.community-note--spotlight:hover .community-note__more .icon { transform: translateX(3px); }

/* ---- In Focus, 2-4 events ------------------------------------------------- */

/* A real grid rather than the Noticeboard's columns-based masonry: at 2-4
   entries this reads as its own section, not an extension of the board
   below it. auto-fit/minmax already answers tablet/mobile widths on its
   own, the same way .community-impact's grid does — no extra breakpoints
   needed. Gap matches .community-notes' own column-gap so the two sections
   feel like the same board even though they lay out differently. */
.community-infocus-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
}
/* .community-note already sets its own bottom margin for the Noticeboard's
   stacked columns; the grid's own gap replaces it here. */
.community-infocus-grid .community-note { margin: 0; }
.community-infocus-grid .community-note--focus:hover .community-note__more { text-decoration: underline; }
.community-infocus-grid .community-note--focus:hover .community-note__more .icon { transform: translateX(3px); }

/* ---- the filter chips ---------------------------------------------------- */

.community-filters { margin-bottom: 14px; }
/* A chip is a pin with a label: the dot carries the same colour as the pin
   holding up the prints it selects, so the board and the filter agree without
   a legend explaining them. */
.community-filters__pin {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--tone);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .6) inset;
}
.chip--tone.is-on {
  background: var(--tone);
  border-color: var(--tone);
  color: #fff;
}
.chip--tone.is-on .community-filters__pin { background: #fff; box-shadow: none; }

/* ---- what it added up to ------------------------------------------------- */

.community-impact {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}
.community-metric {
  padding: 16px 15px;
  border-left: 1px solid var(--line-2);
}
.community-metric:first-child { border-left: 0; }
.community-metric__value {
  margin: 0 0 2px;
  font-family: var(--serif);
  font-size: 26.5px;
  line-height: 1.1;
  font-weight: 650;
  letter-spacing: -.02em;
  color: var(--navy-700);
}
.community-metric__label {
  margin: 0;
  font-size: 12.5px;
  color: var(--ink-3);
}

/* ---- the story sheet ----------------------------------------------------- */

/* Before app.js reaches the page — and forever, without it — the sheets are
   simply the stories, stacked under the board, and every print above is an
   anchor down to one. `is-ready` is what folds them away. */
.community__reader {
  width: auto;
  min-width: 0;
  margin: 25px auto 0;
  container-type: inline-size;
}
.community__reader-head { margin: 0 0 14px; }

.community.is-ready .community__reader-head { display: none; }
.community.is-ready .community-sheet { display: none; }
.community.is-ready .community-sheet.is-open { display: block; }
.community.is-viewing .community__stage { display: none; }
/* the back control only means something once scripting can honour it */
.community-sheet__back { display: none; }
.community.is-ready .community-sheet__back { display: inline-flex; }

.community-sheet {
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  margin: 0 0 24px;
  padding: clamp(18px, 2.2vw, 32px);
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 3px solid var(--tone);
  border-radius: var(--r);
  outline: none;
}
.community.is-ready .community-sheet.is-open {
  animation: community-sheet-in .34s cubic-bezier(.22, .72, .24, 1) both;
}
@keyframes community-sheet-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

.community-sheet__back {
  align-items: center; gap: 7px;
  margin-bottom: 14px;
  padding: 6px 10px 6px 7px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg);
  color: var(--ink-2);
  font: inherit; font-size: 13px; font-weight: 550;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.community-sheet__back:hover { background: var(--navy-050); border-color: #edb9bc; color: var(--navy-700); }
.community-sheet__back:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }
.community-sheet__back .icon { width: 16px; height: 16px; }

.community-sheet__head { margin-bottom: 14px; }
.community-sheet__title { font-size: 22.5px; margin: 8px 0 6px; }
.community-sheet__meta {
  margin: 0;
  font-size: 13.5px;
  color: var(--ink-3);
}
.community-sheet__meta .sep { margin: 0 7px; }

.community-sheet__figure {
  margin: 0 0 16px;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--navy-050);
}
.community-sheet__figure img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: auto;
  max-height: none;
  object-fit: contain;
}

.community-sheet__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(240px, 280px);
  gap: 18px;
  align-items: start;
}
.community-sheet__main { min-width: 0; }
.community-sheet__story {
  min-width: 0;
  padding: clamp(18px, 2vw, 26px);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.community-sheet__story p {
  margin: 0 0 11px;
  width: 100%;
  max-width: none;
  font-size: 15.5px;
  line-height: 1.68;
  color: var(--ink-read);
}

/* auto-fill, not auto-fit: auto-fit collapses the empty tracks, so an entry
   with a single extra photograph got one 1300px-wide thumbnail. auto-fill
   keeps the tracks, and one shot stays the size of one shot. */
.community-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 10px;
  margin-top: 10px;
}
.community-gallery img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--r-sm);
  background: var(--navy-050);
}
.community-gallery__link {
  display: block;
  overflow: hidden;
  border-radius: var(--r-sm);
  cursor: zoom-in;
}
.community-gallery__link:focus-visible {
  outline: 3px solid var(--navy-600);
  outline-offset: 3px;
}
.community-gallery__link img { transition: transform .2s ease; }
.community-gallery__link:hover img { transform: scale(1.035); }

.community-lightbox {
  position: fixed;
  box-sizing: border-box;
  width: fit-content;
  height: fit-content;
  max-width: 94vw;
  max-height: 94vh;
  padding: 0;
  overflow: visible;
  border: 0;
  background: transparent;
}
.community-lightbox::backdrop {
  background: rgba(8, 12, 20, .88);
  backdrop-filter: blur(3px);
}
.community-lightbox img {
  display: block;
  max-width: 92vw;
  max-height: 90vh;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 20px 70px rgba(0, 0, 0, .45);
}
.community-lightbox__close {
  position: absolute;
  z-index: 1;
  top: 10px;
  right: 10px;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .45);
  border-radius: 50%;
  background: rgba(10, 14, 22, .75);
  color: #fff;
  cursor: pointer;
}
.community-lightbox__close .icon { width: 19px; height: 19px; }
.community-lightbox__close:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }

.community-sheet__facts {
  min-width: 0;
  padding: 14px 15px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.community-sheet__facts dl { margin: 0; }
.community-sheet__facts dt {
  font-size: 11px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3);
}
.community-sheet__facts dd {
  margin: 3px 0 12px;
  font-size: 14px;
  color: var(--navy-800);
  font-weight: 550;
  overflow-wrap: anywhere;
}
.community-sheet__facts dd:last-of-type { margin-bottom: 0; }
.community-sheet__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.community-sheet__actions .btn { margin-top: 0; }

/* ---- narrower boards ----------------------------------------------------- */

/* The modal's dialog is inset 20px from the viewport, so the page inside it is
   always narrower than the same page on its own URL. These have to be width
   queries on the page rather than on the window — which is what container
   queries give. */
.community__stage { container-type: inline-size; }

@container (min-width: 1560px) {
  .community-notes { columns: 4; }
}

@container (max-width: 1080px) {
  .community-notes { columns: 2; }
  .community-impact { grid-template-columns: repeat(2, 1fr); }
  .community-metric:nth-child(3) { border-left: 0; }
  .community-metric:nth-child(-n+2) { border-bottom: 1px solid var(--line-2); }
}

@container (max-width: 820px) {
  .community-commitments { grid-template-columns: 1fr; }
  .community-spotlight-section .community-note--spotlight { grid-template-columns: 1fr; }
  .community-note--spotlight .community-note__body { padding: 14px 7px 7px; }
  .community-note--spotlight .community-note__title { font-size: 19px; }
}

@container (max-width: 620px) {
  .community-notes { columns: 1; }
  .community-board { padding: 18px 14px 6px; }
}

@container (max-width: 900px) {
  .community-sheet__layout { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .community-sheet { padding: 20px; }
  .community-sheet__story { padding: 20px; }
  .community-sheet__facts { max-width: none; }
}

/* The sheet sits outside .community__stage, so it answers the window. */
@media (max-width: 1000px) {
  .community-sheet__layout { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .community-sheet { padding: 20px; }
  .community-sheet__title { font-size: 19.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .community-gallery__link img { transition: none; }
  .community-gallery__link:hover img { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .community-note,
  .community-note__shot img,
  .community-note__more .icon { transition: none; }
  .community-note:hover,
  .community-note:focus-visible { transform: rotate(var(--tilt, 0deg)); }
  .community.is-ready .community-sheet.is-open { animation: none; }
}

/* ==========================================================================
   About NCIA — Social Media (about/social): the spotlight grid
   --------------------------------------------------------------------------
   The fifth About section, and the second that lives in this stylesheet
   rather than one of its own: it is an ordinary page, so the map's section
   modal fetches it with ?partial=1 and a partial response never gets to add a
   <link>. Its behaviour is in initSocial() inside app.js for the same reason.

   Five featured posts in a plain CSS Grid bento layout: the first (always
   the Instagram post) is a hero tile spanning two rows, the other four
   auto-place into the 2x2 beside it — no coordinates, no SVG, nothing for
   JavaScript to wire up. Below a container-query breakpoint the grid drops
   to two columns and then one — same markup, no script involved.
   ========================================================================== */

.social {
  /* --brand is what every platform-coloured part reads from. Set once per
     card by the .plat-* class below, so nothing downstream needs to know
     which platform it is drawing. */
  --brand: var(--navy-600);
  --brand-2: var(--navy-700);
}

/* The platform ring. Brand colours, because a social page that renders six
   channels in house maroon is a page nobody can scan — this is the one place
   on the site where an outside brand's colour is the correct colour. The page
   around them stays entirely on the system palette. */
.social .plat-facebook  { --brand: #1877f2; --brand-2: #0b5fd0; }
.social .plat-instagram { --brand: #d62976; --brand-2: #f0912b; }
.social .plat-linkedin  { --brand: #0a66c2; --brand-2: #084c92; }
.social .plat-youtube   { --brand: #e62117; --brand-2: #b81810; }
.social .plat-tiktok    { --brand: #121316; --brand-2: #2b2d33; }
.social .plat-x         { --brand: #14171a; --brand-2: #2b2f34; }
.social .plat-generic   { --brand: var(--navy-600); --brand-2: var(--navy-800); }

/* ---- the platform tile --------------------------------------------------- */

.socialmark {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
  border-radius: 30%;
  background: var(--brand);
  color: #fff;
  box-shadow: 0 1px 2px rgba(43, 22, 24, .18);
}
.socialmark svg { width: 74%; height: 74%; }
.socialmark--sm { width: 24px; height: 24px; }
.socialmark--lg { width: 42px; height: 42px; border-radius: 26%; }
/* a platform nobody has drawn a glyph for — see social_mark() */
.socialmark--mono { font-family: var(--serif); font-weight: 650; font-size: 14px; }
.socialmark--lg.socialmark--mono { font-size: 18px; }
/* Instagram is a gradient in every context it appears; a flat pink reads as
   the wrong app. */
.social .plat-instagram .socialmark,
.socialmark.plat-instagram {
  background: linear-gradient(135deg, #f0912b, #d62976 52%, #8c34b0);
}

/* ---- the spotlight grid ---------------------------------------------------
   .social-spotlight itself is defined further down, alongside its
   container-query reflow, so both live together. */

/* ---- a card in the grid ---------------------------------------------------
   Nothing here positions the card — it is a plain grid item, sized by
   whatever cell .social-spotlight (or its first-child span) gives it. */

.social-node {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 9px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--ink);
  text-decoration: none;
  box-shadow: 0 1px 2px rgba(43, 22, 24, .06), 0 14px 30px -18px rgba(43, 22, 24, .5);
  /* nothing inside may push the card taller than the row can afford */
  min-height: 0;
  transition: transform .2s ease, box-shadow .3s ease, border-color .3s ease;
}
.social-node:hover,
.social-node:focus-visible {
  text-decoration: none;
  transform: translateY(-3px);
  box-shadow: 0 2px 4px rgba(43, 22, 24, .08), 0 26px 46px -20px rgba(43, 22, 24, .55);
  z-index: 2;
}
.social-node:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 3px; }

.social-node__head {
  display: flex; align-items: center; gap: 7px;
  flex: none;
  margin-bottom: 7px;
}
/* The account line. Two lines when the post carries an author of its own —
   the account name over the channel it posted to, the way a post's own
   header reads — and one when it does not, in which case the channel is the
   byline. min-width: 0 so a long account name ellipsises instead of pushing
   the date off the card. */
.social-node__who {
  display: flex; flex-direction: column;
  min-width: 0;
  line-height: 1.25;
}
.social-node__platform {
  font-size: 12.5px; font-weight: 650;
  color: var(--navy-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.social-node__channel {
  font-size: 10.5px;
  color: var(--ink-3);
  white-space: nowrap;
}
.social-node__when {
  margin-left: auto;
  font-size: 11px;
  color: var(--ink-3);
  white-space: nowrap;
}

.social-node__shot,
.social-post__shot {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--r-sm);
  background: var(--navy-050);
}

.social-node__shot img,
.social-post__shot img {
  display: block;
  width: 100%;
  height: auto;                          /* the width/height attributes map to a
                                            presentational height hint, which
                                            beats `auto` and would defeat
                                            aspect-ratio */
  aspect-ratio: 4 / 3;
  object-fit: cover;
}
.social-node__shot { flex: 1 1 auto; min-height: 0; }
.social-node__shot img { height: 100%; aspect-ratio: auto; }
.social-node__foot { flex: none; display: block; }
/* Only a card with no shot slot at all gets the "own words fill the card"
   treatment below — in Edit Mode every kind (including text) renders a shot
   slot so an image can be added, so the text-only layout must not apply
   there or the card doubles up: an image slot plus the old fill-the-card
   caption panel sized for when there was no image. */
.social-node--text .social-node__foot { flex: 1 1 auto; }
.is-edit-mode .social-node--text .social-node__foot { flex: none; display: block; }

/* ---- the embedded post ----------------------------------------------------
   A tile whose inside is the platform's own rendering of the post, loaded by
   the visitor's browser. The card keeps its own frame — border, radius,
   shadow — and the iframe sits inside it at the height that provider's embed
   needs, which is carried in per card as --embed-height because only the
   provider knows it and a cross-origin frame cannot report it back.

   No hover lift here, unlike the compact card: the tile is not a link, and
   an element that rises under the pointer but does nothing when clicked is a
   promise the card cannot keep. */
/* No frame of our own around an embed, on purpose.
   
   Every one of these platforms already draws a card — its own border, its own
   radius, its own white — so wrapping it in a second one framed the same post
   twice. Worse, our frame was what made the leftover space visible: the frame
   height is an estimate (see social_default_embed_height()), and any pixel of
   it the post did not fill showed up as a white panel bounded by our border
   with our footer nailed underneath, which reads as a broken card rather than
   as spacing.

   Both embeds that cannot report their height paint nothing behind themselves
   — LinkedIn's <article> is white but its page is transparent, and Facebook's
   plugin is transparent throughout — so with this container gone and the
   frame below transparent, whatever the post does not fill is simply the page
   showing through. The estimate is still an estimate; it just stopped being
   something you can see. */
.social-node--embed {
  display: flex;
  flex-direction: column;
  /* The platform iframe is the visible card. The outer node must not clip it
     into a second rounded panel or paint a bottom container of its own. */
  overflow: visible;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
/* A one-cell grid, not a positioned block, and that is load-bearing: the
   three things stacked here (the fallback, the frame, the click layer) used
   to be absolutely positioned over a relative parent, and an absolutely
   positioned element inside a multi-column container — which the masonry
   layout makes this — can be painted against the wrong column entirely. The
   symptom was a blocked-embed message floating over a neighbouring card's
   post. Giving all three the same grid cell stacks them without positioning
   anything, so fragmentation has nothing to get wrong. */
/* An embed that will not stretch gets a card its own size instead of a
   column-wide one with white down both sides. The leftover space falls
   outside the card, where it reads as the gap between cards rather than as
   padding nobody asked for. */
.social-node--natural {
  /* Plus the card's own 1px borders. Without them the frame is two pixels
     narrower than the player, and an embed that will not reflow simply loses
     two pixels off its left edge — enough to cut the "Ti" off "TikTok". */
  max-width: calc(var(--embed-width, 0px) + 2px);
  margin-left: auto;
  margin-right: auto;
}

.social-node__frame {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  flex: none;
  /* A scaled embed is drawn larger than it is laid out — a transform does
     not change layout size — so the frame clips what hangs past its own
     height, which app.js sets to the scaled height. */
  overflow: hidden;
}
.social-node__frame > * { grid-area: 1 / 1; }

/* Facebook and LinkedIn do not expose their rendered height to the parent
   page. When the administrator supplied the embed's original dimensions,
   keep the provider document at that native size and scale the complete
   frame down to the available column. The wrapper is only a sizing surface:
   it has no paint of its own and therefore cannot create a second card. */
.social-node--scaled {
  width: min(100%, var(--embed-source-width));
  max-width: 100%;
  margin-inline: auto;
}
.social-node--scaled .social-node__frame {
  width: 100%;
  height: var(--embed-layout-height);
}
.social-node--scaled .social-node__embed {
  width: var(--embed-source-width);
  min-width: var(--embed-source-width);
  max-width: none;
  height: var(--embed-source-height);
  transform: scale(var(--embed-scale, 1));
  transform-origin: top left;
}
/* Meta's XFBML renderer owns the Facebook iframe dimensions. Let its
   generated post contribute its natural height instead of clipping it inside
   the generic frame rules used by other providers. */
.social-node--facebook-official {
  width: 100%;
  max-width: 750px;
  margin-inline: auto;
}
.social-node--facebook-official .social-node__frame {
  display: block;
  overflow: visible;
  height: auto;
}
.social-node--facebook-official .fb-post {
  display: block;
  width: 100%;
  min-height: 0;
  /* Scaled only below Facebook's 350px minimum — see fitFacebookEmbed() in
     app.js. From the corner, so the post stays aligned with the column. */
  transform-origin: top left;
}
/* A post drawn at 350px and scaled into a narrower column still takes 350px
   of layout; this keeps that unscaled width from spilling past the column. */
.social-node--facebook-official { overflow: hidden; }
.social-node__embed {
  display: block;
  z-index: 1;
  width: 100%;
  height: var(--embed-height, 500px);
  border: 0;
  /* Transparent, so the part of the frame the post does not fill is the page
     rather than a white panel. This was opaque once, to stop the fallback
     beneath showing through Facebook's transparent plugin — that is no longer
     what keeps them apart: the fallback is display:none until the card is
     known to be blocked, so there is nothing underneath to show through. */
  background: transparent;
}
/* Facebook's plugin leaves its document background transparent. Give the
   iframe itself a white canvas so its real post stays white without painting
   a border, radius, shadow, or padding on our outer node. */
.social-node--embed.plat-facebook .social-node__embed { background: #fff; }

/* A frame that never reported in: the fallback is all there is to show, so
   the card is only as tall as that needs. */
.social-node--embed.is-embed-blocked .social-node__embed { height: 280px; }
.social-node--embed.is-embed-blocked .social-node__fallback { display: flex; }
/* The one case that still needs a container: with the embed gone there is no
   platform card to sit inside, and the explanation would otherwise float on
   the page with nothing marking it as one post's worth of anything. */
.social-node--embed.is-embed-blocked {
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
/* Nothing to show through once the fallback is up. */
.social-node--embed.is-embed-blocked .social-node__embed { visibility: hidden; }

/* ---- what a blocked embed shows -------------------------------------------
   Sits underneath the frame and is revealed by the frame not being there.
   It is inert — aria-hidden, no controls — because the card's own cover link
   is over the top of it and the "View on …" row beneath is the accessible
   route. This is a picture of the situation, not a second set of buttons. */
.social-node__fallback {
  z-index: 0;
  /* Asked for, not revealed: shown by .is-embed-blocked below. */
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 26px 22px;
  text-align: center;
  background: var(--navy-050);
}
.social-node__fallback-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--navy-900);
}
.social-node__fallback-note {
  max-width: 34ch;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-2);
}
.social-node__fallback-cta {
  margin-top: 2px;
  padding: 7px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-size: 12.5px;
  font-weight: 650;
  color: var(--navy-600);
}
/* The click layer. Transparent, over the whole frame, and the reason the
   card behaves as one link however deep inside the platform's own rendering
   the pointer lands. It sits above the frame rather than replacing it: the
   post still draws itself, it just does not take the click. */
.social-node__cover {
  z-index: 2;
  display: block;
  text-decoration: none;
}
/* It is the card's only link now that the row beneath is gone, so it has to
   show where the keyboard is. Drawn inside the frame's edge because the frame
   clips, and an outline on the outside would be cut in half. */
.social-node__cover:focus-visible {
  outline: 2px solid var(--navy-600);
  outline-offset: -3px;
  border-radius: var(--r);
}
/* The row under the frame. Keyboard users cannot tab into a cross-origin
   frame's own links from this page, so this is the card's accessible way to
   the post — and the visible one when a browser blocks third-party frames. */
.social-node__open {
  display: flex; align-items: center; gap: 8px;
  flex: none;
  padding: 9px 11px;
  border-top: 1px solid var(--line);
  color: var(--navy-900);
  font-size: 12.5px;
  font-weight: 650;
  text-decoration: none;
}
.social-node__open:hover { background: var(--navy-050); text-decoration: none; }
.social-node__open:focus-visible { outline: 2px solid var(--navy-600); outline-offset: -2px; }
.social-node__open .icon { width: 14px; height: 14px; margin-left: auto; color: var(--navy-600); }

/* ---- masonry, for embedded posts ------------------------------------------
   Every embed is a different height — a square photo, a long LinkedIn post,
   a one-line tweet — and Grid lays rows out in lockstep: one tall card sets
   the row's height and every shorter card beside it leaves a hole beneath
   it. So the embed layout leaves Grid behind and becomes a multi-column
   block, which is CSS's one native masonry: each card is placed under the
   previous one in its column, whatever height it happened to be.

   Multi-column rather than `grid-template-rows: masonry`, which no browser
   ships unprefixed yet, and rather than a script, which would have to
   re-measure on every one of those height messages the embeds send.

   The trade the columns make is reading order: cards run down a column and
   then across, not left to right across a row. For a wall of posts with no
   sequence to follow, that is not a cost worth a layout engine to avoid.

   column-width (not column-count) is what keeps it responsive: the browser
   fits as many 340px columns as the container allows, one on a phone.

   The doubled class is specificity: .social-spotlight's own `display: grid`
   is declared further down this stylesheet, and an equal-weight rule here
   would lose to it wherever it sits. */
/* No max-width: the columns take the full width they are given. There used
   to be a cap here, from when TikTok's card had to stay near the 325px its
   old embed drew at — and because it was a cap without centring, everything
   past it was dead space down the right of the page. The player fills any
   width now, so nothing needs the columns held back. */
.social-spotlight.social-spotlight--embeds {
  display: block;
  /* Width and count together: the browser fits as many 340px columns as the
     container allows and then stops at four. Five posts across reads as a
     contact sheet rather than as a wall of posts, and a fifth column on a
     wide screen makes every card too narrow for the platforms' own
     rendering, which is drawn for a phone-width column. */
  column-width: 340px;
  column-count: 4;
  column-gap: 16px;
}
/* A single card should not be stretched across the full width of the page. */
.social-spotlight.social-spotlight--embeds[data-social-count="1"] { max-width: 620px; }

.social-spotlight.social-spotlight--embeds .social-node {
  /* Without this a card is sliced in half across a column boundary — with an
     iframe inside, the half that lands in the next column is blank. */
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  /* Embedded posts must keep their own measured height. This also protects
     the layout if the feed is moved back to Grid at a breakpoint. */
  align-self: start;
  height: auto;
  min-height: 0;
  /* The provider owns the visible card edge. This is deliberate breathing
     room between posts, not a second card/container around the embed. */
  margin: 0 0 16px;
}
/* Also undoes the container-query rule below, which stretches the hero
   across every column on a narrow container — right for a compact card that
   reflows, wrong for a frame whose contents are a fixed-width post. */
/* The doubled class is specificity, not a typo: the container-query rule
   further down that stretches the hero across every column matches with the
   same weight and comes later in the file, so an equal-weight override here
   would lose to it. */
.social-spotlight--embeds.social-spotlight .social-node:first-child {
  grid-row: auto;
  grid-column: auto;
}

/* ---- LinkedIn, redrawn -----------------------------------------------------
   A LinkedIn card is this page's own markup built from a snapshot of the post
   (social_linkedin_card_snapshot() in SocialStore.php), not a frame, so it is
   exactly as tall as what is in it — for every viewer, at every width. It is
   laid out and coloured like LinkedIn's own embed so it reads as one of the
   platform-drawn cards around it: those are white platform cards with no
   container of this site's around them, and so is this. */
.li-post {
  display: flex;
  flex-direction: column;
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  margin: 0 0 16px;
  overflow: hidden;
  background: #fff;
  border: 1px solid rgba(140, 140, 140, .2);
  border-radius: 8px;
  color: rgba(0, 0, 0, .9);
  text-decoration: none;
  /* LinkedIn's own stack, so the post's text wraps as it does there. */
  font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell,
               "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
               "Lucida Grande", Helvetica, Arial, sans-serif;
  transition: border-color .2s ease, box-shadow .2s ease;
}
a.li-post:hover { border-color: rgba(10, 102, 194, .45); box-shadow: 0 4px 14px -6px rgba(0, 0, 0, .25); }
a.li-post:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 3px; }

.li-post__head {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 12px 16px 0;
}
.li-post__logo {
  flex: none;
  width: 48px; height: 48px;
  object-fit: cover;
  border-radius: 0;
}
.li-post__who {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}
.li-post__name {
  font-size: 14px;
  font-weight: 600;
  line-height: 20px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.li-post__meta {
  font-size: 12px;
  line-height: 16px;
  color: rgba(0, 0, 0, .6);
}
.li-post__brand { flex: none; line-height: 0; }

/* Three lines and "…more", like LinkedIn's "less text" embed. The post's own
   line breaks are kept (pre-line). The cut is a height, not line-clamp:
   line-clamp paints its own "…" on the last line, which beside "…more" read
   as a stray ellipsis — worst when that line is one of the post's blank
   ones, as LinkedIn posts often have. */
.li-post__text-wrap {
  position: relative;
  display: block;
  margin: 8px 16px 12px;
}
.li-post__text {
  display: block;
  max-height: 60px; /* 3 x line-height */
  overflow: hidden;
  font-size: 14px;
  line-height: 20px;
  white-space: pre-line;
  overflow-wrap: anywhere;
}
.li-post__more {
  display: none;
  position: absolute;
  right: 0; bottom: 0;
  padding-left: 18px;
  background: linear-gradient(to right, rgba(255, 255, 255, 0), #fff 16px);
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  color: rgba(0, 0, 0, .6);
}
.li-post__text-wrap.is-clamped .li-post__more { display: block; }
a.li-post:hover .li-post__more { color: #0a66c2; text-decoration: underline; }

.li-post__media {
  position: relative;
  display: block;
  background: #f4f2ee;
  line-height: 0;
}
.li-post__media img {
  display: block;
  width: 100%;
  height: auto;
}
.li-post__more-media {
  position: absolute;
  right: 10px; bottom: 10px;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .6);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  line-height: 18px;
}

.li-post__counts {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0 16px;
  padding: 8px 0;
  font-size: 12px;
  line-height: 16px;
  color: rgba(0, 0, 0, .6);
}
.li-post__reactions { display: inline-flex; align-items: center; }
.li-post__reactions img {
  width: 16px; height: 16px;
  margin-right: -3px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px #fff;
}
.li-post__reactions img:last-of-type { margin-right: 4px; }

.li-post__actions {
  display: flex;
  justify-content: space-around;
  min-height: 44px;
  margin: 0 16px;
  border-top: 1px solid rgba(140, 140, 140, .2);
}
.li-post__action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 8px;
  font-size: 14px;
  font-weight: 600;
  color: rgba(0, 0, 0, .6);
}
.li-post__action .icon { width: 20px; height: 20px; }
a.li-post:hover .li-post__action { color: rgba(0, 0, 0, .75); }

/* ---- the count line -------------------------------------------------------
   What makes a tile read as a post rather than as a bookmark: the same marks
   a platform puts under one of its own posts. They are marks, not controls —
   nothing here is focusable or clickable, because the whole card is already
   one link to the original post, and a button inside a link is neither
   operable nor announceable.

   A figure appears only where the post actually reported one (see
   social_metrics() in SocialStore.php). The mark shows either way, so a
   provider that gives comments but not shares still produces an even row
   rather than a gap. */
.social-node__stats {
  display: flex; align-items: center; gap: 12px;
  margin-top: 7px;
  color: var(--ink-3);
}
.social-node__stat {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.social-node__stat-mark { width: 14px; height: 14px; }
/* The heart is the one mark a platform fills rather than outlines, and it is
   the first thing the eye lands on in a count line. */
.social-node__stat:first-child .social-node__stat-mark {
  fill: currentColor;
  color: var(--navy-600);
}
.social-node__stat-count { font-weight: 600; color: var(--ink-2); }

/* The hero's count line can afford the platform's own scale. */
.social-spotlight .social-node:first-child .social-node__stats { gap: 15px; }
.social-spotlight .social-node:first-child .social-node__stat { font-size: 12.5px; }
.social-spotlight .social-node:first-child .social-node__stat-mark { width: 16px; height: 16px; }

/* ---- nothing connected ----------------------------------------------------
   The page no longer invents posts to fill the grid, so it needs somewhere
   to say so. Sized as a panel rather than a line of text: an empty grid area
   with one sentence floating in it reads as a page that failed to load. */
/* The manager header's right-hand side: "Refresh all" beside the status pill,
   so the two things that report on the whole grid sit together. Wraps under
   the heading on a narrow screen rather than squeezing the pill. */
/* A slot that is filled but cannot be drawn: the one manager state that is a
   problem rather than a status, so it is the one that is coloured. */
.social-manager__current.is-warning {
  padding: 8px 10px;
  border-left: 3px solid var(--navy-600);
  border-radius: var(--r-sm);
  background: var(--navy-050);
  color: var(--ink-2);
}

/* A destructive button waiting for its second press. Coloured rather than
   just relabelled, because the label is the question and the colour is what
   makes it read as one. */
.social-manager__actions .btn.is-confirming {
  border-color: var(--navy-600);
  background: var(--navy-600);
  color: #fff;
}

/* What a card knows about its own size, for the one provider whose height
   has to be derived from the post rather than read from the frame. */
.social-manager__measure {
  margin: 0 0 10px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-3);
}

/* The height control on a card in the manager. */
.social-manager__height {
  display: flex; align-items: center; gap: 6px;
  margin: 0 0 10px;
  font-size: 12px;
  color: var(--ink-3);
}
.social-manager__height input {
  width: 84px;
  padding: 5px 7px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font: inherit;
  color: var(--ink);
  background: var(--surface);
}
.social-manager__height-unit { color: var(--ink-3); }

/* The card list's empty state. */
.social-manager__empty {
  margin-top: 12px;
  padding: 18px;
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
  color: var(--ink-2);
  font-size: 13px;
  text-align: center;
}

.social-manager__head-actions {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.social-empty {
  margin-top: 6px;
  padding: 34px 26px;
  border: 1px dashed var(--line);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 14px;
  text-align: center;
}

.social-node__play,
.social-post__play {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  color: var(--brand);
  box-shadow: 0 2px 8px rgba(43, 22, 24, .3);
}
.social-node__play .icon,
.social-post__play .icon { width: 20px; height: 20px; }

.social-node__time,
.social-post__time {
  position: absolute;
  right: 6px; bottom: 6px;
  padding: 1px 5px;
  border-radius: 3px;
  background: rgba(20, 12, 13, .8);
  color: #fff;
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
}

/* A caption is the post's own words and can run long; the card is a preview,
   so it stops after a couple of lines and the real post carries the rest. A
   text post has no thumbnail eating the card, so it gets the room. */
.social-node__caption {
  margin-top: 8px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.social-node--text .social-node__meta {
  position: static;
  margin-top: auto;
  padding: 7px 9px;
  border-top: 1px solid var(--line-2);
}
.is-edit-mode .social-node--text .social-node__meta {
  margin-top: 8px;
}
/* A text post has no thumbnail to absorb the card's slack, so its own words
   take the panel the picture would have had — the same treatment the rail
   gives them, rather than a card that reads as half empty. Edit Mode always
   renders a shot slot (even for a text post, so one can add an image there),
   so this panel treatment only applies when the card is truly imageless. */
.social-node--text .social-node__caption {
  -webkit-line-clamp: 6;
  flex: 1;
  box-sizing: border-box;
  padding: 11px 10px;
  border-radius: var(--r-sm);
  background: var(--bg);
  border: 1px solid var(--line-2);
  font-family: var(--serif);
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--navy-800);
}
.is-edit-mode .social-node--text .social-node__caption {
  -webkit-line-clamp: 2;
  flex: none;
  box-sizing: content-box;
  padding: 0;
  border-radius: 0;
  background: none;
  border: 0;
  font-family: inherit;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-2);
}
.social-node--text .social-node__foot { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.is-edit-mode .social-node--text .social-node__foot { display: block; flex: none; min-height: 0; }
.social-node__meta {
  display: block;
  margin-top: 8px;
  padding: 7px 9px;
  border-top: 1px solid var(--line-2);
  font-size: 11px;
  color: var(--ink-3);
}
.social-node:not(.social-node--text) .social-node__meta,
.is-edit-mode .social-node--text .social-node__meta {
  margin-left: -9px;
  margin-right: -9px;
}

/* ---- Edit Mode: click a card's photo to replace or add one --------------
   .social-node__shot is already position:relative (see above), so the label
   just has to cover it. Left visible rather than hover-only — the toggle
   sits well below the fold on touch, where there is no hover to reveal it. */
.is-edit-mode .social-node__image-edit {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  padding: 6px;
  cursor: pointer;
}
.is-edit-mode .social-node__image-edit-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 7px;
  border-radius: 999px;
  background: rgba(20, 12, 13, .78);
  color: #fff;
  font-size: 10.5px;
  font-weight: 650;
  transition: background .15s ease;
}
.is-edit-mode .social-node__image-edit-tag .icon { width: 11px; height: 11px; }
.is-edit-mode .social-node__image-edit:hover .social-node__image-edit-tag,
.is-edit-mode .social-node__image-edit:focus-within .social-node__image-edit-tag {
  background: var(--brand);
}
/* The file input stays in the document (so a click anywhere on the label
   opens it) but off-screen — the label is the control the admin sees. */
.is-edit-mode .social-node__image-edit input[type="file"] {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0; padding: 0; margin: -1px;
}

/* The X card has no image today, so its shot slot only exists in Edit Mode:
   a dashed "add a photo" tile in the same frame every other card's photo
   fills, rather than a control bolted on somewhere else on the card. */
.is-edit-mode .social-node__shot--empty {
  display: flex;
  border: 1.5px dashed var(--line);
  background: var(--navy-050);
}
/* .social-node__image-edit--add carries no styling of its own beyond this
   selector's existence — the "Add image" control is the exact same corner
   pill badge as "Replace" on every other card (see .social-node__image-edit
   and .social-node__image-edit-tag above), not a distinct look. */
.is-edit-mode .social-node__shot--empty:hover .social-node__image-edit,
.is-edit-mode .social-node__image-edit--add:focus-within {
  border-color: var(--brand);
}

/* ---- Edit Mode: the card's own "Add Link" / "Change Link" control -------
   Sits below the caption, inside the card, as its own fixed-height row —
   flex: none, same as .social-node__head, so it never eats into the shot's
   flexible space beyond the one row it needs. A pill in the same visual
   language as .social-node__image-edit-tag rather than the card's own link
   styling, since the card itself is a <div> (not a link) whenever this
   button can exist at all. */
.social-node__link-btn {
  display: none;
}
.is-edit-mode .social-node__link-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex: none;
  margin-top: 7px;
  padding: 5px 9px;
  border: 1px dashed var(--line);
  border-radius: 999px;
  background: var(--navy-050);
  color: var(--ink-2);
  font: inherit;
  font-size: 11px;
  font-weight: 650;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.is-edit-mode .social-node__link-btn .icon { width: 11px; height: 11px; }
.is-edit-mode .social-node__link-btn:hover,
.is-edit-mode .social-node__link-btn:focus-visible {
  border-color: var(--brand);
  border-style: solid;
  background: var(--brand);
  color: #fff;
}

/* ---- latest from us ------------------------------------------------------ */

.social-latest { margin-top: 30px; }
.social-latest .section__head { margin-bottom: 12px; }

.social-more {
  flex: none;
  display: none;                         /* until app.js can honour it */
  align-items: center; gap: 7px;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--navy-700);
  font: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer;
  transition: background .15s, border-color .15s;
}
.social.is-ready .social-more { display: inline-flex; }
.social-more:hover { background: var(--navy-050); border-color: #edb9bc; }
.social-more:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }
.social-more .icon { width: 15px; height: 15px; transition: transform .25s ease; }
.social-more[aria-expanded="true"] .icon { transform: rotate(90deg); }

/* A rail while it is collapsed: one row that scrolls sideways when the page
   is too narrow to hold six. Expanded, it becomes an ordinary grid — the
   posts are the same elements either way. */
.social-rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(190px, 1fr);
  gap: 12px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  scroll-snap-type: x proximity;
  padding-bottom: 7px;
}
.social-rail > * { scroll-snap-align: start; }
.social.is-ready .social-post--extra { display: none; }
.social-rail.is-open {
  grid-auto-flow: row;
  grid-template-columns: repeat(auto-fill, minmax(228px, 1fr));
  grid-auto-columns: auto;
  overflow: visible;
}
.social.is-ready .social-rail.is-open .social-post--extra { display: flex; }

.social-post {
  display: flex;
  flex-direction: column;
  padding: 10px;
  padding-bottom: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--ink);
  text-decoration: none;
  transition: box-shadow .2s ease, transform .2s ease;
}
.social-post:hover,
.social-post:focus-visible {
  text-decoration: none;
  transform: translateY(-3px);
  box-shadow: var(--shadow-2);
}
.social-post:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }

.social-post__head { display: flex; align-items: center; gap: 7px; margin-bottom: 8px; }
.social-post__platform { font-size: 12.5px; font-weight: 650; color: var(--navy-900); }
.social-post__when { margin-left: auto; font-size: 11px; color: var(--ink-3); white-space: nowrap; }

/* A text post has no picture, so its words take the picture's place rather
   than leaving a hole where one would have been. */
.social-post__quote {
  display: flex;
  align-items: center;
  flex: 1;
  padding: 14px 12px;
  border-radius: var(--r-sm);
  background: var(--bg);
  border: 1px solid var(--line-2);
  font-family: var(--serif);
  font-size: 14px;
  line-height: 1.45;
  color: var(--navy-800);
}

.social-post__body { margin-top: auto; padding: 8px 10px 0; }
.social-post__caption {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
}
.social-post__meta {
  display: block;
  margin-top: 6px;
  margin-left: -10px;
  margin-right: -10px;
  padding: 7px 10px;
  border-top: 1px solid var(--line-2);
  font-size: 11.5px;
  color: var(--ink-3);
}

/* ---- the sign-off -------------------------------------------------------- */

.social-signoff {
  margin: 30px 0 6px;
  padding: 21px 16px 4px;
  border-top: 1px solid var(--line);
  text-align: center;
}
.social-signoff__mark { color: var(--navy-600); }
.social-signoff__text {
  max-width: 46ch;
  margin: 7px auto 0;
  font-family: var(--serif);
  font-size: 15px;
  color: var(--navy-800);
}
.social-signoff__handle {
  margin: 6px 0 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-3);
}

/* ---- the spotlight grid ---------------------------------------------------
   Container queries, not media queries: this page runs inside the section
   modal as often as it runs on its own URL, and the modal's dialog is always
   narrower than the window it sits in. */
.social { container-type: inline-size; }

/* --------------------------------------------------------------------------
   Social Media Card Manager (administrator Edit Mode)
   -------------------------------------------------------------------------- */
.social-manager {
  margin: 0 0 22px;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
.social-manager__head,
.social-manager__slot-head,
.social-manager__editor-head,
.social-manager__editor-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}
.social-manager__head { align-items: flex-start; }
.social-manager h2,
.social-manager h3 { margin: 0; color: var(--navy-900); }
.social-manager h2 { font-size: 20px; }
.social-manager h3 { font-size: 17px; }
.social-manager__hint,
.social-manager__form-hint {
  max-width: 70ch;
  margin: 5px 0 0;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.5;
}
.social-manager__status { min-height: 20px; color: var(--ink-2); font-size: 12px; }
.social-manager__status[data-state="error"] { color: var(--brand); }
.social-manager__status[data-state="saved"] { color: var(--navy-700); }
.social-manager__grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
  margin-top: 16px;
}
.social-manager__slot {
  min-width: 0;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg);
  transition: border-color .18s ease, background .18s ease, opacity .18s ease;
}
.social-manager__slot.is-hidden { opacity: .62; }
.social-manager__slot-head { align-items: flex-start; }
.social-manager__slot-head strong {
  display: block;
  margin-top: 3px;
  color: var(--navy-900);
  font-size: 13px;
}
.social-manager__slot-label {
  display: block;
  color: var(--ink-3);
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.social-manager__badge {
  padding: 3px 7px;
  border-radius: 999px;
  background: var(--navy-100);
  color: var(--navy-700);
  font-size: 10px;
  font-weight: 700;
  text-transform: capitalize;
}
.social-manager__current {
  min-height: 38px;
  margin: 10px 0;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 1.45;
}
.social-manager__actions { display: flex; flex-wrap: wrap; gap: 6px; }
.social-manager__actions .btn { min-height: 34px; font-size: 11px; }
.social-manager__editor {
  margin-top: 16px;
  padding: 16px;
  border: 1px solid #edb9bc;
  border-radius: var(--r-sm);
  background: var(--navy-050);
}
.social-manager__editor-head { margin-bottom: 13px; }
.social-manager__url-row { display: flex; gap: 8px; margin-top: 6px; }
.social-manager__url-row input,
.social-manager__url-row textarea {
  flex: 1;
  min-width: 0;
  min-height: 40px;
  padding: 8px 11px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
}
.social-manager__url-row input:focus,
.social-manager__url-row textarea:focus {
  outline: 2px solid var(--navy-600);
  outline-offset: 2px;
}
.social-manager__preview {
  margin-top: 13px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.5;
}
.social-manager__preview strong { color: var(--navy-900); }
.social-manager__preview a { overflow-wrap: anywhere; }
.social-manager__preview.is-error { border-color: #d67578; color: #8e252a; }
.social-manager__preview ul { margin: 7px 0 0 18px; padding: 0; }
.social-manager__editor-actions { justify-content: flex-end; margin-top: 14px; }
.social-manager .icon-btn {
  width: 36px;
  height: 36px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}
.social-manager .icon-btn:hover,
.social-manager .icon-btn:focus-visible { border-color: var(--brand); color: var(--brand); }

/* A hidden slot keeps its grid footprint so the bento arrangement does not
   reshuffle. Administrators can still see the slot while Edit Mode is on. */
.social-node--hidden { visibility: hidden; pointer-events: none; }
.is-edit-mode .social-node--hidden { visibility: visible; opacity: .5; }

@container (max-width: 920px) {
  .social-manager__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container (max-width: 560px) {
  .social-manager { padding: 14px; }
  .social-manager__grid { grid-template-columns: 1fr; }
  .social-manager__url-row { flex-direction: column; }
  .social-manager__url-row .btn { width: 100%; }
}

.social-spotlight {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1fr;
  grid-auto-rows: minmax(210px, auto);
  gap: 16px;
  margin-top: 6px;
}
/* The hero tile — the first saved post — spans both rows of column one; the
   rest auto-place into the 2x2 beside it. No per-card rule needed.

   The span is conditional because the grid no longer always holds five
   cards: with one or two posts there is no second row to span, and a tile
   stretched over one would leave a column of empty grid beside it. Those two
   counts lay out as plain equal columns instead. */
.social-spotlight[data-social-count="1"] { grid-template-columns: minmax(0, 620px); }
.social-spotlight[data-social-count="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.social-spotlight:not([data-social-count="1"]):not([data-social-count="2"]) .social-node:first-child {
  grid-row: span 2;
}
/* The hero has room to spare, so its caption is allowed to run longer than
   the 2-line clamp every other card keeps. */
.social-spotlight .social-node:first-child .social-node__caption {
  -webkit-line-clamp: 4;
}

@container (max-width: 900px) {
  .social-spotlight {
    grid-template-columns: repeat(2, 1fr);
    grid-auto-rows: minmax(220px, auto);
  }
  .social-spotlight .social-node:first-child {
    grid-column: 1 / -1;
    grid-row: auto;
  }
}

@container (max-width: 560px) {
  .social-spotlight { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .social-node:hover,
  .social-node:focus-visible,
  .social-post:hover { transform: none; }
  .social-more .icon { transition: none; }
}

/* ==========================================================================
   About NCIA — Culture (about/culture): the wall of values
   --------------------------------------------------------------------------
   The sixth About section, and the third to live in this stylesheet: it is an
   ordinary page, so the map's section modal fetches it with ?partial=1 and a
   partial response never gets to add a <link>. Its behaviour is in
   initCulture() inside app.js for the same reason.

   The wall is the signature block. Each value is a full-height panel that
   stands closed as a spine — its name turned on its side — and opens to a
   photograph and a sentence when the visitor comes to it. The accordion is
   pure CSS: :hover opens a panel with no scripting at all, and the script only
   adds what hover cannot (a sticky panel for touch, and keyboard control).
   Below 900px the wall stops being a wall and becomes a stack of ordinary
   cards, all open, from the same markup.
   ========================================================================== */

.culture { container-type: inline-size; }

/* ---- the statement ------------------------------------------------------- */

.culture-statement {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 24px;
  align-items: center;
  margin-top: 4px;
  padding: 24px 24px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.culture-statement__headline {
  font-size: clamp(19.5px, 2.3cqw, 23.5px);
  line-height: 1.24;
  margin-bottom: 12px;
  max-width: 22ch;
}
.culture-statement__text {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.68;
  color: var(--ink-read);
  max-width: 62ch;
}

/* The quote is placed to be read after the claim above it, because it is the
   more convincing of the two and a visitor believes the employee before they
   believe the company. */
.culture-statement__quote {
  margin: 16px 0 0;
  padding: 2px 0 2px 15px;
  border-left: 3px solid var(--navy-600);
}
.culture-statement__quote blockquote {
  margin: 0;
  font-family: var(--serif);
  font-size: 15.5px;
  line-height: 1.45;
  color: var(--navy-800);
}
.culture-statement__quote figcaption {
  margin-top: 7px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-3);
}
.culture-statement__role { color: var(--ink-3); font-weight: 400; }
.culture-statement__role::before { content: " · "; }

.culture-statement__figure {
  position: relative;
  margin: 0;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--navy-050);
}
.culture-statement__figure img {
  display: block;
  width: 100%;
  height: auto;                      /* the width/height attributes map to a
                                        presentational height hint, which beats
                                        `auto` and would defeat aspect-ratio */
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* ---- Edit Mode: click a Culture photo to replace or add one -------------
   The same click-to-replace control as About > Social Media
   (.social-node__image-edit and friends in style.css), reused here under its
   own class names for every image slot on this page — the hero photo, each
   value panel's shot, each moment's figure, and each voice's face. Every
   container this attaches to (.culture-statement__figure,
   .culture-value__shot, .culture-moment__figure, .culture-voice__face-wrap)
   is already, or is made, position: relative so the label can cover it with
   inset: 0. */
.is-edit-mode .culture-img-edit {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  padding: 6px;
  cursor: pointer;
  z-index: 3;                        /* above the value panel's own scrim/spine layers */
  /* On every other slot this label's inset:0 box exactly covers a dedicated
     thumbnail, so blanketing it is fine. .culture-value__shot is different —
     it is the whole card's background layer (see the specificity note a few
     lines above .culture-value__shot img), so an inset:0 click target here
     would sit on top of the accordion button, the spine text and the open
     panel's own editable() fields and swallow every click on the card. The
     label itself takes no clicks; only its visible pill (the __tag span
     below) opts back in, exactly like a floating action button. */
  pointer-events: none;
}
.is-edit-mode .culture-img-edit__tag { pointer-events: auto; }
/* The value-wall control is a compact direct child of its card, so it can
   receive clicks without blanketing the editable copy beneath it. */
.is-edit-mode .culture-value > .culture-img-edit {
  inset: 6px 6px auto auto;
  padding: 0;
  pointer-events: auto;
}
.is-edit-mode .culture-img-edit__tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 7px;
  border-radius: 999px;
  background: rgba(20, 12, 13, .78);
  color: #fff;
  font-size: 10.5px;
  font-weight: 650;
  transition: background .15s ease;
}
.is-edit-mode .culture-img-edit__tag .icon { width: 11px; height: 11px; }
.is-edit-mode .culture-img-edit:hover .culture-img-edit__tag,
.is-edit-mode .culture-img-edit:focus-within .culture-img-edit__tag {
  background: var(--brand);
}
/* The file input stays in the document (so a click anywhere on the label
   opens it) but off-screen — the label is the control the admin sees. */
.is-edit-mode .culture-img-edit input[type="file"] {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0; padding: 0; margin: -1px;
}

/* A slot with no image yet only exists in Edit Mode: a dashed "add a photo"
   tile in the same frame the photograph would otherwise fill, rather than a
   control bolted on somewhere else on the card — same recipe as the social
   cards' .social-node__shot--empty. */
.is-edit-mode .culture-img-edit--empty {
  display: flex;
  border: 1.5px dashed var(--line);
  background: var(--navy-050);
}
.is-edit-mode .culture-img-edit--empty:hover .culture-img-edit,
.is-edit-mode .culture-img-edit--add:focus-within {
  border-color: var(--brand);
}

/* ---- the wall ------------------------------------------------------------ */

.culture-wall {
  display: flex;
  gap: 9px;
  height: clamp(272px, 28cqw, 356px);
}

.culture-value {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  padding: 0;
  border: 0;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--navy-900);
  color: #fff;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: flex-grow .5s cubic-bezier(.22, .72, .24, 1);
}
/* The accordion, in three rules and no JavaScript: one panel is open in the
   markup, hovering the wall closes it, and hovering a panel opens that one.
   initCulture() layers click and keyboard on top for touch and for anyone not
   using a pointer. */
.culture-value.is-open { flex-grow: 3.6; }
.culture-wall:hover .culture-value.is-open { flex-grow: 1; }
.culture-wall:hover .culture-value:hover { flex-grow: 3.6; }
.culture-value:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 3px; }

/* Specificity, not source order: `.culture-value > *` below lifts the spine
   and the panel above the scrim, and it matches this element too — as a plain
   `.culture-value__shot` rule this lost the tie and the photograph dropped
   into the flow, which pushed the panel out of the card entirely once the
   card stopped having a fixed height. */
.culture-value > .culture-value__shot { position: absolute; inset: 0; z-index: 0; }
.culture-value__shot img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: .55;
  transition: opacity .5s ease, transform .7s cubic-bezier(.22, .72, .24, 1);
}
.culture-value.is-open .culture-value__shot img,
.culture-wall:hover .culture-value:hover .culture-value__shot img { opacity: .8; transform: scale(1.04); }
.culture-wall:hover .culture-value.is-open:not(:hover) .culture-value__shot img { opacity: .55; transform: none; }

/* the scrim that keeps type legible over any photograph the company drops in */
.culture-value::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(200deg, rgba(43, 12, 14, .28), rgba(43, 12, 14, .82) 72%);
}
.culture-value > * { position: relative; z-index: 2; }

/* ---- closed: the spine ---- */

.culture-value__spine {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  padding: 16px 0 18px;
  opacity: 1;
  transition: opacity .3s ease;
}
.culture-value__spine .culture-value__no {
  order: -1;
  margin-bottom: auto;
}
.culture-value__name {
  /* turned on its side, which is what lets a closed panel be 80px wide and
     still say what it is */
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 650;
  letter-spacing: .02em;
  white-space: nowrap;
}

.culture-value__no {
  font-family: var(--serif);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .1em;
  color: rgba(255, 255, 255, .62);
}

/* ---- open: the panel ---- */

.culture-value__panel {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 21px 21px 19px;
  width: clamp(280px, 30cqw, 420px);   /* fixed, so the copy does not reflow
                                          while the panel is still widening */
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .32s ease .1s, transform .38s cubic-bezier(.22, .72, .24, 1) .1s;
  pointer-events: none;
}
/* In reading mode the panel is only a visual part of the accordion, so it
   deliberately lets clicks reach the card. In Edit Mode it contains real
   contenteditable fields, which must receive the pointer and keyboard focus
   themselves rather than being treated as part of the card control. */
.is-edit-mode .culture-value { cursor: default; }
.is-edit-mode .culture-value__panel { pointer-events: auto; }
.is-edit-mode .culture-value [contenteditable] { cursor: text; }
/* The general Edit Mode treatment uses the light page surface on focus. These
   fields live on the dark image card, so keep their edit affordance dark and
   legible instead of turning the active field into a white block. */
.is-edit-mode .culture-value [data-edit-key]:hover {
  outline-color: rgba(255, 255, 255, .78);
  background: rgba(255, 255, 255, .10);
}
.is-edit-mode .culture-value [data-edit-key]:focus {
  outline: 2px solid #fff;
  outline-offset: 3px;
  background: rgba(255, 255, 255, .14);
}
.is-edit-mode .culture-value [data-edit-key]:empty::before {
  color: rgba(255, 255, 255, .72);
}
.culture-value.is-open .culture-value__panel,
.culture-wall:hover .culture-value:hover .culture-value__panel { opacity: 1; transform: none; }
.culture-wall:hover .culture-value.is-open:not(:hover) .culture-value__panel {
  opacity: 0;
  transform: translateY(10px);
  transition-delay: 0s;
}

.culture-value__title {
  margin: 7px 0 7px;
  font-family: var(--serif);
  font-size: clamp(19px, 2.1cqw, 22.5px);
  font-weight: 650;
  line-height: 1.15;
  letter-spacing: -.01em;
}
.culture-value__blurb {
  font-size: 14px;
  line-height: 1.6;
  color: rgba(255, 255, 255, .84);
}

/* The spine has to leave while the panel arrives, or the turned name sits
   across the open copy for a third of a second. */
.culture-value.is-open .culture-value__spine,
.culture-wall:hover .culture-value:hover .culture-value__spine { opacity: 0; }
.culture-wall:hover .culture-value.is-open:not(:hover) .culture-value__spine { opacity: 1; }

/* ---- culture in action --------------------------------------------------- */

.culture-moments { display: grid; gap: 12px; }

.culture-moment {
  display: grid;
  grid-template-columns: minmax(0, 290px) minmax(0, 1fr);
  align-items: stretch;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}
/* Alternating sides, so the band reads as a sequence of separate occasions
   rather than a grid of interchangeable tiles. */
.culture-moment:nth-child(even) { grid-template-columns: minmax(0, 1fr) minmax(0, 340px); }
.culture-moment:nth-child(even) .culture-moment__figure { order: 2; }

.culture-moment__figure { position: relative; margin: 0; background: var(--navy-050); }
.culture-moment__figure img {
  display: block;
  width: 100%; height: 100%;
  min-height: 129px;
  object-fit: cover;
}
.culture-moment__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 18px 21px;
}
.culture-moment__when {
  margin: 0 0 6px;
  font-size: 11px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--navy-600);
}
.culture-moment__title { font-size: 18px; margin-bottom: 7px; }
.culture-moment__blurb {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--ink-2);
  max-width: 62ch;
}

/* ---- voices -------------------------------------------------------------- */

.culture-voices {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
.culture-voice {
  display: flex;
  flex-direction: column;
  padding: 18px 18px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
/* One quote may take the wide cell — a wall of equal quotes reads as a survey
   result rather than as people talking. */
.culture-voice--featured { grid-column: span 2; }
.culture-voice--featured .culture-voice__quote { font-size: 18px; }

.culture-voice__quote {
  margin: 0 0 15px;
  font-family: var(--serif);
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--navy-800);
  max-width: 54ch;
}
.culture-voice__quote::before { content: "\201C"; }
.culture-voice__quote::after  { content: "\201D"; }

.culture-voice__who {
  margin-top: auto;
  display: flex; align-items: center; gap: 10px;
  padding-top: 12px;
  border-top: 1px solid var(--line-2);
}
.culture-voice__face {
  display: block;
  width: 100%; height: 100%;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 34%;      /* the frame is head-and-shoulders; a centred
                                    crop would land under the chin */
  background: var(--navy-050);
}
/* The face's own wrapper — needed so the click-to-replace label (position:
   absolute; inset: 0) has a circular, correctly-sized box to cover even when
   no photo has been uploaded yet, the same job .social-node__shot does for
   a social card's image. */
.culture-voice__face-wrap {
  position: relative;
  flex: none;
  width: 40px; height: 40px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--navy-050);
}
.is-edit-mode .culture-voice__face-wrap.culture-img-edit--empty {
  border-radius: 50%;            /* the generic dashed tile is square-cornered by default */
}
.culture-voice__text { display: flex; flex-direction: column; min-width: 0; }
.culture-voice__name { font-size: 13.5px; font-weight: 650; color: var(--navy-900); }
.culture-voice__role { font-size: 12.5px; color: var(--ink-3); }

/* ---- life here ----------------------------------------------------------- */

/* An explicit row height rather than aspect ratios: a wall of photographs is
   the one block on the page with no words in it, so the cells have to line up
   exactly or the whole thing reads as a mistake. */
.culture-gallery {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 142px;
  grid-auto-flow: dense;
  gap: 10px;
}
.culture-gallery__cell {
  position: relative;
  margin: 0;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--navy-050);
}
.culture-gallery__cell img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .55s cubic-bezier(.22, .72, .24, 1);
}
.culture-gallery__cell:hover img { transform: scale(1.05); }

.culture-gallery__cell.is-wide { grid-column: span 2; }
.culture-gallery__cell.is-tall { grid-row: span 2; }
.culture-gallery__cell.is-big  { grid-column: span 2; grid-row: span 2; }

/* ---- traditions ---------------------------------------------------------- */

/* A ledger rather than cards: the cadence is the column a reader scans, and
   putting six of them in a row of boxes would bury it. */
.culture-traditions {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}
.culture-tradition {
  display: grid;
  grid-template-columns: 168px minmax(0, 1fr);
  gap: 16px;
  align-items: baseline;
  padding: 14px 18px;
  border-top: 1px solid var(--line-2);
}
.culture-tradition:first-child { border-top: 0; }
.culture-tradition__when {
  font-size: 11px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--navy-600);
}
.culture-tradition__body { display: flex; flex-direction: column; gap: 3px; }
.culture-tradition__title {
  font-family: var(--serif);
  font-size: 15.5px; font-weight: 650;
  color: var(--navy-900);
}
.culture-tradition__blurb { font-size: 13.5px; color: var(--ink-2); line-height: 1.55; }

/* ---- the numbers --------------------------------------------------------- */

/* Deliberately not the Community page's bordered strip: same idea, and using
   the same box twice in one section would make two different claims look like
   one repeated component. These sit on the page itself, under a rule. */
.culture-numbers {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
.culture-number {
  padding: 4px 4px 12px;
  border-bottom: 2px solid var(--line);
}
.culture-number__value {
  margin: 0 0 2px;
  font-family: var(--serif);
  font-size: clamp(23.5px, 3.2cqw, 30px);
  line-height: 1.05;
  font-weight: 650;
  letter-spacing: -.02em;
  color: var(--navy-700);
}
.culture-number__label { margin: 0; font-size: 12.5px; color: var(--ink-3); }

/* ---- the way out --------------------------------------------------------- */

.culture-careers {
  margin: 33px 0 7px;
  padding: 25px 22px 27px;
  text-align: center;
  background: var(--navy-050);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.culture-careers__award {
  display: inline-flex; align-items: center; gap: 8px;
  margin-bottom: 16px;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 12.5px; font-weight: 600;
  color: var(--navy-800);
}
.culture-careers__award:hover { text-decoration: none; border-color: var(--navy-600); }
.culture-careers__award .icon { width: 15px; height: 15px; color: var(--amber-600); }
.culture-careers__award-go { color: var(--navy-700); display: inline-flex; align-items: center; gap: 5px; }
.culture-careers__award-go .icon { width: 14px; height: 14px; color: currentColor; transition: transform .2s ease; }
.culture-careers__award:hover .culture-careers__award-go .icon { transform: translateX(3px); }

.culture-careers__headline { font-size: clamp(20px, 2.6cqw, 25px); }
.culture-careers__blurb {
  max-width: 54ch;
  margin: 9px auto 16px;
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--ink-read);
}
.culture-careers .btn .icon { transition: transform .2s ease; }
.culture-careers .btn:hover .icon { transform: translateX(3px); }

/* ---- narrower pages ------------------------------------------------------ */

@container (max-width: 1080px) {
  .culture-voices { grid-template-columns: repeat(2, 1fr); }
  .culture-voice--featured { grid-column: span 2; }
  .culture-numbers { grid-template-columns: repeat(2, 1fr); }
  .culture-gallery { grid-template-columns: repeat(3, 1fr); }
}

/* Past here a closed panel is narrower than the turned name inside it, and
   the open one has no room left for its sentence. The wall becomes a stack of
   ordinary cards — every value open, nothing hidden behind a hover that a
   phone cannot perform anyway. */
@container (max-width: 900px) {
  .culture-wall {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    height: auto;
  }
  /* The copy sits at the foot of the card here too, which is where the scrim
     is darkest — anchored at the top it landed on the lightest part of the
     gradient and the white type washed out. */
  .culture-value {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-height: 170px;
    flex: none;
  }
  .culture-value__spine,
  .culture-wall:hover .culture-value.is-open:not(:hover) .culture-value__spine { display: none; }
  .culture-value__panel,
  .culture-wall:hover .culture-value.is-open:not(:hover) .culture-value__panel {
    position: static;
    width: auto;
    opacity: 1;
    transform: none;
  }
  .culture-value__shot img,
  .culture-wall:hover .culture-value.is-open:not(:hover) .culture-value__shot img { opacity: .7; }

  .culture-moment,
  .culture-moment:nth-child(even) { grid-template-columns: 1fr; }
  .culture-moment:nth-child(even) .culture-moment__figure { order: 0; }
  .culture-moment__figure img { max-height: 210px; }

  .culture-statement { grid-template-columns: 1fr; padding: 19px; }
  .culture-statement__figure { order: -1; }

  .culture-tradition { grid-template-columns: 1fr; gap: 4px; padding: 12px 15px; }
}

@container (max-width: 620px) {
  .culture-wall { grid-template-columns: 1fr; }
  .culture-voices { grid-template-columns: 1fr; }
  .culture-voice--featured { grid-column: span 1; }
  .culture-numbers { grid-template-columns: 1fr; }
  .culture-gallery { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 132px; }
}

@media (prefers-reduced-motion: reduce) {
  .culture-value,
  .culture-value__shot img,
  .culture-value__panel,
  .culture-value__spine,
  .culture-gallery__cell img,
  .culture-careers .btn .icon,
  .culture-careers__award-go .icon { transition: none; }
  .culture-value.is-open .culture-value__shot img,
  .culture-wall:hover .culture-value:hover .culture-value__shot img { transform: none; }
  .culture-gallery__cell:hover img { transform: none; }
}

/* ==========================================================================
   About NCIA — "What we place" (about/index)
   --------------------------------------------------------------------------
   Every line of cover the agency arranges, in the column the lorem timeline
   used to hold. It sits under six big section cards and beside the mission
   card, so it stays deliberately calmer than those: bordered cards, but one
   flat tone rather than the six-colour ring above — a list of lines, not a
   third set of destinations.

   Admin-addable (about_cover_items — see about_cover_items_rows() in
   app/Data/about.php), so the layout has to keep reading cleanly as cards are
   added or removed. A two-column CSS multi-column (not grid) fills
   column-first — card 1 top-left, card 2 top-right, card 3 sits directly
   under card 1 — and reflows on its own when a card is removed, unlike a
   grid with explicit tracks.
   ========================================================================== */

/* The mission card used to be sticky here, on the theory that a short card
   beside a much taller list should travel with the reader rather than get
   left behind. In practice a pinned card and a long scroll do the opposite of
   what that theory intended: the card parks near the top of the viewport and
   the rest of the column below it sits empty for as long as the list keeps
   going, which reads as an abandoned panel rather than a considered layout.
   Ordinary flow instead: the card ends where its own content ends, the same
   way any shorter sidebar does next to a longer one. */

.cover-lede {
  margin: -4px 0 18px;
  font-size: 13.5px;
  color: var(--ink-2);
  max-width: 80ch;
}

.cover-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.cover-cards__card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 14px;
}

.cover-cards__icon {
  width: 34px; height: 34px; border-radius: 9px;
  display: grid; place-items: center; margin-bottom: 10px;
  background: var(--navy-100); color: var(--navy-700);
}
.cover-cards__icon .icon-lg { width: 19px; height: 19px; }

/* The select replaces a 19px glyph with a word — "briefcase", "building" —
   so the tile that held the mark has to grow to fit text instead of
   staying pinned to icon size. Auto width off the select's own content
   rather than a fixed value, so short names ("car") don't carry the same
   padding as long ones. */
.is-edit-mode .cover-cards__icon {
  width: auto;
  height: auto;
  min-height: 25px;
  padding: 6px 9px;
}

.cover-cards__name {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
}

.cover-cards__description {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-3);
}

/* The icon <select> in Edit Mode: same tile the mark sits in off-edit, just
   wearing a caret, so picking a new icon reads as swapping the mark in place
   rather than dropping in an unrelated form control. */
.is-edit-mode .icon-select {
  appearance: none;
  -webkit-appearance: none;
  width: auto;
  max-width: none;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 11px;
  white-space: nowrap;
  cursor: pointer;
  text-align: center;
}
.is-edit-mode .icon-select:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 1px; }

.is-edit-mode .cover-cards__card .edit-remove { position: absolute; top: 8px; right: 8px; margin: 0; }

@media (max-width: 560px) {
  .cover-cards { grid-template-columns: minmax(0, 1fr); }
}

/* The six top cards (History/Awards/Offices/Community/Social Media/Culture),
   scoped so it only touches this grid and not .card__icon sitewide. Same
   tone/tone-soft custom-property pair as the About map's own cards, one
   colour per card so the row reads as six distinct destinations rather than
   six copies of the same tile. */
.about-cards .card__icon { background: var(--tone-soft, var(--navy-100)); color: var(--tone, var(--navy-700)); }
.about-cards .card.tone-blue   { --tone: var(--tag-blue-fg);   --tone-soft: var(--tag-blue-bg); }
.about-cards .card.tone-teal   { --tone: var(--tag-teal-fg);   --tone-soft: var(--tag-teal-bg); }
.about-cards .card.tone-purple { --tone: var(--tag-purple-fg); --tone-soft: var(--tag-purple-bg); }
.about-cards .card.tone-amber  { --tone: var(--tag-amber-fg);  --tone-soft: var(--tag-amber-bg); }
.about-cards .card.tone-green  { --tone: var(--tag-green-fg);  --tone-soft: var(--tag-green-bg); }
.about-cards .card.tone-red    { --tone: var(--tag-red-fg);    --tone-soft: var(--tag-red-bg); }

/* ===========================================================================
   About NCIA landing page (about/index)
   ---------------------------------------------------------------------------
   A compact, reference-led composition: six illustrated destinations above
   a wider insurance list and two quiet principle cards. All selectors are
   page-specific so the six destination pages remain visually untouched.
   ======================================================================== */

.about-landing {
  padding-top: var(--ui-space-lg);
}

/* The modal already names the destination. Keep one real h1 for document
   structure without spending the vertical space the compact grid needs. */
.about-landing__title {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.about-nav-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.about-nav-card {
  position: relative;
  isolation: isolate;
  min-width: 0;
  min-height: 168px;
  overflow: hidden;
  padding: 20px 64px 18px 22px;
  color: var(--ink);
  background: #fffdfd;
  border: 1px solid #efe2e2;
  border-radius: 11px;
  box-shadow: 0 2px 8px rgba(74, 5, 9, .045), 0 9px 24px rgba(74, 5, 9, .045);
  text-decoration: none;
  cursor: pointer;
  transition: transform .2s ease, border-color .2s ease, box-shadow .2s ease;
}

a.about-nav-card { display: block; }
a.about-nav-card:hover {
  color: var(--ink);
  border-color: #e8c4c6;
  box-shadow: 0 4px 10px rgba(74, 5, 9, .07), 0 15px 30px rgba(74, 5, 9, .075);
  text-decoration: none;
  transform: translateY(-3px);
}
.about-nav-card:focus-visible {
  outline: 3px solid rgba(211, 19, 29, .35);
  outline-offset: 2px;
}

.about-nav-card__content {
  position: relative;
  z-index: 2;
  max-width: 66%;
}

.about-nav-card__icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-bottom: 8px;
  color: var(--navy-600);
}
.about-nav-card__icon .icon-lg { width: 29px; height: 29px; }

.about-nav-card__title {
  margin: 0 0 5px;
  color: #221719;
  font-family: var(--font);
  font-size: 18px;
  font-weight: 680;
  line-height: 1.2;
  letter-spacing: -.02em;
}

.about-nav-card__description {
  margin: 0;
  color: var(--ink-2);
  font-size: 12.5px;
  line-height: 1.48;
}

.about-nav-card__art {
  position: absolute;
  z-index: 0;
  right: 0;
  bottom: 0;
  width: 88%;
  height: 100%;
  object-fit: contain;
  object-position: right bottom;
  opacity: .7;
  filter: saturate(1.35) contrast(1.08);
  pointer-events: none;
  user-select: none;
  transition: opacity .2s ease, transform .2s ease;
}
.about-nav-card:hover .about-nav-card__art { opacity: .84; }

/* Rich-text toolbars sit just outside the field while editing. Let the
   active card release its clipping boundary so the toolbar is usable on
   titles and descriptions near the top edge; inactive cards keep their
   artwork safely clipped. */
.is-edit-mode .about-nav-card:has(.richtext:hover),
.is-edit-mode .about-nav-card:has(.richtext:focus-within),
.is-edit-mode .about-principle-card:has(.richtext:hover),
.is-edit-mode .about-principle-card:has(.richtext:focus-within),
.is-edit-mode .about-place-panel:has(.richtext:hover),
.is-edit-mode .about-place-panel:has(.richtext:focus-within) {
  overflow: visible;
}

/* A fixed toolbar still lives inside its card's stacking context. Raise the
   active card itself, not just the toolbar, so neighboring cards cannot paint
   over the toolbar or a resize handle. */
.is-edit-mode .about-nav-card:has(.richtext--toolbar-active),
.is-edit-mode .about-principle-card:has(.richtext--toolbar-active),
.is-edit-mode .about-place-panel:has(.richtext--toolbar-active) {
  z-index: 20;
}

/* NCIA7 has two additional clipping layers: its content column and the
   scrolling principles accordion. Release them only for the active editor so
   a toolbar can sit above the card (or above an individual principle)
   without changing the artwork clipping or the normal card layout. */
.is-edit-mode .about-principle-card--ncia7:has(.richtext:hover),
.is-edit-mode .about-principle-card--ncia7:has(.richtext:focus-within),
.is-edit-mode .about-principle-card--ncia7:has(.richtext--toolbar-active) {
  z-index: 20;
}
.is-edit-mode .about-principle-card--ncia7:has(.richtext:hover) .about-principle-card__content,
.is-edit-mode .about-principle-card--ncia7:has(.richtext:focus-within) .about-principle-card__content,
.is-edit-mode .about-principle-card--ncia7:has(.richtext--toolbar-active) .about-principle-card__content,
.is-edit-mode .about-principle-card--ncia7 .cover-accordion--ncia7:has(.richtext:hover),
.is-edit-mode .about-principle-card--ncia7 .cover-accordion--ncia7:has(.richtext:focus-within),
.is-edit-mode .about-principle-card--ncia7 .cover-accordion--ncia7:has(.richtext--toolbar-active) {
  overflow: visible;
}

.about-nav-card--purpose {
  display: block;
  min-height: 154px;
  margin-bottom: 14px;
  padding-right: 28%;
  cursor: default;
}
.about-nav-card--purpose .about-nav-card__content {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  column-gap: 12px;
  align-items: start;
  max-width: 72%;
}
.about-nav-card--purpose .about-nav-card__icon {
  grid-column: 1;
  grid-row: 1 / span 2;
  margin: 0;
}
.about-nav-card--purpose .about-nav-card__title,
.about-nav-card--purpose .about-nav-card__description {
  grid-column: 2;
  min-width: 0;
}
.about-nav-card--purpose .about-nav-card__art {
  width: 48%;
  opacity: .42;
}
.about-nav-card--purpose:hover .about-nav-card__art { opacity: .28; }

/* In Edit Mode the purpose statement may use the whole purpose card. The
   artwork is a background layer, so the text surface can safely grow into
   the otherwise unused right-hand space without changing read mode. */
.is-edit-mode .about-nav-card--purpose {
  padding-right: 18px;
}
.is-edit-mode .about-nav-card--purpose .about-nav-card__content {
  max-width: 100%;
}

/* Once the administrator has deliberately widened either purpose field,
   read mode must use the same available card width as Edit Mode. */
.about-nav-card--purpose:has([data-edit-layout]) {
  padding-right: 18px;
}
.about-nav-card--purpose:has([data-edit-layout]) .about-nav-card__content {
  width: 100%;
  max-width: 100%;
}

.about-nav-card__arrow {
  position: absolute;
  z-index: 3;
  right: 15px;
  bottom: 14px;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  color: var(--navy-600);
  background: rgba(255, 255, 255, .88);
  border: 1px solid #efcfd0;
  border-radius: 50%;
  text-decoration: none;
  transition: color .18s ease, background .18s ease, border-color .18s ease, transform .18s ease;
}
.about-nav-card__arrow .icon { width: 15px; height: 15px; }
a.about-nav-card:hover .about-nav-card__arrow,
.about-nav-card__arrow:hover {
  color: #fff;
  background: var(--navy-600);
  border-color: var(--navy-600);
  text-decoration: none;
  transform: translateX(2px);
}
.about-nav-card__arrow:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }

/* Edit Mode keeps the visual card but removes the pointer cue from the
   editable surface; its circular arrow remains the explicit navigation. */
.is-edit-mode .about-nav-card { cursor: default; }
.is-edit-mode .about-nav-card__content { max-width: 72%; }

.about-overview-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr);
  gap: 18px;
  align-items: stretch;
  margin-top: 18px;
}

.about-handbook-action {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  width: 100%;
  margin-top: 18px;
  padding: 0 22px 18px;
  box-sizing: border-box;
}
.about-handbook-action .btn { margin-top: 0 !important; }

.about-overview-grid > .about-principle-card--ncia7 {
  grid-column: 1;
  grid-row: 1;
  min-height: 0;
  overflow: hidden;
}
.about-overview-grid > .about-principles {
  grid-column: 2;
  grid-row: 1;
}
.about-overview-grid > .about-foundation-grid {
  grid-column: 1 / -1;
  grid-row: 2;
}
.about-overview-grid > .about-place-panel {
  grid-column: 1 / -1;
  grid-row: 3;
  margin-top: 0;
}

.about-place-panel,
.about-principle-card {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: #fffdfd;
  border: 1px solid #efe2e2;
  border-radius: 11px;
  box-shadow: 0 2px 8px rgba(74, 5, 9, .045), 0 9px 24px rgba(74, 5, 9, .045);
}

.about-place-panel { min-width: 0; }
.about-place-panel__content {
  position: relative;
  z-index: 2;
  padding: 18px 20px 20px;
}
.about-place-panel__art {
  position: absolute;
  z-index: 0;
  left: 0;
  bottom: 0;
  width: 64%;
  height: 100%;
  object-fit: contain;
  object-position: left bottom;
  opacity: .42;
  filter: saturate(1.35) contrast(1.08);
  pointer-events: none;
  user-select: none;
}

.about-place-panel__heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
}
.about-place-panel__heading h2,
.about-principle-card h2 {
  color: #221719;
  font-family: var(--font);
  font-size: 18px;
  font-weight: 680;
  letter-spacing: -.02em;
}
.about-heading-accent {
  display: block;
  width: 28px;
  height: 2px;
  margin-top: 7px;
  background: var(--navy-600);
  border-radius: 999px;
}
.about-place-panel__heading .edit-add { flex: none; margin-top: 0; }

.about-place-panel__lede {
  max-width: 64ch;
  margin: 6px 0 8px;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 1.5;
}

.cover-accordion { border-top: 1px solid #f0e4e4; }
.cover-accordion__item {
  position: relative;
  border-bottom: 1px solid #f0e4e4;
}

.cover-accordion__toggle,
.cover-accordion__editor-head {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) 44px;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 44px;
}
.cover-accordion__toggle {
  padding: 0;
  color: var(--ink);
  background: transparent;
  border: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.cover-accordion__toggle:hover { background: rgba(253, 244, 244, .78); }
.cover-accordion__toggle:focus-visible {
  position: relative;
  z-index: 2;
  outline: 2px solid var(--navy-600);
  outline-offset: -2px;
  border-radius: 4px;
}

.cover-accordion__icon {
  display: grid;
  place-items: center;
  width: 24px;
  color: var(--navy-600);
}
.cover-accordion__icon .icon-lg { width: 18px; height: 18px; }

.cover-accordion__title {
  min-width: 0;
  margin: 0;
  color: #352326;
  font-family: var(--font);
  font-size: 12.5px;
  font-weight: 570;
  line-height: 1.35;
}

.cover-accordion__chevron {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  color: var(--navy-600);
  background: transparent;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
}
.cover-accordion__chevron .icon {
  width: 14px;
  height: 14px;
  transition: transform .2s ease;
}
.cover-accordion__item.is-open .cover-accordion__chevron .icon { transform: rotate(180deg); }
.cover-accordion__chevron:focus-visible { outline: 2px solid var(--navy-600); outline-offset: -3px; }

.cover-accordion__content {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  transition: grid-template-rows .22s ease, visibility 0s linear .22s;
}
.cover-accordion__content-inner { min-height: 0; overflow: hidden; }
.cover-accordion__item.is-open .cover-accordion__content {
  grid-template-rows: 1fr;
  visibility: visible;
  transition: grid-template-rows .22s ease;
}
.cover-accordion__description {
  margin: 0;
  padding: 0 42px 11px 32px;
  color: var(--ink-3);
  font-size: 12px;
  line-height: 1.5;
}
.cover-accordion__empty {
  margin: 14px 0 0;
  padding: 12px;
  color: var(--ink-3);
  background: var(--navy-050);
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
  font-size: 12.5px;
}

.cover-accordion__editor-head { grid-template-columns: auto minmax(0, 1fr) auto; }
.cover-accordion__admin-actions { display: flex; align-items: center; gap: 2px; }
.is-edit-mode .cover-accordion__editor-head .cover-accordion__icon {
  width: auto;
  min-width: 54px;
  justify-content: start;
}
.is-edit-mode .cover-accordion__editor-head .icon-select {
  min-height: 30px;
  padding: 4px 20px 4px 7px;
  background: var(--navy-050);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  text-align: left;
}
.is-edit-mode .cover-accordion__item .edit-remove {
  position: static;
  width: 44px;
  height: 44px;
  margin: 0;
}

.about-principles {
  display: grid;
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: 16px;
  min-width: 0;
  min-height: 100%;
}

.about-principle-card {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  gap: 14px;
  min-height: 174px;
  padding: 20px 22px;
}
.about-principle-card__icon {
  position: relative;
  z-index: 2;
  display: grid;
  place-items: center;
  align-self: start;
  width: 52px;
  height: 52px;
  color: var(--navy-600);
  background: var(--navy-050);
  border: 1px solid #f2dada;
  border-radius: 50%;
}
.about-principle-card__icon .icon-lg { width: 27px; height: 27px; }
.about-principle-card__content {
  position: relative;
  z-index: 2;
  max-width: 68%;
  padding-top: 8px;
}
.about-principle-card__statement {
  margin: 12px 0 0;
  color: var(--ink-2);
  font-size: 12.5px;
  line-height: 1.55;
}
.about-principles .about-principle-card__content { max-width: 78%; }
.about-principles .about-principle-card__statement {
  font-size: clamp(15px, 1.05vw, 16px);
  line-height: 1.55;
}
.about-principle-card--ncia7 .about-principle-card__content {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
  max-width: 100%;
  overflow: hidden;
}
.about-principle-card--ncia7 {
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
}
.about-principle-card--ncia7 .about-principle-card__art {
  opacity: .14;
  filter: saturate(.9) contrast(.92);
}
/* The NCIA7 card now hosts the same accordion as "What we place" (see
   .cover-accordion below), so the card's own body just has to give it the
   remaining height and let it scroll — the old two-column flowing list of
   bare principle lines is gone, and with it the edit/view height mismatch
   that wrapped the seventh principle into a second column. */
.about-principle-card--ncia7 .cover-accordion--ncia7 {
  flex: 1 1 auto;
  min-height: 0;
  margin-top: 12px;
  overflow-y: auto;
}
.about-principle-card--ncia7 .edit-add {
  margin-top: 12px;
}
.about-nav-card--purpose .about-nav-card__art {
  opacity: .28;
  filter: saturate(.9) contrast(.95);
}
.about-principle-card__art {
  position: absolute;
  z-index: 0;
  right: 0;
  bottom: 0;
  width: 82%;
  height: 100%;
  object-fit: contain;
  object-position: right bottom;
  opacity: .56;
  filter: saturate(1.35) contrast(1.08);
  pointer-events: none;
  user-select: none;
}

/* The five About foundations use the same quiet card language as Vision and
   Mission, but sit in a deliberate two-column grid. Organizational Structure
   gets the final full-width row because its subject naturally benefits from
   more horizontal reading space. */
.about-foundation-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
  margin-top: 18px;
}
.about-foundation-card {
  grid-column: auto;
  min-height: 214px;
}
.about-foundation-card--service { grid-column: 1; grid-row: 1; order: 1; }
.about-foundation-card--what-counts { grid-column: 2; grid-row: 1; order: 2; }
.about-foundation-card--operating-principle { grid-column: 1; grid-row: 2; order: 3; }
.about-foundation-card--ncia-way { grid-column: 2; grid-row: 2; order: 4; }
.about-foundation-card--org-structure { grid-column: 1 / -1; grid-row: 3; order: 5; }
.about-foundation-card .about-principle-card__content {
  max-width: 76%;
  padding-top: 8px;
}
.about-foundation-card .about-principle-card__art {
  width: 76%;
  opacity: .26;
  filter: saturate(.92) contrast(.96);
}
.about-foundation-card--service .about-principle-card__art { width: 74%; opacity: .28; }
.about-foundation-card--what-counts .about-principle-card__art { width: 72%; opacity: .24; }
.about-foundation-card--operating-principle .about-principle-card__art { width: 78%; opacity: .23; }
.about-foundation-card--org-structure .about-principle-card__art { width: 70%; opacity: .25; }
.about-foundation-card--ncia-way .about-principle-card__art { width: 76%; opacity: .25; }
.about-foundation-card:hover .about-principle-card__art { opacity: .18; }

/* Organizational Structure is the one intentionally expansive foundation
   card. Keep the title/icon treatment shared with the other cards, then let
   the canonical chart and workflow use the full remaining width. */
.about-foundation-card--org-structure {
  display: block;
  min-height: 0;
  padding: 20px 22px;
}
.about-foundation-card--org-structure .about-principle-card__icon {
  position: absolute;
  top: 20px;
  left: 22px;
}
.about-foundation-card--org-structure .about-principle-card__content {
  width: 100%;
  max-width: none;
  text-align: center;
}
.about-foundation-card--org-structure .about-heading-accent {
  margin-left: auto;
  margin-right: auto;
}
.about-org-detail {
  position: relative;
  z-index: 2;
  width: 100%;
  margin-top: 18px;
  text-align: left;
}
.about-org-detail .org-chart,
.about-org-detail .waterfall {
  position: relative;
  z-index: 2;
}
.about-org-detail .article-subhead {
  margin-top: 26px;
  text-align: center;
}
.about-org-detail > .article-prose {
  max-width: 78ch;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}
.about-org-detail .edit-add {
  position: relative;
  z-index: 2;
}

@media (max-width: 960px) {
  .about-foundation-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 700px) {
  .about-handbook-action { padding-right: 18px; padding-bottom: 16px; padding-left: 18px; }
  .about-foundation-grid { grid-template-columns: minmax(0, 1fr); }
  .about-foundation-card,
  .about-foundation-card--service,
  .about-foundation-card--what-counts,
  .about-foundation-card--operating-principle,
  .about-foundation-card--ncia-way,
  .about-foundation-card--org-structure {
    grid-column: auto;
    grid-row: auto;
  }
  .about-foundation-card .about-principle-card__content { max-width: 78%; }
  .about-foundation-card--org-structure { padding: 18px; }
  .about-foundation-card--org-structure .about-principle-card__icon { top: 18px; left: 18px; }
  .about-foundation-card--org-structure .about-principle-card__content { max-width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .about-foundation-card .about-principle-card__art { transition: none; }
}

@media (max-width: 1100px) {
  .about-place-panel__content { padding-left: 20px; }
  .about-principle-card__content { max-width: 76%; }
}

@media (max-width: 960px) {
  .about-nav-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .about-overview-grid { grid-template-columns: minmax(0, 1fr); }
  .about-principles { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto; }
  .about-overview-grid > .about-principle-card--ncia7 { grid-column: 1; grid-row: 1; }
  .about-overview-grid > .about-principles { grid-column: 1; grid-row: 2; }
  .about-overview-grid > .about-foundation-grid { grid-column: 1; grid-row: 3; }
  .about-overview-grid > .about-place-panel { grid-column: 1; grid-row: 4; }
  .about-place-panel__content { padding-left: 20px; }
}

@media (max-width: 700px) {
  .about-landing { padding-top: var(--ui-space-md); }
  .about-nav-grid { grid-template-columns: minmax(0, 1fr); }
  .about-nav-card { min-height: 158px; }
  .about-nav-card--purpose { min-height: 168px; padding-right: 20px; }
  .about-nav-card--purpose .about-nav-card__content { max-width: 100%; }
  .about-principles { grid-template-columns: minmax(0, 1fr); }
  .about-principle-card--ncia7 .cover-accordion--ncia7 {
    flex: 0 0 auto;
    overflow-y: visible;
  }
  .about-place-panel__content { padding: 18px; }
  .about-place-panel__art { left: 0; width: 72%; opacity: .38; }
}

@media (max-width: 430px) {
  .about-nav-card { padding-left: 18px; }
  .about-nav-card__content { max-width: 72%; }
  .about-place-panel__heading { align-items: stretch; flex-direction: column; }
  .about-place-panel__heading .edit-add { align-self: flex-start; }
  .about-principle-card { grid-template-columns: 44px minmax(0, 1fr); gap: 11px; padding: 18px; }
  .about-principle-card--ncia7 { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .about-principle-card__icon { width: 44px; height: 44px; }
  .about-principle-card__icon .icon-lg { width: 23px; height: 23px; }
  .about-principle-card__content { max-width: 82%; padding-top: 5px; }
}

@media (prefers-reduced-motion: reduce) {
  .about-nav-card,
  .about-nav-card__art,
  .about-nav-card__arrow,
  .cover-accordion__content,
  .cover-accordion__chevron .icon { transition: none; }
  a.about-nav-card:hover,
  .about-nav-card:hover .about-nav-card__art,
  a.about-nav-card:hover .about-nav-card__arrow,
  .about-nav-card__arrow:hover { transform: none; }
}

/* ==========================================================================
   The uploaded library — administration and template reading
   --------------------------------------------------------------------------
   How We Work and Templates are filled by uploading files rather than by
   editing text, so they get their own controls rather than Edit Mode's
   in-place fields: a dialog to upload one, a mode in which every card can be
   picked and deleted, and a dialog for the two vocabularies both upload forms
   pick from.

   These styles live here rather than in a stylesheet of their own for the
   same reason the Community board's do: both pages are fetched into the map's
   section modal with ?partial=1, and a partial response never gets to add a
   <link>.
   ========================================================================== */

/* The one destructive button in the library. Outlined rather than filled —
   it sits beside Upload, which is the action the page is actually for. */
.btn--danger { border-color: #eaacb0; color: var(--tag-red-fg); }
.btn--danger:hover { background: var(--tag-red-bg); border-color: var(--tag-red-fg); }
.btn--danger[aria-pressed="true"] {
  background: var(--tag-red-fg); border-color: var(--tag-red-fg); color: #fff;
}
.btn--danger[aria-pressed="true"]:hover { background: #8f1e17; border-color: #8f1e17; }

/* --------------------------------------------------------------------------
   Delete mode
   --------------------------------------------------------------------------
   Picking is a state of the page, not of one card, so the shelf says so:
   every card leans a degree or two out of true and keeps shifting, which is
   what tells a reader at a glance that a click here removes rather than
   opens. The checkbox rides in the top-right corner of each card, and is
   rendered inert into the markup up front rather than injected — the card is
   a link, and a control that appears inside one after the fact is a control
   the browser has already decided how to treat.
   -------------------------------------------------------------------------- */

.libpick {
  position: absolute;
  top: 10px; right: 10px;
  z-index: 4;
  display: none;
}
.libpick__box {
  display: grid; place-items: center;
  width: 26px; height: 26px;
  border: 1.5px solid var(--line);
  border-radius: 7px;
  background: rgba(255, 255, 255, .94);
  box-shadow: var(--shadow-1);
  color: transparent;
}
.libpick__box .icon { width: 17px; height: 17px; }

.is-lib-picking .libpick { display: block; }
.is-lib-picking .book-card,
.is-lib-picking .tpl-card { cursor: pointer; }
.is-lib-picking .book-card { position: relative; }
.is-lib-picking .tpl-card__dl { pointer-events: none; opacity: .35; }

/* The cover's own hover lift and the "Read" badge both promise opening,
   which is not what a click does here. */
.is-lib-picking .book-card:hover .book-cover { transform: none; }
.is-lib-picking .book-cover__open,
.is-lib-picking .tpl-card__hover { display: none; }

.is-lib-picking .book-card,
.is-lib-picking .tpl-card {
  animation: lib-wiggle .42s ease-in-out infinite alternate;
  transform-origin: 50% 60%;
}
/* Offset every other card, or the whole grid shivers in lockstep and reads
   as one moving surface rather than a page of loose cards. */
.is-lib-picking .book-card:nth-child(even),
.is-lib-picking .tpl-card:nth-child(even) { animation-delay: -.21s; }

@keyframes lib-wiggle {
  from { transform: rotate(-.7deg) translateY(0); }
  to   { transform: rotate(.7deg) translateY(-2px); }
}

.book-card.is-picked,
.tpl-card.is-picked { animation-play-state: paused; }
.book-card.is-picked .book-cover { outline: 3px solid var(--tag-red-fg); outline-offset: 3px; }
.tpl-card.is-picked { border-color: var(--tag-red-fg); box-shadow: 0 0 0 2px var(--tag-red-bg); }
.is-picked .libpick__box {
  background: var(--tag-red-fg); border-color: var(--tag-red-fg); color: #fff;
}

/* Learn uses the same checkbox language as module/template deletion while
   keeping its mode scoped to course cards only. A course can appear in more
   than one catalogue section; JavaScript mirrors one id's state to every copy. */
.is-course-picking .coursepick { display: block; }
.is-course-picking .course-card { cursor: pointer; animation: lib-wiggle .42s ease-in-out infinite alternate; transform-origin: 50% 60%; }
.is-course-picking .course-card:nth-child(even) { animation-delay: -.21s; }
.is-course-picking .course-card:hover { box-shadow: var(--shadow-1); }
.is-course-picking .course-card.is-picked {
  animation-play-state: paused;
  border-color: var(--tag-red-fg);
  box-shadow: 0 0 0 2px var(--tag-red-bg);
}

/* Departments wall delete mode — same .libpick checkbox and is-picked
   language as How We Work above, scoped to .deptlogo tiles instead of
   book-card/tpl-card. The tile is a link (see .deptlogo above), so the
   click-to-pick interception happens in JS (initDepartmentAdmin), not here. */
.is-dept-picking .libpick { display: block; }
.is-dept-picking .deptlogo { cursor: pointer; animation: lib-wiggle .42s ease-in-out infinite alternate; transform-origin: 50% 60%; }
.is-dept-picking .deptwall li:nth-child(even) .deptlogo { animation-delay: -.21s; }
.is-dept-picking .deptlogo:hover .deptlogo__art,
.is-dept-picking .deptlogo:focus-visible .deptlogo__art { opacity: 1; transform: none; }
.is-dept-picking .deptlogo.is-picked { animation-play-state: paused; outline: 3px solid var(--tag-red-fg); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .is-lib-picking .book-card,
  .is-lib-picking .tpl-card { animation: none; }
  .is-course-picking .course-card { animation: none; outline: 2px dashed var(--ink-3); outline-offset: 2px; }
  .is-dept-picking .deptlogo { animation: none; outline: 2px dashed var(--ink-3); outline-offset: 2px; }
  /* Motion was carrying the "these can be removed" signal; without it the
     dashed edge has to. */
  .is-lib-picking .book-card .book-cover,
  .is-lib-picking .tpl-card { outline: 2px dashed var(--ink-3); outline-offset: 2px; }
}

/* --------------------------------------------------------------------------
   Learn: lesson selection modal
   --------------------------------------------------------------------------
   The lesson-selection modal (Create Course → Select Lessons for This
   Course) reuses How We Work's own .libpick checkbox and .is-picked outline
   treatment above — same chip, same red outline once picked — but this modal
   has only one mode, so the checkbox shows unconditionally rather than
   through is-lib-picking, and none of that state's lib-wiggle animation
   comes with it. Nothing here should vibrate.
   -------------------------------------------------------------------------- */

.lesson-picker__grid .libpick { display: block; }
.lesson-picker__grid .book-card { cursor: pointer; }
.lesson-picker__grid .book-cover__open { display: none; }
.template-picker__grid .libpick { display: block; }
.template-picker__grid .tpl-card { cursor: pointer; }
.template-picker__filters { margin-bottom: 12px; }
.template-picker__filter-row { display: flex; flex-wrap: wrap; gap: 10px; }

button.libpick { border: 0; background: none; padding: 0; cursor: pointer; }

.libdialog--lg .libdialog__panel { max-width: 960px; width: 94vw; }
.lesson-picker__body { max-height: 62vh; }
.lesson-picker__foot { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--ink-2); }
.lesson-picker__spacer { flex: 1; }

/* --------------------------------------------------------------------------
   Learn: Create Course form
   -------------------------------------------------------------------------- */

.libdialog--course .libdialog__panel {
  width: min(860px, 100%);
  max-height: min(92vh, 900px);
  max-height: min(92dvh, 900px);
}
.libdialog--course .libdialog__head { align-items: flex-start; padding: 18px 21px 15px; }
.libdialog--course .libdialog__close { width: 44px; height: 44px; }
.learn-create__heading { min-width: 0; }
.learn-create__eyebrow {
  margin: 0 0 4px;
  color: var(--navy-600); font-size: 10.5px; font-weight: 800;
  letter-spacing: .09em; text-transform: uppercase;
}
.learn-create__heading .libdialog__title { font-size: clamp(18px, 2.4vw, 21px); line-height: 1.2; }
.learn-create__intro { max-width: 620px; margin: 6px 0 0; color: var(--ink-2); font-size: 13.5px; line-height: 1.55; }

.learn-create .learn-create__body { gap: 15px; padding: 16px 21px 19px; background: var(--navy-050); }
.learn-create__section {
  padding: 16px;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--shadow-1);
}
.learn-create__section-head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 15px; }
.learn-create__section-head > div { min-width: 0; flex: 1; }
.learn-create__section-head h3 { margin: 0; color: var(--navy-900); font-size: 14.5px; line-height: 1.3; }
.learn-create__section-head p { margin: 3px 0 0; color: var(--ink-3); font-size: 12.5px; line-height: 1.5; }
.learn-create__step {
  display: grid; place-items: center; flex: none;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--navy-100); color: var(--navy-700);
  font-size: 12px; font-weight: 800;
}
.learn-create__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 15px 15px; }
.learn-create__wide { grid-column: 1 / -1; }
.learn-create .libfield__label {
  color: var(--ink-2); font-size: 12.5px; font-weight: 700;
  letter-spacing: 0; text-transform: none;
}
.learn-create .libfield__label.is-required::after { content: ' *'; color: var(--tag-red-fg); }
.learn-create .libfield__hint { font-size: 12px; }

.learn-create__settings {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(220px, .72fr);
  gap: 15px 15px;
}
.learn-duration {
  display: flex; min-height: 33px; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface);
}
.learn-create .learn-duration input[type="number"] {
  flex: 1; min-width: 0; border: 0; border-radius: 0; box-shadow: none;
}
.learn-create .learn-duration input[type="number"]:focus-visible { outline: 0; }
.learn-duration:focus-within { outline: 2px solid var(--navy-600); outline-offset: 1px; }
.learn-duration__unit {
  display: flex; align-items: center; padding: 0 12px;
  border-left: 1px solid var(--line); background: var(--navy-050);
  color: var(--ink-2); font-size: 12.5px; font-weight: 650;
}
.learn-create .learn-create__date { display: flex; align-items: center; min-height: 33px; }
.learn-create__requirement {
  grid-column: 1 / -1;
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--navy-050); cursor: pointer;
}
.learn-create__requirement:hover { border-color: #edb9bc; }
.learn-create__requirement input { width: 18px; height: 18px; margin: 2px 0 0; flex: none; accent-color: var(--navy-600); }
.learn-create__requirement > span { display: grid; gap: 3px; }
.learn-create__requirement strong { color: var(--navy-900); font-size: 13.5px; }
.learn-create__requirement small { color: var(--ink-3); font-size: 12px; line-height: 1.5; }

.learn-create__section-head--action { align-items: center; }
.learn-create__section-head--action .btn { margin-left: auto; flex: none; }
.learn-create__selection {
  min-height: 41px; padding: 10px 12px;
  border: 1px dashed var(--line); border-radius: var(--r-sm);
  background: var(--navy-050);
}
.learn-create__selection .learn-create__lessons { margin-top: 0; }
.learn-create__selection .learn-create__lessons:empty { display: none; }
.learn-create__selection .learn-create__lessons:not(:empty) + .libfield__hint { display: block; margin-top: 8px; }
.learn-create__error { margin-top: 0; }
.learn-create .learn-create__foot { align-items: center; padding: 14px 21px 15px; }
.learn-create__foot > p { flex: 1; margin: 0 auto 0 0; color: var(--ink-3); font-size: 12px; line-height: 1.45; }

.libfield--check {
  display: grid; grid-template-columns: auto 1fr; column-gap: 7px; align-items: center;
}
.libfield--check input[type="checkbox"] { width: 16px; height: 16px; margin: 0; }
.libfield--check span:nth-child(2) { font-size: 13.5px; font-weight: 600; color: var(--ink-1); }
.libfield--check .libfield__hint { grid-column: 2; }

.learn-create__lessons {
  list-style: none; margin: 9px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 7px;
}
.learn-create__lesson {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 6px 5px 9px; border-radius: 999px;
  background: var(--navy-050); border: 1px solid var(--line);
  font-size: 12.5px; color: var(--ink-2);
}
.learn-create__lesson-remove {
  border: 0; background: none; cursor: pointer; padding: 0;
  width: 18px; height: 18px; border-radius: 50%;
  display: grid; place-items: center; color: var(--ink-3); font-size: 14px; line-height: 1;
}
.learn-create__lesson-remove:hover { background: var(--tag-red-bg); color: var(--tag-red-fg); }

/* ---- Learn assessment choice/upload ------------------------------------ */
.assessment-dialog { width: min(820px, 94vw); }
.assessment-dialog .libdialog__head { align-items: flex-start; padding: 18px 21px 15px; }
.assessment-dialog__body { padding: 21px; background: var(--navy-050); }
.assessment-choice-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.assessment-choice {
  display: grid; gap: 8px; align-content: start; min-height: 185px; padding: 18px;
  border: 1px solid var(--line); border-radius: var(--r); background: var(--surface);
  color: var(--ink); font: inherit; text-align: left; cursor: pointer;
  box-shadow: var(--shadow-1);
  transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}
.assessment-choice:hover { border-color: var(--navy-600); box-shadow: var(--shadow-2); transform: translateY(-2px); }
.assessment-choice:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }
.assessment-choice__icon {
  display: grid; place-items: center; width: 42px; height: 42px; margin-bottom: 4px;
  border-radius: 12px; background: var(--navy-050); color: var(--navy-700);
}
.assessment-choice__icon .icon { width: 22px; height: 22px; }
.assessment-choice strong { color: var(--navy-900); font-size: 14px; }
.assessment-choice > span:last-child { color: var(--ink-3); font-size: 12.5px; line-height: 1.55; }
.assessment-upload { display: grid; gap: 14px; }
/* The component has an explicit display value, so the browser's default
   [hidden] rule cannot win in the cascade. Keep the upload step progressive:
   it appears only after the administrator chooses the upload option. */
.assessment-upload[hidden] { display: none; }
.assessment-upload__head { display: flex; align-items: flex-start; gap: 14px; justify-content: space-between; }
.assessment-upload__head h3 { margin: 0; color: var(--navy-900); font-size: 16px; }
.assessment-upload__head p { max-width: 560px; margin: 5px 0 0; color: var(--ink-3); font-size: 12.5px; line-height: 1.55; }
.assessment-upload__head .btn { flex: 0 0 auto; white-space: nowrap; }
.assessment-dropzone {
  position: relative; display: grid; place-items: center; gap: 7px; min-height: 190px; padding: 20px;
  border: 1.5px dashed var(--navy-600); border-radius: var(--r); background: var(--surface);
  color: var(--ink-2); text-align: center; cursor: pointer;
  transition: background .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.assessment-dropzone:hover,
.assessment-dropzone.is-dragging,
.assessment-dropzone:focus-within { border-color: var(--navy-700); background: var(--navy-050); box-shadow: inset 0 0 0 2px rgba(35, 56, 83, .08); }
.assessment-dropzone input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.assessment-dropzone__icon { display: grid; place-items: center; width: 42px; height: 42px; border-radius: 50%; background: var(--navy-100); color: var(--navy-700); }
.assessment-dropzone__icon .icon { width: 22px; height: 22px; }
.assessment-dropzone strong { color: var(--navy-900); font-size: 13.5px; }
.assessment-dropzone small { color: var(--ink-3); font-size: 11.5px; }
.assessment-dialog__foot { align-items: center; }
.assessment-dialog__spacer { flex: 1; }

@media (max-width: 640px) {
  .assessment-dialog .libdialog__head,
  .assessment-dialog__body { padding-inline: 15px; }
  .assessment-choice-grid { grid-template-columns: minmax(0, 1fr); }
  .assessment-choice { min-height: 0; }
  .assessment-upload__head { flex-direction: column; }
  .assessment-upload__head .btn { width: 100%; white-space: normal; }
  .assessment-dialog__foot { flex-wrap: wrap; }
  .assessment-dialog__spacer { display: none; }
}

@media (max-width: 720px) {
  .libdialog--course { padding: 10px; }
  .libdialog--course .libdialog__panel { max-height: 96vh; max-height: 96dvh; }
  .libdialog--course .libdialog__head { padding: 18px 18px 15px; }
  .learn-create .learn-create__body { padding: 14px; gap: 14px; }
  .learn-create__section { padding: 16px; }
  .learn-create__grid,
  .learn-create__settings { grid-template-columns: minmax(0, 1fr); }
  .learn-create__wide,
  .learn-create__requirement { grid-column: auto; }
  .learn-create__section-head--action { flex-wrap: wrap; }
  .learn-create__section-head--action .btn { width: calc(100% - 42px); margin-left: 42px; }
  .learn-create .learn-create__foot { flex-wrap: wrap; padding: 13px 18px 16px; }
  .learn-create__foot > p { width: 100%; flex-basis: 100%; margin-bottom: 3px; }
  .learn-create select,
  .learn-create input[type="text"],
  .learn-create input[type="number"],
  .learn-create textarea { font-size: 16px; }
}

/* --------------------------------------------------------------------------
   Learn: course-creation progress loader
   -------------------------------------------------------------------------- */

.learn-progress-dialog__text { margin: 0 0 10px; font-size: 13.5px; color: var(--ink-2); }
.learn-progress-bar {
  width: 100%; height: 10px; border-radius: 999px;
  background: var(--navy-050); overflow: hidden;
}
.learn-progress-bar i {
  display: block; height: 100%; border-radius: 999px;
  background: var(--navy-700); transition: width .3s ease;
}

/* --------------------------------------------------------------------------
   Learn: real course covers
   --------------------------------------------------------------------------
   Once a course's cover has been generated (the first page of its first
   lesson's PDF) it replaces the abstract SVG scatter with a real image; the
   overlay text gets a bottom scrim so it stays legible over a photograph
   instead of only the flat gradient the SVG version sits on. */

.cover__photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.cover:has(.cover__photo) .cover__bottom {
  position: relative;
  margin: -7px -9px -6px; padding: 7px 9px 6px;
  border-radius: 0 0 10px 10px;
  background: linear-gradient(180deg, rgba(10, 16, 28, .55), rgba(10, 16, 28, .92) 70%);
}
.cover:has(.cover__photo) .cover__eyebrow,
.cover:has(.cover__photo) .cover__title,
.cover:has(.cover__photo) .cover__meta { color: #fff; text-shadow: 0 1px 2px rgba(10, 16, 28, .55); }
.cover:has(.cover__photo) .cover__brand { background: var(--navy-600); }

.cover--blue  { --cover-accent: var(--tag-blue-fg);  --cover-tint: var(--tag-blue-bg); }
.cover--teal  { --cover-accent: var(--tag-teal-fg);  --cover-tint: var(--tag-teal-bg); }
.cover--amber { --cover-accent: var(--tag-amber-fg); --cover-tint: var(--tag-amber-bg); }
.cover--slate { --cover-accent: var(--navy-600);     --cover-tint: var(--navy-050); }

/* --------------------------------------------------------------------------
   The upload and settings dialogs
   --------------------------------------------------------------------------
   Fixed and above the section modal (z-index 100), because either page can
   arrive as a fragment inside it — a dialog that respected its place in the
   document would open inside a scrolling panel.
   -------------------------------------------------------------------------- */

.libdialog {
  position: fixed; inset: 0; z-index: 400;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
}
.libdialog[hidden] { display: none; }

.libdialog__scrim { position: absolute; inset: 0; background: rgba(43, 22, 24, .46); }

.libdialog__panel {
  position: relative;
  display: flex; flex-direction: column;
  width: min(520px, 100%);
  max-height: min(88vh, 760px);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: 0 24px 64px rgba(74, 5, 9, .28);
  overflow: hidden;
}

.libdialog__head {
  display: flex; align-items: center; gap: 10px;
  padding: 15px 16px 12px;
  border-bottom: 1px solid var(--line-2);
}
.libdialog__title { margin: 0; font-size: 15.5px; color: var(--navy-900); }
.libdialog__close {
  margin-left: auto; flex: none;
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink-2); cursor: pointer;
}
.libdialog__close:hover { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }
.libdialog__close .icon { width: 17px; height: 17px; }

.libdialog__body { padding: 15px 16px; overflow-y: auto; display: grid; gap: 14px; }
.libdialog__lede { margin: 0; font-size: 13px; line-height: 1.6; color: var(--ink-2); }

.libdialog__foot {
  display: flex; justify-content: flex-end; gap: 9px;
  padding: 12px 16px 15px;
  border-top: 1px solid var(--line-2);
}

.libdialog__error {
  margin: 0; padding: 9px 10px;
  border: 1px solid var(--tag-red-fg); border-radius: var(--r-sm);
  background: var(--tag-red-bg);
  color: var(--tag-red-fg); font-size: 13px; line-height: 1.5;
}
.libdialog__error[hidden] { display: none; }

/* ---- the Users dialog: two tabs over one panel ----------------------------
   The panel is already a flex column with a fixed max-height, so each tab
   panel becomes the same thing one level down: a body that scrolls between a
   tab strip that does not and a footer that does not. min-height:0 is what
   lets the body actually shrink instead of pushing the footer off the panel.
   -------------------------------------------------------------------------- */
.usertabs {
  display: flex; flex-wrap: wrap; gap: 2px;
  padding: 0 16px;
  border-bottom: 1px solid var(--line-2);
}
.usertabs__tab {
  padding: 9px 12px 8px;
  border: 0; border-bottom: 2px solid transparent;
  background: none;
  color: var(--ink-3); font: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.usertabs__tab:hover { color: var(--navy-700); }
.usertabs__tab:focus-visible { outline: 2px solid var(--navy-600); outline-offset: -2px; }
.usertabs__tab.is-active { color: var(--navy-800); border-bottom-color: var(--navy-600); }

.userpanel { display: flex; flex-direction: column; min-height: 0; flex: 1; }
.userpanel[hidden] { display: none; }

/* ---- AI model usage tab ---------------------------------------------------
   Reuses the Learn page's list and badge vocabulary inside the dialog body's
   own grid rhythm. The totals chips sit left here rather than right, because
   nothing sits beside them — the tab has no heading of its own. */
.modelusage-totals { justify-content: flex-start; }
.modelusage-recent { display: grid; gap: 10px; }

/* ---- one account in the Existing users tab ---- */
.userlist { display: grid; gap: 10px; }
.userlist__note { margin: 0; font-size: 13px; color: var(--ink-3); }
.userlist__note[hidden] { display: none; }

.userrow {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface);
}
.userrow.is-dirty { border-color: var(--navy-600); }

.userrow__fields {
  flex: 1; min-width: 0;
  display: grid; gap: 10px;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, .8fr);
}

.userrow__side {
  flex: none; width: 128px;
  display: grid; gap: 6px; justify-items: stretch;
  /* Lines the button up with the inputs rather than with their labels. */
  padding-top: 21px;
}
.userrow__side .btn { white-space: nowrap; }
.userrow__msg { margin: 0; font-size: 11.5px; line-height: 1.4; color: var(--ink-3); }
.userrow__msg[hidden] { display: none; }
.userrow__msg.is-error { color: var(--tag-red-fg); }
.userrow__msg.is-saved { color: var(--navy-700); }

/* A removed account keeps its row — removing is clearing is_active, not
   deleting, so the row is still the control that gives access back. Greyed
   rather than hidden, so "who used to have access" is still answerable. */
.userrow.is-inactive { background: var(--navy-050); border-style: dashed; }
.userrow.is-inactive .userrow__fields { opacity: .55; }
.userrow__badge {
  display: inline-block; margin-left: 6px;
  padding: 1px 6px; border-radius: 999px;
  background: var(--tag-red-bg); color: var(--tag-red-fg);
  font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  vertical-align: 1px;
}
.userrow__badge[hidden] { display: none; }
/* The second press of a two-step remove, so the confirming state cannot be
   mistaken for the resting one. */
.userrow [data-row-remove].is-confirming {
  background: var(--tag-red-fg); border-color: var(--tag-red-fg); color: #fff;
}
/* Same two-step confirm on Reset progress, in the navy ramp rather than red —
   destructive to progress, not to access, so it should not read as the same
   severity as Remove. */
.userrow [data-row-reset].is-confirming {
  background: var(--navy-700); border-color: var(--navy-700); color: #fff;
}

@media (max-width: 720px) {
  /* align-items governs the cross axis, which the direction change has just
     turned from vertical to horizontal — left at flex-start the stacked
     fields would shrink to their content instead of filling the row. */
  .userrow { flex-direction: column; align-items: stretch; }
  .userrow__fields { grid-template-columns: minmax(0, 1fr); }
  .userrow__side { width: 100%; padding-top: 0; }
}

/* ---- one field in an upload form ---- */

.libfield { display: grid; gap: 6px; }
.libfield__label {
  font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}
.libfield__hint { font-size: 12px; line-height: 1.5; color: var(--ink-3); }

/* Every input type the dialogs actually use has to be named here: the list
   is type-scoped, so anything missing from it renders at the user-agent
   default instead — which is what happened to the Community event's date
   field (21px tall, browser font, no border, beside 41px styled siblings).
   The date/time/email/url/search types are listed so the next form that
   reaches for one inherits the dialog's field styling for free. */
.libfield select,
.libfield input[type="text"],
.libfield input[type="file"],
.libfield input[type="number"],
.libfield input[type="date"],
.libfield input[type="time"],
.libfield input[type="datetime-local"],
.libfield input[type="email"],
.libfield input[type="url"],
.libfield input[type="search"],
.libfield textarea {
  width: 100%;
  min-height: 33px; padding: 9px 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface);
  font: inherit; font-size: 14px; line-height: 1.45; color: var(--ink);
}
.libfield textarea { min-height: 76px; resize: vertical; }
.libfield input::placeholder,
.libfield textarea::placeholder { color: var(--ink-3); opacity: .78; }
.libfield select,
.libfield input[type="date"],
.libfield input[type="time"],
.libfield input[type="datetime-local"] { cursor: pointer; }
.libfield input[type="file"] { padding: 7px; cursor: pointer; }
.libfield select:focus-visible,
.libfield input:focus-visible,
.libfield textarea:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 1px; }

/* A value the form fills in itself: the format read off the file, and the
   two dates. Styled as a field so the form reads as one thing, but plainly
   not typeable, because none of it is. */
.libfield__auto {
  display: block;
  padding: 8px 10px;
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
  background: var(--navy-050);
  font-size: 14px; color: var(--ink-2);
}
.libfield--pair { grid-template-columns: 1fr 1fr; gap: 10px; }
.libfield--pair > div { display: grid; gap: 6px; }

/* ---- the Add Event image uploader ----
   No existing multi-file/reorder widget in this app to port (the Library
   and Department dialogs both take a single file) — small and
   self-contained, built from the same tokens as everything else here. */
.community-uploader__grid {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}
.community-uploader__grid[hidden] { display: none; }
.community-uploader__grid:empty { display: none; }
.community-uploader__item {
  position: relative;
  width: 74px; height: 74px;
  flex: none;
  border-radius: var(--r-sm);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--navy-050);
}
.community-uploader__item--primary { outline: 2px solid var(--navy-600); outline-offset: 1px; }
.community-uploader__item img { display: block; width: 100%; height: 100%; object-fit: cover; }
.community-uploader__badge {
  position: absolute;
  left: 0; bottom: 0; right: 0;
  padding: 2px 0;
  background: rgba(20, 30, 45, .72);
  color: #fff;
  font-size: 9.5px; font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase;
  text-align: center;
}
.community-uploader__remove {
  position: absolute; top: 3px; right: 3px;
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: rgba(20, 30, 45, .72);
  color: #fff;
  cursor: pointer; padding: 0;
}
.community-uploader__remove:hover { background: var(--tag-red-fg); }
.community-uploader__remove .icon { width: 12px; height: 12px; }

/* ---- the vocabularies ---- */

.libset { border-top: 1px solid var(--line-2); padding-top: 12px; }
.libset:first-of-type { border-top: 0; padding-top: 0; }
.libset__title { margin: 0 0 9px; font-size: 13px; color: var(--navy-900); }

.libset__list { list-style: none; margin: 0 0 9px; padding: 0; display: grid; gap: 6px; }
.libset__item {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 7px 7px 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); font-size: 13.5px;
}
.libset__item > span { min-width: 0; overflow-wrap: anywhere; }
.libset__remove {
  margin-left: auto; flex: none;
  display: grid; place-items: center;
  width: 24px; height: 24px;
  border: 0; border-radius: 6px;
  background: transparent; color: var(--ink-3); cursor: pointer;
}
.libset__remove:hover { background: var(--tag-red-bg); color: var(--tag-red-fg); }
.libset__remove .icon { width: 15px; height: 15px; }

.libset__empty { margin: 0 0 9px; font-size: 12.5px; color: var(--ink-3); }
.libset__empty[hidden] { display: none; }

.libset__add { display: flex; gap: 7px; }
.libset__add input {
  flex: 1; min-width: 0;
  padding: 7px 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); font: inherit; font-size: 13.5px;
}
.libset__add input:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 1px; }

/* --------------------------------------------------------------------------
   "This file is not supported"
   --------------------------------------------------------------------------
   The honest answer for an archive or a mail shell: there is no single
   printed form of it to draw, so the reader is offered the file instead of
   an empty book.
   -------------------------------------------------------------------------- */

.libnotice {
  position: fixed; inset: 0; z-index: 400;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
}
.libnotice[hidden] { display: none; }

.libnotice__panel {
  position: relative;
  width: min(440px, 100%);
  padding: 24px 21px 19px;
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: 0 24px 64px rgba(74, 5, 9, .28);
  text-align: center;
}
.libnotice__panel > .icon { width: 34px; height: 34px; color: var(--tag-amber-fg); }
.libnotice__title { margin: 10px 0 7px; font-size: 16px; color: var(--navy-900); }
.libnotice__panel p { margin: 0; font-size: 14px; line-height: 1.6; color: var(--ink-2); }
.libnotice__actions {
  display: flex; justify-content: center; gap: 9px; flex-wrap: wrap;
  margin-top: 16px;
}

/* --------------------------------------------------------------------------
   Template cards, now that they are files
   --------------------------------------------------------------------------
   The card does two things — open the template, and download it — so it is
   an <article> with a link over its body and a second one in the corner.
   Nesting the download inside the reading link would not be markup a browser
   can act on.
   -------------------------------------------------------------------------- */

.tpl-card { position: relative; }
.tpl-card:focus-within { border-color: #eaacb0; box-shadow: var(--shadow-2); }
.tpl-card__open { display: block; color: inherit; text-decoration: none; }
.tpl-card__open:hover { text-decoration: none; }

.tpl-card__dl {
  position: absolute; top: 10px; right: 10px; z-index: 3;
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border-radius: 8px;
  background: rgba(255, 255, 255, .92);
  box-shadow: var(--shadow-1);
  color: var(--navy-700);
  opacity: 0;
  transition: opacity .15s, background .15s;
}
.tpl-card:hover .tpl-card__dl,
.tpl-card:focus-within .tpl-card__dl { opacity: 1; }
.tpl-card__dl:hover { background: var(--navy-700); color: #fff; }
.tpl-card__dl:focus-visible { opacity: 1; outline: 2px solid var(--navy-600); outline-offset: 2px; }
.tpl-card__dl .icon { width: 16px; height: 16px; }

/* Waiting on LibreOffice. Keep the card legible and replace the ambiguous
   greyed-out state with an explicit progress message. The document viewer
   carries the same message once it opens over the page. */
.tpl-card.is-preparing .tpl-card__open { cursor: progress; }
.tpl-card.is-preparing .tpl-card__hover { opacity: 0; }

.tpl-format-section__empty {
  margin: 0;
  padding: 21px 16px;
  border: 1px dashed var(--line);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink-3);
  font-size: 13.5px;
  text-align: center;
}

/* A department with nothing filed under it keeps all three layers — the
   stack is the shape that says "templates live here" — but they are drawn
   as empty paper rather than as documents that do not exist. Hairlined, or
   three sheets of the page background read as one smudge. */
.tpl-dept-card__layer--blank {
  background:
    repeating-linear-gradient(-45deg, var(--navy-050) 0 9px, var(--surface) 9px 18px);
  box-shadow: inset 0 0 0 1px var(--line), var(--shadow-1);
}
.tpl-dept-card--empty .tpl-dept-card__layer--3 { box-shadow: var(--shadow-1); }
.tpl-dept-card--empty .tpl-dept-card__count { color: var(--ink-3); }

/* Nothing behind a dialog should scroll under it. Either page can also arrive
   as a fragment inside the section modal, where it's the modal body that
   scrolls, not the document body, so that one is held too. */
body.is-lib-dialog-open { overflow: hidden; }
body.is-lib-dialog-open .modal__body { overflow: hidden; }

@media (max-width: 560px) {
  .libfield--pair { grid-template-columns: 1fr; }
  .libdialog__panel { max-height: 92vh; }
}

/* .btn sets display, which beats the UA sheet's [hidden] rule on specificity —
   so a button that is meant to be absent (Cancel, until delete mode is on)
   would otherwise still be laid out. */
.btn[hidden] { display: none; }
.libfield[hidden] { display: none; }

/* ==========================================================================
   Home, on a phone
   --------------------------------------------------------------------------
   The map does not survive a 390px screen, so a phone gets the same six
   destinations as a dashboard: a docked top bar carrying the map HUD's
   controls, then one card per destination, two to a row. Everything a card
   opens is the ordinary section modal, unchanged.

   Server-chosen, not breakpointed — is_phone_request() in
   app/Support/helpers.php decides, and a phone is never sent the map at all.
   That is why there is no @media around this block: the markup it styles
   only exists on the requests it is meant for, and wrapping it in a width
   query would also claim narrow desktop windows, which keep the map.

   These rules do use the --ui-* compact scale, unlike the map above them: a
   dashboard of cards is a document you read, which is exactly what that
   ramp is tuned for.
   ========================================================================== */

body.is-mobile-home {
  background: var(--surface-canvas);
  /* The address bar comes and goes while scrolling; svh is the small
     viewport, so the page is never shorter than the screen at its shortest. */
  min-height: 100svh;
}

/* --- the top bar ---------------------------------------------------------
   Sticky rather than fixed: it scrolls with the document's own scrollbar and
   needs no compensating padding on the content below it. */
.mobilebar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--ui-space-sm);
  padding: 10px 14px;
  padding-top: max(10px, env(safe-area-inset-top));
  background: rgba(255, 255, 255, .92);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--line);
}

.mobilebar__brand {
  display: block;
  min-width: 0;
  flex: 0 1 auto;
  padding: 0;
  text-decoration: none;
}
.mobilebar__brand:hover { text-decoration: none; }
.mobilebar__brand:focus-visible { outline: 2px solid var(--navy-700); outline-offset: 3px; }
.mobilebar__brand-logo {
  display: block;
  width: 86px;
  max-width: 100%;
  height: auto;
}

.mobilebar__tools {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
  border-radius: 999px;
}

/* The bar's controls are the HUD's, at touch size. .iconbtn is a shared
   utility, so restate the shape here rather than inheriting the map's. */
.mobilebar .iconbtn {
  width: 38px;
  height: 38px;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
}
.mobilebar .iconbtn:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 2px; }
.mobilebar .iconbtn .icon { width: 18px; height: 18px; }

/* Edit Mode's label ("Edit Mode: ON") is wider than the whole tools row has
   to spare, so on a phone the toggle is the pencil alone and its state is
   carried by fill instead of by words. aria-label on the button and the
   live aria-pressed value both survive, so nothing is lost to a screen
   reader. */
.mobilebar .iconbtn--edit { width: 38px; padding: 0; }
.mobilebar .iconbtn--edit .small { display: none; }
.mobilebar .iconbtn--edit[aria-pressed="true"] {
  background: var(--navy-600);
  border-color: var(--navy-600);
  color: #fff;
}

/* --- the dashboard ------------------------------------------------------- */

.mobilehome {
  display: block;
  padding: var(--ui-space-xl) 14px calc(var(--ui-space-2xl) + env(safe-area-inset-bottom));
}

.mobilehome__intro { margin: 0 0 var(--ui-space-lg); }
.mobilehome__eyebrow {
  margin: 0 0 5px;
  font-size: var(--ui-text-2xs);
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--navy-600);
}
.mobilehome__title {
  margin: 0 0 6px;
  font-size: var(--ui-text-3xl);
  line-height: 1.2;
  color: var(--navy-900);
}
.mobilehome__lede {
  margin: 0;
  font-size: var(--ui-text-md);
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 34ch;
}

.mobilehome__notice {
  display: flex;
  align-items: flex-start;
  gap: var(--ui-space-sm);
  margin: 0 0 var(--ui-space-lg);
  padding: 10px 12px;
  border: 1px solid var(--tag-amber-bg);
  border-radius: var(--r);
  background: var(--tag-amber-bg);
  color: var(--tag-amber-fg);
  font-size: var(--ui-text-sm);
  line-height: 1.5;
}
.mobilehome__notice .icon { width: 16px; height: 16px; flex: none; margin-top: 1px; }

.mobilehome__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

/* --- one destination ----------------------------------------------------- */

.mobilecard {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-height: 148px;
  padding: 13px 12px 14px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-1);
  color: inherit;
  text-decoration: none;
  transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
.mobilecard:hover { text-decoration: none; }
.mobilecard:active { transform: scale(.985); }
.mobilecard:focus-visible { outline: 2px solid var(--navy-600); outline-offset: 3px; }
/* Open in the modal — the same is-active the map puts on a building. */
.mobilecard.is-active {
  border-color: var(--navy-600);
  box-shadow: var(--shadow-2);
}

.mobilecard__icon {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  margin-bottom: 3px;
  border-radius: 10px;
  background: var(--navy-100);
  color: var(--navy-700);
}
.mobilecard__icon .icon { width: 19px; height: 19px; }

.mobilecard__name {
  font-size: var(--ui-text-lg);
  font-weight: 650;
  line-height: 1.25;
  color: var(--navy-900);
}
.mobilecard__blurb {
  font-size: var(--ui-text-sm);
  line-height: 1.45;
  color: var(--ink-3);
  /* Four lines is the tallest a blurb can be before two cards in a row stop
     lining up; the longest of them (How We Work) runs well past that. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  overflow: hidden;
}

.mobilecard__go {
  position: absolute;
  top: 13px; right: 12px;
  display: grid;
  place-items: center;
  color: var(--navy-600);
}
.mobilecard__go .icon { width: 16px; height: 16px; }
.mobilecard__go-locked { display: none; }

/* Locked until the Welcome journey is finished — same rule the map applies
   to its buildings, and the same shape of unlock: dropping --locked is all
   assets/js/app.js has to do to hand the card back. */
.mobilecard--locked {
  pointer-events: none;
  border-style: dashed;
  background: var(--bg);
  box-shadow: none;
}
.mobilecard--locked .mobilecard__icon { background: var(--line-2); color: var(--ink-3); }
.mobilecard--locked .mobilecard__name { color: var(--ink-2); }
.mobilecard--locked .mobilecard__go { color: var(--ink-3); }
.mobilecard--locked .mobilecard__go-open { display: none; }
.mobilecard--locked .mobilecard__go-locked { display: grid; }

@media (prefers-reduced-motion: reduce) {
  .mobilecard { transition: none; }
  .mobilecard:active { transform: none; }
}

/* ==========================================================================
   Phone adjustments outside home
   --------------------------------------------------------------------------
   body.is-phone is on every route a phone loads (layouts/header.php), not
   just the dashboard. What follows is the handful of places built for a
   pointer and a wide window that a 390px screen cannot hold: the admin
   dialogs and the compact list row. Everything else in the section modal was
   already responsive and is left alone.

   Keyed to the class rather than to a width, deliberately — a narrow desktop
   window is not a phone here, and the map is still what it gets.
   ========================================================================== */

/* --- admin dialogs (Users, Library, Departments, Community, Learn) -------- */

/* .libdialog__panel is a fixed-width card centred in the viewport. On a phone
   the card is the screen, so give it the width and the height, and pull the
   surrounding gutter in to match. dvh, because the panel is measured against
   a viewport the address bar keeps resizing. */
body.is-phone .libdialog { padding: 10px; }
body.is-phone .libdialog__panel,
body.is-phone .libdialog--lg .libdialog__panel {
  width: 100%;
  max-width: none;
  max-height: min(92dvh, 900px);
}

/* The Users dialog's five tabs.
 *
 * They used to wrap, which is the right answer on a wide screen and the wrong
 * one here: three rows of tabs eat a third of the panel before any content is
 * drawn, and the row that lands under the panel's own overflow:hidden edge
 * takes "AI model usage" and "Logs" off the screen entirely. One scrolling
 * strip instead — the phone convention, and it can hold any number of tabs at
 * any width without the panel growing. The active tab is scrolled into view
 * by the browser when it is focused, and the strip starts on the first. */
body.is-phone .usertabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;                     /* the strip is dragged, not scrolled */
  -webkit-overflow-scrolling: touch;
}
body.is-phone .usertabs::-webkit-scrollbar { display: none; }
body.is-phone .usertabs__tab {
  flex: none;
  white-space: nowrap;
  padding: 11px 12px 10px;                   /* a touch target, not a pointer target */
}

/* --- the compact list row ------------------------------------------------
   .list__side never shrinks (badges and counts must stay legible), and .list
   clips, so on a narrow screen the side of a row is simply cut off — which is
   how the AI model usage tab loses its status badges. Let a row become two
   lines instead: the title takes the width, the side wraps under it. */
body.is-phone .list__row { flex-wrap: wrap; row-gap: 6px; }
body.is-phone .list__main { flex: 1 1 100%; }
body.is-phone .list__side { flex-wrap: wrap; row-gap: 4px; }

/* --- last resort inside the section modal --------------------------------
   Every section measured clean at 390px, so nothing needs this today. It is
   here as a floor, not a layout: if some future page (or an uploaded table,
   or a long unbroken string in content somebody types) turns out wider than
   a phone, the modal body should scroll sideways to reach it rather than
   clip it out of existence, which is what overflow-y:auto alone does. The
   modal is the only view of a section on a phone, so there is no wider
   presentation left to fall back to. */
body.is-phone #module-modal .modal__body { overflow-x: auto; }
