/* =========================================================================
   Barazas brand layer, loaded AFTER assets/metronic/css/styles.css.
   Re-points Metronic's semantic tokens (--primary, --border, --radius, etc.)
   at the Barazas design system, and layers the brand's own tokens on top
   for anything Metronic doesn't have an equivalent for (status tints,
   the "tail corner" bubble-radius system, motion easing).
   Source: Barazas Brand Guidelines v1.0 (Oct 2026).
   ========================================================================= */

/* ---- Fonts (self-hosted, see /public/assets/brand/fonts) ---- */
@font-face {
  font-family: 'Rubik';
  src: url('/assets/brand/fonts/Rubik-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Rubik';
  src: url('/assets/brand/fonts/Rubik-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Lexend';
  src: url('/assets/brand/fonts/Lexend-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Lexend';
  src: url('/assets/brand/fonts/Lexend-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Lexend';
  src: url('/assets/brand/fonts/Lexend-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  src: url('/assets/brand/fonts/IBMPlexSansArabic-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  src: url('/assets/brand/fonts/IBMPlexSansArabic-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  src: url('/assets/brand/fonts/IBMPlexSansArabic-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* ---- Base brand colors ---- */
  --color-coral: #F26B4A;
  --color-coral-deep: #C2462A;
  --color-coral-press: #A33A22;
  --color-coral-text: #B8432A;
  --color-coral-soft: #F8A58F;
  --color-coral-tint: #FDEBE5;
  --color-coral-tint-2: #FBD9CE;

  --color-usiku: #1E2340;
  --color-usiku-raised: #2B3157;
  --color-usiku-line: #3D4470;

  --color-bahari: #1F8A84;
  --color-bahari-deep: #156A65;
  --color-bahari-soft: #7CC4BF;
  --color-bahari-tint: #E2F2F0;

  --color-white: #FFFFFF;
  --color-sand-50: #FBF7F2;
  --color-sand-100: #F3ECE3;
  --color-sand-200: #ECE4DA;
  --color-sand-300: #CFC5B8;

  --color-ink: #1E2340;
  --color-ink-2: #454A66;
  --color-ink-3: #5C6078;
  --color-ink-4: #6F7389;

  --color-success: #2F7D4F;
  --color-success-tint: #E3F2E8;
  --color-warning: #B26A00;
  --color-warning-fill: #F5B23D;
  --color-warning-tint: #FFF1D6;
  --color-danger: #B42335;
  --color-danger-tint: #FCE7EA;

  /* ---- Semantic text ---- */
  --text-body: var(--color-ink);
  --text-secondary: var(--color-ink-2);
  --text-muted: var(--color-ink-3);
  --text-subtle: var(--color-ink-4);
  --text-on-dark: #FFFFFF;
  --text-on-dark-muted: rgba(255, 255, 255, .66);
  --text-on-coral: var(--color-usiku);
  --text-link: var(--color-coral-text);
  --text-link-hover: var(--color-coral-press);

  /* ---- Semantic surfaces ---- */
  --surface-page: #FFFFFF;
  --surface-card: #FFFFFF;
  --surface-soft: var(--color-sand-50);
  --surface-sand: var(--color-sand-100);
  --surface-coral-tint: var(--color-coral-tint);
  --surface-bahari-tint: var(--color-bahari-tint);
  --surface-dark: var(--color-usiku);
  --surface-dark-raised: var(--color-usiku-raised);

  /* ---- Semantic borders ---- */
  --border-hairline: var(--color-sand-200);
  --border-input: var(--color-sand-300);
  --border-focus: var(--color-coral);
  --border-on-dark: var(--color-usiku-line);
  --focus-ring: 0 0 0 3px rgba(242, 107, 74, .32);

  /* ---- CTA (button) tokens ---- */
  --cta-bg: var(--color-coral);
  --cta-bg-hover: var(--color-coral-deep);
  --cta-bg-press: var(--color-coral-press);
  --cta-fg: var(--color-usiku);
  --cta-fg-hover: #FFFFFF;
  --cta-secondary-fg: var(--color-ink);
  --cta-secondary-border: var(--color-sand-300);
  --cta-secondary-hover: var(--color-sand-100);

  /* ---- Status ---- */
  --status-success: var(--color-success);
  --status-success-bg: var(--color-success-tint);
  --status-warning: var(--color-warning);
  --status-warning-bg: var(--color-warning-tint);
  --status-danger: var(--color-danger);
  --status-danger-bg: var(--color-danger-tint);
  --status-info: var(--color-bahari-deep);
  --status-info-bg: var(--color-bahari-tint);

  /* Darkened for use as text on the matching tint above. Measured against
     their own -bg, not white: see the alert block below. */
  --status-primary-text: var(--color-coral-press);
  --status-success-text: #276A43;
  --status-warning-text: #8A5200;
  --status-danger-text: var(--color-danger);
  --status-info-text: var(--color-bahari-deep);

  /* ---- Charts ---- */
  --chart-1: var(--color-coral);
  --chart-2: var(--color-bahari);
  --chart-3: var(--color-usiku);
  --chart-4: var(--color-coral-soft);
  --chart-5: var(--color-bahari-soft);

  /* ---- Type ---- */
  --font-display: 'Rubik', ui-sans-serif, system-ui, sans-serif;
  --font-body: 'Lexend', ui-sans-serif, system-ui, sans-serif;
  --font-arabic: 'IBM Plex Sans Arabic', 'Lexend', ui-sans-serif, system-ui, sans-serif;

  --type-display-xxl: 64px;
  --type-display-xl: 48px;
  --type-display-lg: 36px;
  --type-display-md: 28px;
  --type-heading-lg: 22px;
  --type-heading-md: 18px;
  --type-heading-sm: 16px;
  --type-body-lg: 17px;
  --type-body: 15px;
  --type-body-sm: 13px;
  --type-caption: 12px;
  --type-eyebrow: 11px;

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-display: 700;

  /* ---- Spacing ---- */
  --space-2xs: 2px;
  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 12px;
  --space-base: 16px;
  --space-lg: 24px;
  --space-xl: 32px;
  --space-2xl: 40px;
  --space-3xl: 56px;
  --space-4xl: 80px;
  --space-5xl: 112px;

  /* ---- Radius: two families ----
     "Bubble" family (tail) = anything with a voice: badges, avatars,
     notifications, announcement cards. "Plain" family (symmetric) =
     buttons, inputs, generic cards/containers. */
  --radius-xs: 4px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-pill: 9999px;
  --tail: 4px;

  --radius-bubble-pill: 9999px 9999px 9999px var(--tail);
  --radius-bubble-sm: 10px 10px 10px var(--tail);
  --radius-bubble-md: 16px 16px 16px var(--tail);
  --radius-bubble-lg: 24px 24px 24px var(--tail);
  --radius-bubble-avatar: 50% 50% 50% var(--tail);
  --radius-bubble-reply: 16px 16px var(--tail) 16px;

  --radius-button: var(--radius-pill);
  --radius-input: 10px;
  --radius-card: var(--radius-lg);

  /* ---- Shadows (tinted with Usiku ink, not pure black) ---- */
  --shadow-1: 0 1px 2px rgba(30, 35, 64, .06), 0 1px 3px rgba(30, 35, 64, .06);
  --shadow-2: 0 6px 20px rgba(30, 35, 64, .10), 0 2px 6px rgba(30, 35, 64, .05);
  --shadow-3: 0 20px 48px rgba(30, 35, 64, .18), 0 4px 12px rgba(30, 35, 64, .08);
  --scrim: rgba(30, 35, 64, .48);

  /* ---- Motion ---- */
  --dur-fast: 120ms;
  --dur-base: 200ms;
  --dur-slow: 320ms;
  --ease-out: cubic-bezier(.2, 0, 0, 1);
  --ease-reply: cubic-bezier(.3, 1.35, .5, 1);
}

/* RTL: tail moves to the bottom-right; Arabic carries both display + body */
[dir="rtl"] {
  --radius-bubble-pill: 9999px 9999px var(--tail) 9999px;
  --radius-bubble-sm: 10px 10px var(--tail) 10px;
  --radius-bubble-md: 16px 16px var(--tail) 16px;
  --radius-bubble-lg: 24px 24px var(--tail) 24px;
  --radius-bubble-avatar: 50% 50% var(--tail) 50%;
  --radius-bubble-reply: 16px 16px 16px var(--tail);
  --font-display: var(--font-arabic);
  --font-body: var(--font-arabic);
}

/* =========================================================================
   Re-point Metronic/KTUI's own semantic tokens at the brand palette.
   This one block is what re-skins the entire component library.
   ========================================================================= */
:root, .dark {
  --font-sans: var(--font-body);

  --background: var(--color-white);
  --foreground: var(--color-ink);
  --card: var(--color-white);
  --card-foreground: var(--color-ink);
  --popover: var(--color-white);
  --popover-foreground: var(--color-ink);

  --primary: var(--color-coral);
  --primary-foreground: var(--color-usiku);

  --secondary: var(--color-sand-100);
  --secondary-foreground: var(--color-ink);

  --muted: var(--color-sand-50);
  --muted-foreground: var(--color-ink-3);

  --accent: var(--color-bahari-tint);
  --accent-foreground: var(--color-bahari-deep);

  --destructive: var(--color-danger);
  --destructive-foreground: var(--color-white);

  --mono: var(--color-usiku);
  --mono-foreground: var(--color-white);

  --border: var(--color-sand-200);
  --input: var(--color-sand-300);
  --ring: var(--color-coral);

  --radius: var(--radius-lg);
}

/* Backend sidebar/header are forced dark (.dark) regardless of app theme;
   give that surface the brand's raised-dark tone rather than Tailwind zinc. */
.dark {
  --background: var(--color-usiku);
  --foreground: var(--color-white);
  --card: var(--color-usiku-raised);
  --card-foreground: var(--color-white);
  --secondary: var(--color-usiku-raised);
  --secondary-foreground: var(--color-white);
  --muted: var(--color-usiku-raised);
  --muted-foreground: var(--text-on-dark-muted);
  --accent: var(--color-usiku-raised);
  --accent-foreground: var(--color-white);
  --border: var(--color-usiku-line);
  --input: var(--color-usiku-line);

  /* Inverted here, and it has to be. The sidebar menu uses text-mono for its
     hover and active states, so leaving --mono at the :root value painted
     navy text onto this navy surface - the hovered item simply vanished.
     Every other colour in this block is already redefined for the dark
     surface; --mono was the one that was missed. */
  --mono: var(--color-white);
  --mono-foreground: var(--color-usiku);

  /* The same oversight, found later and in the same way. Dropdowns inside
     this surface paint themselves with --popover, which stayed at the :root
     white while --foreground above flipped to white - so the signed-in name
     and email in the sidebar's profile menu rendered white on white and the
     menu looked empty. The sidebar is deliberately dark, so its popovers
     are dark too. */
  --popover: var(--color-usiku-raised);
  --popover-foreground: var(--color-white);

  /* Links too. brand.css sets `a { color: var(--text-link) }` unlayered,
     which beats Metronic's layered .kt-dropdown-menu-link rule whatever the
     specificity says, so the Settings link in the sidebar's profile menu
     came out as --color-coral-text on navy: about 1.9:1, unreadable. The
     soft coral clears 5.9:1 on this surface. */
  --text-link: var(--color-coral-soft);
  --text-link-hover: var(--color-white);
}

/* --accent is the raised tone, which is now also the popover's own fill, so
   the stock hover would paint the row the colour it already is. Lift the
   hover one step further rather than leaving it invisible. */
.dark .kt-dropdown-menu-link:hover,
.dark .kt-dropdown-menu-link:focus-visible {
  background-color: var(--color-usiku-line);
  color: var(--color-white);
}

/* Section labels in the backend sidebar. kt-menu-heading carries no base
   styling in this layout (Metronic only styles it for a collapsed-sidebar
   demo we do not use), so it is purely the semantic hook here. */
.dark .kt-menu-heading {
  padding: var(--space-base) var(--space-sm) var(--space-2xs);
  font-size: 10.5px;
  font-weight: var(--weight-medium);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-on-dark-muted);
}
.dark .kt-menu-item:first-child > .kt-menu-heading { padding-top: var(--space-xs); }

/* ---- Base typography ---- */
body {
  font-family: var(--font-sans);
  color: var(--text-body);
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-body);
  font-weight: var(--weight-medium);
}

/* Display tier: marketing hero headlines and large stat/report numbers */
.t-display,
.t-display-xxl, .t-display-xl, .t-display-lg, .t-display-md {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 0;
}
.t-display-xxl { font-size: clamp(32px, 5vw, 64px); line-height: 1.04; letter-spacing: -0.03em; }
.t-display-xl  { font-size: clamp(28px, 4vw, 48px); line-height: 1.06; letter-spacing: -0.025em; }
.t-display-lg  { font-size: clamp(24px, 3vw, 36px); line-height: 1.1;  letter-spacing: -0.016em; }
.t-display-md  { font-size: clamp(20px, 2.4vw, 28px); line-height: 1.16; letter-spacing: -0.01em; }

.t-heading-lg { font-size: var(--type-heading-lg); line-height: 1.3; font-weight: var(--weight-medium); margin: 0; }
.t-heading-md { font-size: var(--type-heading-md); line-height: 1.35; font-weight: var(--weight-medium); margin: 0; }
.t-heading-sm { font-size: var(--type-heading-sm); line-height: 1.4; font-weight: var(--weight-medium); margin: 0; }
.t-body-lg { font-size: var(--type-body-lg); line-height: 1.6; }
.t-body-sm { font-size: var(--type-body-sm); line-height: 1.5; }
.t-caption { font-size: var(--type-caption); line-height: 1.4; color: var(--text-muted); }
.t-eyebrow {
  display: inline-block;
  font-size: var(--type-eyebrow);
  letter-spacing: .09em;
  text-transform: uppercase;
  font-weight: var(--weight-medium);
  color: var(--text-link);
}

[dir="rtl"] .t-display,
[dir="rtl"] .t-display-xxl, [dir="rtl"] .t-display-xl, [dir="rtl"] .t-display-lg, [dir="rtl"] .t-display-md,
[dir="rtl"] .t-eyebrow {
  letter-spacing: 0;
}
[dir="rtl"] .t-eyebrow { text-transform: none; }

.tnum {
  font-variant-numeric: tabular-nums;
}

/* ---- Buttons: fully round, coral CTA with the navy-then-white rule ---- */
.kt-btn {
  border-radius: var(--radius-button);
  transition: var(--dur-fast) var(--ease-out);
  transition-property: background-color, color, border-color, box-shadow;
}

.kt-btn:not(.kt-btn-outline):not(.kt-btn-ghost):not(.kt-btn-mono):not(.kt-btn-destructive) {
  color: var(--cta-fg);
}
@media (hover: hover) {
  .kt-btn:not(.kt-btn-outline):not(.kt-btn-ghost):not(.kt-btn-mono):not(.kt-btn-destructive):hover {
    color: var(--cta-fg-hover);
  }
}
.kt-btn:not(.kt-btn-outline):not(.kt-btn-ghost):not(.kt-btn-mono):not(.kt-btn-destructive).active {
  color: var(--cta-fg-hover);
}

.kt-input, .kt-select, .kt-textarea {
  border-radius: var(--radius-input);
}

/* ---- Checkboxes: Metronic derives this from the global --radius token
   (calc(var(--radius) - 4px)), so repointing --radius to the brand's 16px
   card radius balloons an 18px checkbox into a near-circle. Per the brand
   guidelines, checkboxes use a fixed small radius regardless of --radius. */
.kt-checkbox {
  border-radius: var(--radius-xs);
}

/* ---- Cards: plain data containers stay symmetric ---- */
.kt-card {
  border-radius: var(--radius-card);
}

/* ---- Badges / status pills: tailed, mapped to status tokens ---- */
.kt-badge {
  border-radius: var(--radius-bubble-pill);
}
.kt-badge-success,
.kt-badge-outline.kt-badge-success { color: var(--status-success); background-color: var(--status-success-bg); border-color: var(--status-success-bg); }
.kt-badge-warning,
.kt-badge-outline.kt-badge-warning.kt-badge-outline { color: var(--status-warning); background-color: var(--status-warning-bg); border-color: var(--status-warning-bg); }
.kt-badge-destructive,
.kt-badge-outline.kt-badge-destructive.kt-badge-outline { color: var(--status-danger); background-color: var(--status-danger-bg); border-color: var(--status-danger-bg); }
.kt-badge-info,
.kt-badge-outline.kt-badge-info.kt-badge-outline { color: var(--status-info); background-color: var(--status-info-bg); border-color: var(--status-info-bg); }
.kt-badge-outline.kt-badge-primary { color: var(--text-link); background-color: var(--surface-coral-tint); border-color: var(--surface-coral-tint); }
.kt-badge-outline.kt-badge-secondary { color: var(--text-muted); background-color: var(--surface-sand); border-color: var(--border-hairline); }

/* ---- Radios: a radio group with no option selected yet matches CSS
   :indeterminate (per spec), and Metronic styles :indeterminate identically
   to :checked, so an unanswered required radio group (e.g. the consent
   form) renders with every option looking pre-selected. Indeterminate
   should look like the plain unchecked state instead. ---- */
.kt-radio:indeterminate {
  background-color: var(--background);
  border-color: var(--input);
  color: transparent;
}

/* ---- Avatars: tailed ---- */
.kt-avatar-image, .kt-avatar img {
  border-radius: var(--radius-bubble-avatar);
}

/* ---- Alerts: brand tints, with text dark enough to read on them ----------
   Metronic fills alerts with a saturated colour; these tints are quieter. The
   status colours themselves are tuned for white, and on their own tints
   warning fell to 3.79:1 and success to 4.35:1, both under AA. The --status-*
   -text tokens below are the same hues darkened until they clear AA on the
   matching tint, and they are used only here, so badges and pills keep the
   brand palette untouched. No left accent rule: --radius is 14px, and a 3px
   edge on that curve reads as a smudge rather than a bar.

   kt-alert-primary was never mapped here at all, which is why that one alert
   still rendered as Metronic's solid coral slab with navy text on it. ---- */
.kt-alert-primary { background-color: var(--surface-coral-tint); color: var(--status-primary-text); }
.kt-alert-success { background-color: var(--status-success-bg); color: var(--status-success-text); }
.kt-alert-warning { background-color: var(--status-warning-bg); color: var(--status-warning-text); }
.kt-alert-danger, .kt-alert-destructive { background-color: var(--status-danger-bg); color: var(--status-danger-text); }
.kt-alert-info { background-color: var(--status-info-bg); color: var(--status-info-text); }

/* An icon marked .kt-alert-accent keeps the full-strength status colour: it
   is a shape, not text, so it is not bound by the contrast floor. */
.kt-alert-primary .kt-alert-accent { color: var(--color-coral); }
.kt-alert-success .kt-alert-accent { color: var(--status-success); }
.kt-alert-warning .kt-alert-accent { color: var(--status-warning); }
.kt-alert-danger .kt-alert-accent,
.kt-alert-destructive .kt-alert-accent { color: var(--status-danger); }
.kt-alert-info .kt-alert-accent { color: var(--status-info); }

/* ---- Screen-reader-only utility: Metronic's bundled styles.css only ships
   the specific utility classes its own templates use, and .sr-only (used by
   the custom file-input component to hide the native <input type=file>
   behind a styled label) isn't one of them, so the native control was
   rendering fully visible, duplicating the "no file chosen" text. ---- */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

/* ---- Links ---- */
a { color: var(--text-link); }
a:hover { color: var(--text-link-hover); }

/* ---- Focus ring ---- */
:focus-visible {
  box-shadow: var(--focus-ring);
}

/* =========================================================================
   Marketing site: hero mockup, alternating feature showcases, closing
   panel and footer. Hand-authored rather than Tailwind utilities: Metronic's
   bundled styles.css only ships the specific utility classes its own admin
   templates use, so arbitrary spacing/grid/responsive classes silently do
   nothing (no max-w-3xl, no py-16, no md:/lg: variants, etc).
   ========================================================================= */

.mk-section { padding: var(--space-4xl) 0; }
.mk-section--tight { padding: var(--space-3xl) 0; }
.mk-section--soft { background: var(--surface-soft); }

.mk-eyebrow-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 16px;
  border-radius: var(--radius-bubble-pill);
  background: var(--surface-coral-tint);
  color: var(--text-link);
  font-size: 13px;
  font-weight: var(--weight-medium);
}

/* ---- Contact layout -----------------------------------------------------
   The columns used to be an inline style, so no media query could reach them
   and the two-column split survived down to phone width, pushing the card
   5px past the viewport. Single column until there is room for two. ---- */
.mk-contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
}
@media (min-width: 960px) {
  .mk-contact-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: 40px; }
}
/* Stacked, the form is what the page is for. Reaching it should not mean
   scrolling past an address block first. */
@media (max-width: 959px) {
  .mk-contact-grid > .kt-card { order: -1; }
}

/* ---- Delegate shell -----------------------------------------------------
   The signed-in delegate area. Its bottom bar and status dot are declared
   here because styles.css is prebuilt: inset-x-0 and bg-warning are not in
   it, so those utilities would have been silently inert. ---- */
/* ---- The delegate shell -------------------------------------------------

   Navigation sits at the top and stays there. It used to be a fixed bar
   along the bottom of a phone, which put it under the thumb but also under
   the reader's notice: delegates reported not finding the badge or the
   account at all, because a row of small icons at the foot of a long page
   reads as part of the browser rather than part of the site.

   Declared here rather than with utilities because styles.css is prebuilt:
   the sticky, flex-wrap and scroll behaviours this needs at these
   breakpoints are not in the shipped file, so utility classes for them
   would compile to nothing at all. */
.bz-delegate-header {
  position: sticky;
  top: 0;
  z-index: 30;
}

.bz-delegate-header__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm, 10px);
}

/* The one rule that stops the overlap: the name may shrink, and truncate. */
.bz-delegate-header__identity {
  min-width: 0;
  flex: 1 1 auto;
}

.bz-delegate-header__actions { flex: 0 0 auto; }

/* ---- The tab strip ------------------------------------------------------
   Scrolls sideways rather than wrapping. Seven tabs on a narrow phone would
   otherwise become three stacked rows of header, and the reader would have
   to scroll past the navigation to reach any of the event. */
.bz-delegate-tabs {
  display: flex;
  align-items: stretch;
  gap: 2px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* Each tab's active underline sits on this line. */
  box-shadow: inset 0 -1px 0 var(--color-border, #E5E7EB);
}

.bz-delegate-tabs::-webkit-scrollbar { display: none; }

.bz-delegate-tab {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 10px 12px;
  font-size: var(--type-caption, 12px);
  color: var(--text-secondary, #6B7280);
  border-bottom: 2px solid transparent;
  text-decoration: none;
  /* 44px is the smallest target a thumb hits reliably, and this strip is
     operated one-handed while standing in a conference hall. */
  min-height: 44px;
}

.bz-delegate-tab:hover { color: var(--text-primary, #1E2340); }

.bz-delegate-tab--active,
.bz-delegate-tab[aria-current] {
  color: var(--color-coral, #F26B4A);
  border-bottom-color: var(--color-coral, #F26B4A);
  font-weight: var(--weight-medium, 500);
}

.bz-delegate-tab:focus-visible {
  outline: 2px solid var(--color-coral, #F26B4A);
  outline-offset: -2px;
}

/* An anchor must land below the sticky header, not behind it. Without this
   every section tab scrolls the heading out of sight under the strip, which
   looks like the link went to the wrong place.

   The offset is the header's real height, measured and written to this
   variable by delegate-tabs.js, because the header is not one height: the
   identity and the actions take separate lines on a phone and share one on
   a laptop, and a long event name can wrap on either. A hardcoded guess was
   35px short at 467px wide, which put the heading back under the strip.

   The fallback is deliberately generous. If the script never runs, landing
   slightly low is a small oddity; landing high hides the thing you asked
   for. */
.bz-delegate-doc {
  scroll-padding-top: var(--bz-delegate-header-h, 160px);
}

@media (max-width: 767px) {
  .bz-delegate-header__top {
    flex-wrap: wrap;
    row-gap: 10px;
  }

  /* Each gets its own line, so neither can land on the other. */
  .bz-delegate-header__identity,
  .bz-delegate-header__actions { flex: 1 1 100%; }

  .bz-delegate-header__actions { justify-content: flex-start; }
}

.bz-dot-warning {
  background: var(--status-warning);
}

/* ---- Delegate programme -------------------------------------------------
   A day at a time, and breaks told apart from sessions. A flat list of 47
   rows across five days is a list nobody reads, and a coffee break set in
   the same weight as a keynote reads as another thing to attend. ---- */
.bz-day-tab {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  color: var(--text-secondary);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.bz-day-tab:hover { color: var(--text-body); }
.bz-day-tab.is-active {
  color: var(--color-coral-text);
  border-bottom-color: var(--color-coral);
  font-weight: var(--weight-medium);
}
.bz-day-tab__count {
  font-size: 11px;
  background: var(--surface-soft);
  color: var(--text-muted);
  border-radius: var(--radius-pill);
  padding: 1px 7px;
  font-variant-numeric: tabular-nums;
}
.bz-day-tab.is-active .bz-day-tab__count {
  background: var(--surface-coral-tint);
  color: var(--color-coral-text);
}

.bz-slot {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 14px;
  padding: 12px 14px;
  border-radius: var(--radius-bubble-md, 12px);
  border: 1px solid transparent;
}
.bz-slot + .bz-slot { margin-top: 2px; }
.bz-slot__time {
  font-size: 12px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  padding-top: 2px;
}
.bz-slot__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.bz-slot__title { font-size: 14px; font-weight: var(--weight-medium); color: var(--text-body); text-wrap: pretty; }
.bz-slot__meta { font-size: 12px; color: var(--text-muted); }

/* Add to calendar, on a programme row.

   Quiet on purpose. It appears on every session, and a page of forty rows
   each carrying a button reads as a form to fill in rather than a programme
   to read. It becomes a link proper on hover and carries a visible focus
   ring, because it is still something to press. */
.bz-slot__cal {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-muted);
  text-decoration: none;
  /* A 44px row would double the height of every session. The target is
     widened sideways instead, where there is room for it. */
  padding: 4px 2px;
}
.bz-slot__cal:hover { color: var(--color-bahari-deep); text-decoration: underline; }
.bz-slot__cal:focus-visible { outline: 2px solid var(--color-bahari); outline-offset: 2px; border-radius: 4px; }

/* The room, or the track, on a programme card.

   Tinted rather than outlined: on a page of white cards an outlined pill
   reads as a disabled control, and this is a label, not something to press.
   Bahari rather than coral, because this appears on every single card and
   coral is the brand's action colour - a page of coral pills competes with
   the active day tab and with every button on it for the eye.

   No icon, deliberately. The same field is a room at one event ("Plenary
   Hall") and a track at another ("AI & Society"), and a map pin would be
   wrong half the time. */
.bz-room {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  max-width: 100%;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--surface-bahari-tint);
  border: 1px solid var(--color-bahari-soft);
  color: var(--color-bahari-deep);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.6;
}

/* Online or hybrid, beside the room. Coral so that two pills on one card
   read as two different facts rather than one repeated, and because this is
   the rarer and more notable of the two. */
.bz-room--online {
  background: var(--color-coral-tint);
  border-color: var(--color-coral-tint-2);
  color: var(--color-coral-text);
}

/* Not a session: lighter, tinted, and the title drops to normal weight. */
.bz-slot--break {
  background: var(--surface-bahari-tint);
  border-color: var(--color-bahari-tint);
}
.bz-slot--break .bz-slot__title {
  font-weight: var(--weight-regular, 400);
  color: var(--color-bahari-deep);
}
.bz-slot--break .bz-slot__time { color: var(--color-bahari-deep); }

@media (max-width: 520px) {
  .bz-slot { grid-template-columns: minmax(0, 1fr); gap: 2px; }
}

/* Organiser-written description, which arrives as rich text. */
.bz-rich > *:first-child { margin-top: 0; }
.bz-rich > *:last-child { margin-bottom: 0; }
.bz-rich p { margin: 0 0 10px; }
.bz-rich ul, .bz-rich ol { margin: 0 0 10px; padding-inline-start: 1.25em; }
.bz-rich img { max-width: 100%; height: auto; border-radius: 10px; }
.bz-rich a { color: var(--text-link); }

/* ---- Delegate area mock -------------------------------------------------
   The delegate side as a delegate meets it: a menu with something waiting,
   and a poll mid-answer. ---- */
.mk-delegate-mock {
  width: 100%;
  max-width: 340px;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-bubble-md);
  overflow: hidden;
}
.mk-delegate-mock__bar {
  display: flex;
  gap: 2px;
  padding: 10px 8px;
  border-bottom: 1px solid var(--border-hairline);
  font-size: 11px;
  color: var(--text-muted);
}
.mk-delegate-mock__bar span {
  position: relative;
  flex: 1;
  text-align: center;
  padding: 4px 2px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.mk-delegate-mock__bar .is-active {
  background: var(--surface-coral-tint);
  color: var(--color-coral-text);
  font-weight: var(--weight-medium);
}
.mk-delegate-mock__dot {
  position: absolute;
  top: -3px;
  inset-inline-end: 0;
  min-width: 14px;
  height: 14px;
  border-radius: var(--radius-pill);
  background: var(--color-coral);
  color: var(--color-usiku);
  font-size: 9px;
  font-style: normal;
  font-weight: var(--weight-medium);
  line-height: 14px;
  text-align: center;
}
.mk-delegate-mock__body { padding: 14px; display: flex; flex-direction: column; gap: 10px; }
.mk-delegate-mock__body strong { font-size: 13px; color: var(--text-body); }
.mk-delegate-mock__row { display: flex; flex-direction: column; gap: 4px; font-size: 11px; color: var(--text-muted); }
.mk-delegate-mock__meter { height: 6px; border-radius: var(--radius-pill); background: var(--surface-soft); overflow: hidden; }
.mk-delegate-mock__meter i { display: block; height: 100%; background: var(--color-coral); border-radius: var(--radius-pill); }

/* ---- AI import visual ---------------------------------------------------
   A document on the left, the programme it becomes on the right. The arrow
   between them is three dots rather than a glyph, so it can carry a little
   motion without a sprite. ---- */
.mk-ai-import {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: center;
  gap: var(--space-base);
}

.mk-ai-import__doc {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 16px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--background);
  font-size: 12px;
  color: var(--text-secondary);
  text-align: center;
}
.mk-ai-import__doc i { font-size: 26px; color: var(--text-link); }

.mk-ai-import__arrow { display: flex; align-items: center; gap: 5px; }
.mk-ai-import__arrow span {
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: var(--color-coral);
  opacity: .35;
  animation: mk-ai-flow 1.4s ease-in-out infinite;
}
.mk-ai-import__arrow span:nth-child(2) { animation-delay: .18s; }
.mk-ai-import__arrow span:nth-child(3) { animation-delay: .36s; }

@keyframes mk-ai-flow {
  0%, 100% { opacity: .25; transform: translateX(0); }
  50%      { opacity: 1;   transform: translateX(2px); }
}

.mk-ai-import__out {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.mk-ai-import__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--background);
  font-size: 12px;
  color: var(--text-primary);
}
.mk-ai-import__row .tnum { color: var(--text-muted); flex: none; }
.mk-ai-import__row--person { border-style: dashed; }
.mk-ai-import__avatar {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: color-mix(in oklab, var(--color-coral) 14%, transparent);
  color: var(--color-coral-press);
  font-size: 11px;
  font-weight: 600;
  flex: none;
}

/* Stacked, the arrow would point at nothing, so it lies down. */
@media (max-width: 560px) {
  .mk-ai-import { grid-template-columns: minmax(0, 1fr); justify-items: stretch; }
  .mk-ai-import__arrow { justify-content: center; transform: rotate(90deg); }
}

@media (prefers-reduced-motion: reduce) {
  .mk-ai-import__arrow span { animation: none; opacity: .5; }
}

/* ---- Portal handbook ----------------------------------------------------
   A reference document inside an application: a contents rail that follows
   you down the page, and a reading column that does not stretch to the width
   of a dashboard. Declared here because styles.css is prebuilt and the grid
   below uses values no utility class carries. ---- */
.bz-handbook {
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: 48px;
  align-items: start;
}

.bz-hb-rail {
  position: sticky;
  top: 16px;
  font-size: 13px;
  max-height: calc(100vh - 120px);
  overflow-y: auto;
}
.bz-hb-rail__label {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: 11px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.bz-hb-rail ol { list-style: none; margin: 0; padding: 0; }

/* Group headings in the rail. Thirty-three links in one column is a list
   nobody reads to the bottom of; eight headings of three to six turn it
   into something you scan.

   Coral, with a rule above, which is exactly what the same headings do down
   the page - the rail and the reading order should not only agree about
   order, they should look like the same document. Grey uppercase on its own
   was not enough: against navy links at 13px it read as a faint caption
   rather than as the thing the links hang under. */
.bz-hb-rail__group {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: 10.5px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--color-coral-text);
  margin: 20px 0 6px;
  padding: 11px 9px 0;
  border-top: 1px solid rgb(0 0 0 / .08);
}
.bz-hb-rail__group:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
.bz-hb-rail a {
  display: block;
  padding: 4px 9px;
  border-radius: 6px;
  color: var(--text-secondary);
  text-decoration: none;
  /* Quieter than the heading above it, so the hierarchy reads at a glance
     rather than after comparing two type sizes. */
  font-weight: var(--weight-regular, 400);
}
.bz-hb-rail a:hover { color: var(--color-coral-text); background: var(--color-sand-100, rgb(0 0 0 / .03)); }

.bz-hb-body { max-width: 72ch; }
.bz-hb-body section { scroll-margin-top: 90px; }
.bz-hb-body section + section { margin-top: 44px; }

/* The same groups down the page, so the rail and the reading order agree.
   A rule above each one, because the break is the point. */
.bz-hb-group {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: 11px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--color-coral-text);
  margin: 56px 0 22px;
  padding-top: 22px;
  border-top: 1px solid rgb(0 0 0 / .08);
}
.bz-hb-group:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
.bz-hb-group + section { margin-top: 0; }

.bz-hb-body h2 {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: 22px;
  letter-spacing: -.015em;
  margin: 0 0 8px;
}
.bz-hb-body h3 {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: 15.5px;
  margin: 22px 0 6px;
}
.bz-hb-body p { margin: 0 0 13px; line-height: 1.65; }
.bz-hb-body ul { padding-left: 19px; margin: 0 0 13px; }
.bz-hb-body li { margin-bottom: 6px; line-height: 1.6; }

/* The role chip. Only four of nineteen sections are admin-only, so marking
   them is a short true signal rather than decoration. */
.bz-hb-chip { margin-bottom: 10px; }
.bz-hb-chip--both  { color: var(--color-coral-text); border-color: var(--color-coral-soft); }
.bz-hb-chip--admin { color: var(--color-bahari-deep); border-color: var(--color-bahari-soft); }

.bz-hb-table { font-size: 14px; }
.bz-hb-yes { color: var(--color-bahari-deep); font-weight: var(--weight-medium); }
.bz-hb-no  { color: var(--text-muted); }

.bz-hb-note { align-items: flex-start; margin: 16px 0; }

.bz-hb-steps {
  counter-reset: bz-step;
  list-style: none;
  padding-left: 0;
  margin: 0 0 13px;
}
.bz-hb-steps li {
  counter-increment: bz-step;
  position: relative;
  padding-inline-start: 32px;
  margin-bottom: 10px;
  line-height: 1.6;
}
.bz-hb-steps li::before {
  content: counter(bz-step);
  position: absolute;
  inset-inline-start: 0;
  top: 1px;
  width: 21px;
  height: 21px;
  border-radius: 999px;
  background: var(--color-coral-tint);
  color: var(--color-coral-text);
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: 11.5px;
  display: grid;
  place-items: center;
}

.bz-hb-foot {
  margin-top: 28px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  color: var(--text-muted);
}

@media (max-width: 1100px) {
  .bz-handbook { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .bz-hb-rail {
    position: static;
    max-height: none;
    margin-bottom: 28px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
  }
  .bz-hb-rail ol { columns: 2; column-gap: 22px; }
  .bz-hb-body { max-width: none; }
}

/* ---- Embed attribution --------------------------------------------------
   Shared by both embeds. Quiet by default: a credit on somebody else's page
   is not a promotion, and it should not compete with their content. ---- */
.bz-poweredby {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 14px;
  padding-top: 10px;
  font-size: 11px;
  line-height: 1;
  color: var(--text-muted);
  text-decoration: none;
  transition: color .15s ease;
}
.bz-poweredby:hover { color: var(--text-secondary); }
.bz-poweredby__mark { display: block; flex: none; }

/* ---- Row action menu ----------------------------------------------------
   The dropdown a table row's three-dot button opens. Width lives here because
   styles.css is prebuilt and would not compile an arbitrary w-[180px]. ---- */
.bz-row-menu {
  width: 190px;
}

/* ---- Sticky actions column ----------------------------------------------
   A wide table scrolls horizontally, and the row's actions sit in the last
   column, so reaching them means scrolling right every time. Worse, the
   three-dot menu inside it opened at the toggle's UNSCROLLED position: on a
   table wider than the viewport the menu rendered off-screen to the right,
   and clicking it appeared to do nothing at all.

   Pinning the column to the right edge fixes both. The actions are always
   reachable, and the toggle now has a stable on-screen position for the menu
   to open against. ---- */
.bz-actions-col {
  position: sticky;
  right: 0;
  z-index: 2;
  background: var(--background);
  /* A hairline so a scrolled row reads as passing underneath, rather than
     the buttons appearing to belong to whatever column is behind them. */
  box-shadow: -8px 0 8px -8px rgb(30 35 64 / .18);
}

/* The header cell needs to outrank the body cells it scrolls over. */
thead .bz-actions-col {
  z-index: 3;
  background: var(--color-sand, var(--background));
}

/* An open menu has to outrank the header it opens over.

   The pinned cell is position:sticky with a z-index, which makes it a
   stacking context - so the dropdown's own z-index of 105 is resolved
   INSIDE that context, against siblings, and the whole subtree still
   paints below the header's z-index of 3. The menu was therefore drawn
   underneath the sticky header: its button rendered as an unlabelled
   block of colour, because the centred label sat behind the header while
   the left edge of the button poked out beside it.

   Raised only while a menu is open, so a scrolled row still passes
   underneath the header the rest of the time. */
.bz-actions-col:has(> [data-kt-dropdown].open),
.bz-actions-col:has(.kt-dropdown-menu.open) {
  z-index: 4;
}

/* Nothing to pin when the whole table already fits. */
@media (max-width: 640px) {
  .bz-actions-col { position: static; box-shadow: none; }
}

/* The reject panel. A dropdown menu is sized for links, so it needs a real
   width to hold a textarea without the field spilling out of it. */
.bz-reject-panel {
  width: 320px;
  max-width: calc(100vw - 32px);
  padding: var(--space-base);
}

/* kt-input sets a single-line height, which wins over the rows attribute
   and leaves a three-row textarea one line tall. */
.bz-reject-panel textarea {
  width: 100%;
  min-height: 72px;
  height: auto;
  padding-block: 8px;
  line-height: 1.45;
  resize: vertical;
}

/* ---- Money figures -------------------------------------------------------
   Real rules rather than utilities: lg:grid-cols-4 and lg:col-span-4 are not
   in the prebuilt styles.css, so they compile to nothing and a four-figure
   row silently stacks. ------------------------------------------------- */

.bz-figures {
  display: grid;
  gap: var(--space-base);
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 640px) {
  .bz-figures { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .bz-figures { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* The headline total sits under the four, full width at every size. */
.bz-figures__total {
  grid-column: 1 / -1;
  border-top: 1px solid var(--color-line, var(--border));
  padding-top: var(--space-base);
}

/* Digits that line up in a column, and never wrap mid-number. */
.bz-figure {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---- Wide tables inside a grid ------------------------------------------
   A `display:grid` wrapper with no explicit columns creates one implicit
   `auto` track, and an `auto` track floors at its item's min-content width.
   So a card holding a wide table refuses to shrink: the card grows past the
   grid, the overflow-x:auto container never becomes narrower than its own
   content, and the table therefore never scrolls - it just pushes the page
   sideways and takes the pinned actions column off-screen with it.

   minmax(0, 1fr) removes that floor, which lets the scroll container do the
   job it was already asked to do. Scoped with :has() to exactly the wrappers
   that contain a horizontal scroller, so ordinary card grids are untouched.
   ------------------------------------------------------------------------- */

.grid:has(> .kt-card .kt-scrollable-x-auto) {
  grid-template-columns: minmax(0, 1fr);
}

/* ---- Event page branding ------------------------------------------------
   The event's logo sits in a card lifted onto the bottom of the banner, the
   way a profile mark sits on a cover image. It was 28px tall in the corner of
   the language row, which is unreadable for any mark carrying a wordmark, and
   it competed with the language buttons instead of introducing the event.

   The lift only applies when there is a banner to lift onto; without one the
   card simply starts the content. ---- */
.bz-event-brand {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-base);
  flex-wrap: wrap;
}

.bz-event-logo {
  display: grid;
  place-items: center;
  padding: 10px 14px;
  background: var(--background);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 6px 20px rgb(30 35 64 / .10);
}

/* Only when a banner is above it. */
.bz-event-logo--over {
  margin-top: -46px;
}

.bz-event-logo img {
  display: block;
  height: 76px;
  width: auto;
  max-width: 260px;
  object-fit: contain;
}

.bz-event-brand__lang {
  /* Sits on the baseline of the logo card rather than floating against its
     full height. */
  align-self: flex-end;
  padding-bottom: 2px;
}

@media (max-width: 640px) {
  .bz-event-logo--over { margin-top: -30px; }
  .bz-event-logo { padding: 8px 10px; border-radius: 12px; }
  .bz-event-logo img { height: 52px; max-width: 190px; }
  /* Stacked, the switcher reads as its own row rather than a stray column. */
  .bz-event-brand { gap: 10px; }
  .bz-event-brand__lang { align-self: flex-start; }
}

/* ---- Speaker cards ------------------------------------------------------
   A line-up reads as a group, not a list: stacked full-width rows made
   twenty-six people look like a database dump. auto-fill rather than
   auto-fit, so a short line-up keeps card-sized cards instead of stretching
   two of them across the whole width.

   Declared here because styles.css is prebuilt: a minmax() arbitrary value
   in a utility class would compile to nothing. ---- */
.bz-speakers {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 12px;
}

.bz-speaker {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 20px 14px;
  text-align: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 12px);
  background: var(--background);
  transition: border-color .15s ease;
}
.bz-speaker:hover { border-color: var(--color-coral); }

.bz-speaker__avatar {
  width: 64px;
  height: 64px;
  border-radius: 999px;
  object-fit: cover;
  flex: none;
  display: grid;
  place-items: center;
  background: color-mix(in oklab, var(--color-coral) 12%, transparent);
  color: var(--color-coral-press);
  font-weight: 600;
  font-size: 22px;
}

.bz-speaker__name {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  /* A long name wraps rather than being cut: these are people's names. */
  overflow-wrap: anywhere;
}

/* Three lines under a name, and they were two colours between them: the
   organisation and the biography both sat on --text-muted, so a card read
   as a name followed by an undifferentiated grey block. Each line now says
   what kind of line it is before it is read.

   The job title stays the darkest of the three because it is the one most
   people scan for. The organisation takes the brand's own text colour,
   which separates it without introducing a fourth hue. The biography is
   the quietest, being the part you read only if the first three interested
   you. */
.bz-speaker__role {
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-secondary);
  font-weight: var(--weight-medium, 500);
}

.bz-speaker__org {
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-link);
}

.bz-speaker__bio {
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
  margin-top: 2px;
}

/* One per row on the narrowest phones, where a 230px floor would overflow. */
@media (max-width: 380px) {
  .bz-speakers { grid-template-columns: minmax(0, 1fr); }
}

/* ---- Touch-sized form controls ------------------------------------------
   Metronic sets .kt-input at 13px/34px, which is a desktop density. On a
   phone it causes two distinct problems:

     1. iOS Safari zooms the whole page in whenever a field under 16px takes
        focus, and does not zoom back out afterwards. That single rule is
        what makes a form feel broken on an iPhone.
     2. 34px is well under the ~44px minimum comfortable touch target, so
        neighbouring fields are easy to hit by mistake.

   Fixed here rather than per-form so every form on the platform benefits.
   brand.css is unlayered, so these also override the -sm and -lg modifiers,
   which is intended: on a phone there is no such thing as a field too small
   to trigger the zoom. Desktop density is untouched. ---- */
@media (max-width: 767px) {
  .kt-input,
  .kt-textarea,
  .kt-select {
    font-size: 16px;
    line-height: 1.5;
  }

  .kt-input,
  .kt-select {
    height: 44px;
    padding-inline: 12px;
  }

  .kt-textarea {
    padding: 10px 12px;
  }

  /* Full-width submit: a button the width of its label is a small target at
     the end of a column of full-width fields, and reads as unfinished. */
  .mk-form-actions .kt-btn {
    width: 100%;
    justify-content: center;
    /* kt-btn-lg still lands at 40px, just under the comfortable minimum. */
    height: 48px;
    font-size: 15px;
  }
}

/* ---- Reading column ------------------------------------------------------
   kt-container-fixed only picks up margin-inline:auto above 1280px, so a
   narrower max-width set on it sits hard against the left edge at every
   width below that. The About page was doing exactly that inline. ---- */
.mk-prose {
  max-width: 760px;
  margin-inline: auto;
}

/* ---- Trusted by ----------------------------------------------------------
   A marquee of client marks. Duplicated once in the markup so the loop has
   something to scroll into; the copy is aria-hidden so a screen reader hears
   each name once rather than twice. ---- */
.mk-trusted {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-base);
}
.mk-trusted__label {
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.mk-trusted__window {
  position: relative;
  width: 100%;
  overflow: hidden;
  /* Fades the marks in and out at the edges rather than clipping them dead. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.mk-trusted__track {
  display: flex;
  align-items: center;
  gap: var(--space-3xl);
  width: max-content;
  animation: mk-trusted-scroll 32s linear infinite;
}
.mk-trusted__window:hover .mk-trusted__track { animation-play-state: paused; }
.mk-trusted__item {
  display: grid;
  place-items: center;
  /* A fixed row height so the optical corrections below cannot shunt the
     marks off each other's baseline. */
  height: 64px;
  flex: none;
}
.mk-trusted__item img {
  height: var(--mk-logo-h, 44px);
  width: auto;
  max-width: 190px;
  object-fit: contain;
  /* Marks arrive in every colour. Draining them to one ink keeps the row
     reading as one band rather than a ransom note. */
  filter: grayscale(1);
  opacity: .62;
  transition: filter .2s ease, opacity .2s ease;
}
.mk-trusted__item:hover img { filter: none; opacity: 1; }
/* A name standing in for a mark we do not hold. It has to sit at the same
   visual weight as the real logos beside it, which means matching their
   faded ink rather than inheriting body-copy contrast: set bold and dark it
   out-shouted every actual client in the row. */
.mk-trusted__item span {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: -0.01em;
  color: var(--text-muted);
  opacity: .62;
  white-space: nowrap;
  transition: opacity .2s ease;
}
.mk-trusted__item:hover span { opacity: 1; }

@keyframes mk-trusted-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-25%); }
}

/* A marquee nobody asked for is hostile. Stopped, and centred, when the
   reader has said they do not want motion. */
@media (prefers-reduced-motion: reduce) {
  .mk-trusted__track { animation: none; flex-wrap: wrap; justify-content: center; width: 100%; }
  .mk-trusted__window { -webkit-mask-image: none; mask-image: none; }
}

/* ---- Marketing header ----------------------------------------------------
   One row at every width. Below 960px the links and the two buttons go into
   a drawer rather than wrapping, which previously stacked the header three
   rows deep before a phone showed any content. 960px is where the hero grid
   already goes two-column, so the header and the page break together. ---- */
.mk-header-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-base);
  padding-block: var(--space-base);
}
.mk-header-nav,
.mk-header-actions { display: none; }
.mk-header-burger { display: inline-flex; }

/* No display property here: brand.css is unlayered, so it would outrank
   Tailwind's .hidden and the panel would never close. KTUI owns display,
   toggling .hidden against .flex; flex-col on the element sets the axis. */
.mk-drawer-panel {
  position: fixed;
  inset-block: 0;
  inset-inline-end: 0;
  width: 300px;
  max-width: 85%;
  /* The slide is declared here rather than left to Metronic's own
     .kt-drawer-end rules: those resolve translate through --tw-translate-*
     variables that did not settle to 0 on open, leaving the panel parked
     off-canvas. brand.css is unlayered, so these win outright. KTUI still
     owns display and the .open class; this only moves the panel. */
  translate: 100% 0;
  transition: translate 300ms ease;
}
.mk-drawer-panel.open { translate: 0 0; }

/* In Arabic the inline end is the left edge, so it parks the other way. */
[dir="rtl"] .mk-drawer-panel { translate: -100% 0; }
[dir="rtl"] .mk-drawer-panel.open { translate: 0 0; }

@media (prefers-reduced-motion: reduce) {
  .mk-drawer-panel { transition: none; }
}
.mk-drawer-foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: var(--space-lg);
}
.mk-drawer-nav { display: flex; flex-direction: column; padding: var(--space-sm) 0; }
.mk-drawer-nav a {
  padding: 12px var(--space-lg);
  font-size: 15px;
  font-weight: var(--weight-medium);
  color: var(--text-body);
}
.mk-drawer-nav a:hover { background: var(--surface-soft); color: var(--text-link); }

@media (min-width: 960px) {
  .mk-header-nav {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
    font-size: 14px;
    font-weight: var(--weight-medium);
    color: var(--text-secondary);
  }
  .mk-header-actions { display: flex; align-items: center; gap: 12px; }
  .mk-header-burger { display: none; }
}

/* ---- The mark as the argument ---------------------------------------------
   Two bubbles, two lines: the problem beside the one that speaks, the answer
   beside the one that replies. The grid is what makes it read, each half of
   the mark sitting on its own line of text rather than floating beside both.
   ---- */
/* It sits in the copy column, between the headline and the buttons, so it
   needs a little air rather than a min-height of its own. */
.bz-argument { margin-block: var(--space-sm) var(--space-xs, 8px); }
.bz-argument {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: var(--space-lg);
  row-gap: var(--space-base);
  align-items: center;
  max-width: 520px;
}
.bz-argument__mark {
  grid-row: 1 / span 2;
  width: 76px;
  height: auto;
  overflow: visible;
}
.bz-argument__say,
.bz-argument__reply {
  transform-box: fill-box;
  transform-origin: 0 100%;
  transform: scale(0);
  transition: transform 620ms cubic-bezier(.3, 1.35, .5, 1);
}
.bz-argument.is-speaking .bz-argument__say { transform: scale(1); }
.bz-argument.is-replying .bz-argument__say,
.bz-argument.is-replying .bz-argument__reply { transform: scale(1); }

.bz-argument__problem,
.bz-argument__solution {
  margin: 0;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 420ms ease, transform 420ms ease;
  text-wrap: pretty;
}
.bz-argument__problem {
  font-size: 15px;
  color: var(--text-muted);
}
.bz-argument__problem s { text-decoration-color: var(--color-coral); }
.bz-argument__solution {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: clamp(17px, 2.2vw, 21px);
  line-height: 1.3;
  color: var(--color-ink);
}
.bz-argument.is-speaking .bz-argument__problem,
.bz-argument.is-replying .bz-argument__problem,
.bz-argument.is-replying .bz-argument__solution {
  opacity: 1;
  transform: none;
}

/* Reduced motion gets the first pair, whole and still. Holding the shapes at
   scale(0) would leave the mark missing rather than calm. */
@media (prefers-reduced-motion: reduce) {
  .bz-argument__say,
  .bz-argument__reply { transform: scale(1); transition: none; }
  .bz-argument__problem,
  .bz-argument__solution { opacity: 1; transform: none; transition: none; }
}

@media (max-width: 560px) {
  .bz-argument { grid-template-columns: 56px minmax(0, 1fr); column-gap: var(--space-base); }
  .bz-argument__mark { width: 56px; }
}

/* ---- Animated mark -------------------------------------------------------
   Lifted from "10 Motion/barazas-logo-animation.html" in the brand assets.
   The brand file loops forever on a 2600ms cycle and scales both shapes back
   to 0 between cycles; that suits the video intro and loader it is specified
   for, but in a hero a logo that disappears every 2.6s competes with the
   headline. This keeps the brand's easing and its stagger, runs the entrance
   once, and holds. Original entrance keyframes, on a 2600ms clock:
     say    0ms -> 0, 312ms -> 1.06, 468ms -> 1
     reply  572ms -> 0, 884ms -> 1.06, 1040ms -> 1
   Rescaled below to a 1040ms run, so every shape still turns at the same
   instant it does in the brand file. ---- */
.bz-mark-anim {
  width: var(--bz-mark-size, 56px);
  height: auto;
  display: block;
  overflow: visible;
}
.bz-mark-anim__say,
.bz-mark-anim__reply {
  transform-box: fill-box;
  transform-origin: 0 100%;
  animation-duration: 1040ms;
  animation-timing-function: cubic-bezier(.3, 1.35, .5, 1);
  animation-fill-mode: both;
}
.bz-mark-anim__say { animation-name: bz-mark-say; }
.bz-mark-anim__reply { animation-name: bz-mark-reply; }

@keyframes bz-mark-say {
  0% { transform: scale(0); }
  30% { transform: scale(1.06); }
  45%, 100% { transform: scale(1); }
}
@keyframes bz-mark-reply {
  0%, 55% { transform: scale(0); }
  85% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

/* Reduced motion gets the finished mark, not a missing one: fill-mode both
   would otherwise leave it held at the 0% frame, scaled to nothing. */
@media (prefers-reduced-motion: reduce) {
  .bz-mark-anim__say,
  .bz-mark-anim__reply { animation: none; transform: scale(1); }
}

/* ---- Hero ---- */
.mk-hero { padding: var(--space-3xl) 0 var(--space-4xl); }
.mk-hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2xl);
  align-items: center;
}
.mk-hero-copy { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-lg); }
.mk-hero-copy .t-display-xxl { color: var(--color-ink); }
.mk-hero-lead { margin: 0; color: var(--text-secondary); max-width: 480px; text-wrap: pretty; }
.mk-hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-md); }
.mk-hero-note { font-size: 13px; color: var(--text-muted); }

.mk-hero-visual { position: relative; min-height: 420px; display: none; }


.mk-hero-blob {
  position: absolute;
  inset: 0 40px 36px 0;
  background: var(--surface-sand);
  border-radius: var(--radius-bubble-lg);
}

.mk-mock-card {
  position: absolute;
  top: 0;
  left: 0;
  width: min(360px, 88%);
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-2);
  overflow: hidden;
}
.mk-mock-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-hairline);
  font-weight: var(--weight-medium);
  font-size: 14px;
}
.mk-mock-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px;
  border-bottom: 1px solid var(--border-hairline);
  font-size: 13px;
}
.mk-mock-row:last-child { border-bottom: none; }
.mk-mock-row__name { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.mk-mock-row__name span:first-child { color: var(--text-body); }
.mk-mock-row__name span:last-child { font-size: 11px; color: var(--text-muted); }

.mk-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-bubble-avatar);
  background: var(--surface-coral-tint);
  color: var(--text-link);
  font-size: 12px;
  font-weight: var(--weight-semibold);
}

.mk-name-badge {
  position: absolute;
  right: 0;
  top: 46%;
  width: 196px;
  background: var(--surface-card);
  border-radius: var(--radius-bubble-md);
  box-shadow: var(--shadow-3);
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.mk-name-badge__name { font-family: var(--font-display); font-weight: var(--weight-display); font-size: 15px; }
.mk-name-badge__meta { font-size: 11px; color: var(--text-muted); }
.mk-name-badge__role {
  align-self: flex-start;
  margin-top: 6px;
  padding: 3px 10px;
  border-radius: var(--radius-bubble-pill);
  background: var(--surface-coral-tint);
  color: var(--text-link);
  font-size: 11px;
  font-weight: var(--weight-medium);
}

.mk-toast {
  position: absolute;
  left: 24px;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface-card);
  border-radius: var(--radius-bubble-md);
  box-shadow: var(--shadow-3);
  padding: 12px 16px;
  max-width: 240px;
}
.mk-toast__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--status-success-bg);
  color: var(--status-success);
  flex-shrink: 0;
}
.mk-toast__title { font-size: 13px; font-weight: var(--weight-medium); color: var(--color-ink); }
.mk-toast__body { font-size: 11px; color: var(--text-muted); }

/* ---- Feature showcases (alternating) ---- */
.mk-feature {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
  align-items: center;
}
.mk-feature + .mk-feature { margin-top: var(--space-4xl); }
.mk-feature-copy { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-base); }
.mk-feature-copy p { margin: 0; color: var(--text-secondary); max-width: 440px; text-wrap: pretty; }
/* The showcases alternate coral and bahari rather than running four coral
   sections in a row. The brand has a teal family that nothing on the
   marketing site was using, and four identical panels on white was the
   thing that made this stretch of the page read as plain. */
.mk-feature-visual {
  min-width: 0;
  overflow-wrap: anywhere;
  background: var(--surface-coral-tint);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-bubble-lg);
  padding: var(--space-xl);
  min-height: 260px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.mk-feature--flip .mk-feature-visual {
  background: var(--surface-bahari-tint);
}
.mk-feature--flip .mk-feature-copy .t-eyebrow {
  color: var(--color-bahari-deep);
}

/* The cards floating inside a tinted panel need to stay white, or they
   disappear into it. */
.mk-feature-visual .mk-csv,
.mk-feature-visual .mk-email-list,
.mk-feature-visual .mk-consent-card {
  background: var(--surface-card);
  border-radius: var(--radius-bubble-md);
  padding: var(--space-base);
}
.mk-feature--flip .mk-feature-visual { order: -1; }

/* CSV import demo */
.mk-csv { width: 100%; max-width: 360px; display: flex; flex-direction: column; gap: 12px; }
.mk-csv__head { display: flex; align-items: center; gap: 10px; font-size: 13px; font-weight: var(--weight-medium); }
.mk-csv__bar { height: 6px; border-radius: var(--radius-pill); background: var(--border-hairline); overflow: hidden; }
.mk-csv__bar span { display: block; height: 100%; width: 98%; background: var(--status-success); border-radius: var(--radius-pill); }
.mk-csv__stat { font-size: 12px; color: var(--text-muted); }
.mk-csv__errors { display: flex; flex-direction: column; gap: 6px; }
.mk-csv__error {
  display: flex;
  gap: 8px;
  font-size: 12px;
  color: var(--status-danger);
  background: var(--status-danger-bg);
  border-radius: var(--radius-bubble-sm);
  padding: 8px 12px;
}

/* Consent RTL demo */
.mk-consent-card {
  background: var(--surface-soft);
  border-radius: var(--radius-bubble-md);
  padding: 22px;
  max-width: 320px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.mk-consent-card strong { font-family: var(--font-arabic); font-weight: 700; font-size: 20px; }
.mk-consent-card span { font-size: 14px; color: var(--text-secondary); }

/* Email template rows */
.mk-email-list { width: 100%; max-width: 380px; display: flex; flex-direction: column; gap: 8px; }
.mk-email-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 16px;
  background: var(--surface-soft);
  border-radius: var(--radius-bubble-sm);
}
.mk-email-row__name { font-size: 13px; font-weight: var(--weight-medium); color: var(--color-ink); }
.mk-email-row__trigger { font-size: 11px; color: var(--text-muted); }

/* Badges & check-in demo */
.mk-badge-demo { display: flex; align-items: center; gap: 18px; }
.mk-badge-card {
  width: 140px;
  background: var(--surface-dark);
  color: #fff;
  border-radius: var(--radius-bubble-md);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-shadow: var(--shadow-2);
}
.mk-badge-card__name { font-family: var(--font-display); font-weight: var(--weight-display); font-size: 14px; }
.mk-badge-card__org { font-size: 10px; color: var(--text-on-dark-muted); }
.mk-badge-card__qr {
  margin-top: 10px;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  background: rgba(255,255,255,.14);
}
.mk-doc-list { display: flex; flex-direction: column; gap: 8px; }
.mk-doc-row { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-secondary); }

/* ---- "One platform instead of six" --------------------------------------
   The strikethrough is the argument, not decoration: each card names a tool
   the organizer is using right now and crosses it out. A list of features
   with nothing crossed out is the generic claim every competitor already
   makes, which is exactly what this section exists to avoid.

   The cards are numbered because they are a sequence - the order an
   organizer meets these six tools - and because the count is the claim the
   heading makes. */
.mk-replaces-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  max-width: 560px;
  margin-bottom: var(--space-2xl);
}
.mk-replaces-head p { margin: 0; color: var(--text-secondary); text-wrap: pretty; }

.mk-replaces-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-base);
}
.mk-replaces-card {
  display: grid;
  grid-template-columns: 112px minmax(0, 1fr);
  align-items: center;
  gap: var(--space-base);
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-bubble-lg);
  padding: var(--space-base);
}
.mk-replaces-scene {
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-bubble-md);
  background: var(--surface-coral-tint);
}
.mk-replaces-card:nth-child(even) .mk-replaces-scene { background: var(--surface-bahari-tint); }
.bz-scene { width: 100%; height: auto; display: block; }
.mk-replaces-copy { margin: 0; min-width: 0; color: var(--text-secondary); text-wrap: pretty; }

@media (max-width: 480px) {
  .mk-replaces-card { grid-template-columns: minmax(0, 1fr); }
  .mk-replaces-scene { max-width: 180px; }
}

.mk-replaces-card p {
  margin: 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-secondary);
  text-wrap: pretty;
}

/* ---- Closing CTA panel ---- */
.mk-closing-panel {
  background: var(--surface-dark);
  color: #fff;
  border-radius: var(--radius-bubble-lg);
  padding: var(--space-xl) var(--space-xl);
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}
.mk-closing-panel > div:first-child { display: flex; flex-direction: column; gap: var(--space-sm); }
.mk-closing-panel h2 { color: #fff; }
.mk-closing-panel p { margin: 0; color: var(--text-on-dark-muted); max-width: 440px; }

/* ---- Footer ---- */
.mk-footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
}
.mk-footer-brand { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-base); }
.mk-footer-brand img { width: auto; max-width: 160px; }
.mk-footer-brand p { margin: 0; font-size: 13px; color: var(--text-muted); max-width: 260px; }
.mk-footer-col h3 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-muted);
  font-weight: var(--weight-medium);
  margin: 0 0 var(--space-md);
}
.mk-footer-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-sm); }
.mk-footer-col a { color: var(--text-secondary); font-size: 14px; }
.mk-footer-col a:hover { color: var(--text-link); text-decoration: none; }
.mk-footer-col span { color: var(--text-muted); font-size: 14px; }
.mk-footer-bottom {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  align-items: flex-start;
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--border-hairline);
  font-size: 13px;
  color: var(--text-muted);
}

@media (min-width: 720px) {
  .mk-feature { grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: var(--space-2xl); }
  .mk-replaces-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .mk-footer-grid { grid-template-columns: 1.6fr 1fr 1fr 1fr 1fr; gap: var(--space-xl); }
  .mk-footer-bottom { flex-direction: row; align-items: center; justify-content: space-between; }
}

/* Terms and privacy, inline beside the copyright rather than under a
   heading of their own. Two links did not need a column. */
.mk-footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-base);
}

.mk-footer-legal a {
  color: var(--text-muted);
  text-decoration: none;
}

.mk-footer-legal a:hover { color: var(--text-link); }

/* ---- Everything else, by phase -------------------------------------------
   Fifteen capabilities grouped into three, because fifteen of anything reads
   as a wall and three reads as a choice. An organiser already thinks in
   before / on the day / afterwards, so the grouping is the product's own
   shape rather than a device laid over it.

   Radio inputs drive it, not script. The panels switch through `:checked ~`,
   so it works with JavaScript blocked, which is how a fair share of corporate
   networks see this page, and the radios are real tab stops so arrow keys
   move between them.
   -------------------------------------------------------------------------- */
.mk-phases { margin-top: var(--space-xl); }

/* Off-screen rather than display:none, which would take them out of the tab
   order and strand the whole control for a keyboard. */
.mk-phases__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.mk-phases__tab {
  display: inline-flex;
  align-items: center;
  margin: 0 8px 16px 0;
  padding: 8px 18px;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-bubble-pill);
  background: var(--surface-card);
  color: var(--text-muted);
  font-size: 14px;
  font-weight: var(--weight-medium);
  cursor: pointer;
  user-select: none;
}

.mk-phases__tab:hover { color: var(--text-body); }

#mk-phase-before:checked ~ .mk-phases__tab[for="mk-phase-before"],
#mk-phase-during:checked ~ .mk-phases__tab[for="mk-phase-during"],
#mk-phase-after:checked  ~ .mk-phases__tab[for="mk-phase-after"] {
  background: var(--color-coral);
  border-color: var(--color-coral);
  color: var(--text-on-coral);
}

/* The focus ring belongs on the label, since the input it describes is the
   thing off-screen. */
#mk-phase-before:focus-visible ~ .mk-phases__tab[for="mk-phase-before"],
#mk-phase-during:focus-visible ~ .mk-phases__tab[for="mk-phase-during"],
#mk-phase-after:focus-visible  ~ .mk-phases__tab[for="mk-phase-after"] {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.mk-phases__panel { display: none; }

#mk-phase-before:checked ~ .mk-phases__panel[data-phase="before"],
#mk-phase-during:checked ~ .mk-phases__panel[data-phase="during"],
#mk-phase-after:checked  ~ .mk-phases__panel[data-phase="after"] {
  display: block;
}

.mk-phases__panel ul {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-base);
  margin: 0;
  padding: 0;
  list-style: none;
}

.mk-phases__panel li {
  padding: 18px 20px;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-card);
  background: var(--surface-card);
}

.mk-phases__panel h3 {
  margin: 0 0 4px;
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  font-size: 16px;
  color: var(--text-body);
}

.mk-phases__panel p {
  margin: 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-muted);
}

@media (min-width: 640px) {
  .mk-phases__panel ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 960px) {
  .mk-phases__panel ul { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}


@media (min-width: 960px) {
  .mk-hero-grid { grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: var(--space-3xl); }
  .mk-hero-visual { display: block; }
  .mk-replaces-grid { grid-template-columns: repeat(3, minmax(0,1fr)); }
}

/* ---- Package chooser (public lead form) ---------------------------------
   Radio cards. The input stays in the DOM and focusable - hiding it with
   display:none would take the whole group out of the tab order and off
   screen readers - so it is clipped instead, and the visible card reacts to
   :checked and :focus-visible on its sibling. */
.mk-package-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
}

.mk-package-card { display: block; cursor: pointer; }

/* On the pricing page a card is a link rather than a radio: choosing one
   there is choosing to start, not filling in a field. It needs the hover and
   focus states the radio variant gets from :checked. */
.mk-package-card--link { text-decoration: none; color: inherit; }
.mk-package-card--link:hover .mk-package-card__inner,
.mk-package-card--link:focus-visible .mk-package-card__inner {
  border-color: var(--color-coral);
  transform: translateY(-2px);
}
.mk-package-card--link .mk-package-card__inner { transition: border-color .15s ease, transform .15s ease; }

/* The deciding number. Someone scanning this page is matching their expected
   delegate count against these, so it reads before the price does. */
.mk-package-card__cap {
  display: block;
  font-size: 13px;
  font-weight: var(--weight-medium);
  color: var(--color-coral-press);
}

/* The call to action sits at the foot of every card, on the same line
   whatever the blurb above it does, so the row reads as a row. */
.mk-package-card__cta {
  margin-top: auto;
  justify-content: center;
  width: 100%;
  pointer-events: none;
}


.mk-package-card input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.mk-package-card__inner {
  display: flex;
  flex-direction: column;
  gap: 8px;
  height: 100%;
  padding: 16px;
  border: 1.5px solid var(--color-sand-200);
  border-radius: var(--radius-lg);
  background: var(--color-white);
  transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}

.mk-package-card:hover .mk-package-card__inner {
  border-color: var(--color-coral);
}

.mk-package-card input:focus-visible + .mk-package-card__inner {
  outline: 2px solid var(--color-coral);
  outline-offset: 2px;
}

/* Selected state carries a border AND a tint, so it does not rest on colour
   alone for anyone who cannot distinguish it. */
.mk-package-card input:checked + .mk-package-card__inner {
  border-color: var(--color-coral);
  box-shadow: inset 0 0 0 1px var(--color-coral);
  background: var(--color-sand-50);
}

.mk-package-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.mk-package-card__name { font-weight: 700; font-size: 15px; }

.mk-package-card__tag {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--color-coral);
  color: var(--color-white);
}

.mk-package-card__price {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: 20px;
  line-height: 1.1;
}

.mk-package-card__blurb { font-size: 12.5px; color: var(--text-muted); }

.mk-package-card__list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--text-body);
}

.mk-package-card__list > span { position: relative; padding-inline-start: 16px; }

.mk-package-card__list > span::before {
  content: "✓";
  position: absolute;
  inset-inline-start: 0;
  color: var(--color-coral);
  font-weight: 700;
}

.mk-package-card__tax {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: -4px;
}

/* ---- Public event listing cards ---------------------------------------- */
.mk-event-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 20px;
}

.mk-event-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--color-sand-200);
  border-radius: var(--radius-lg);
  background: var(--color-white);
  transition: border-color 140ms ease, transform 140ms ease, box-shadow 140ms ease;
}

.mk-event-card:hover {
  border-color: var(--color-coral);
  transform: translateY(-2px);
  box-shadow: 0 10px 24px -14px rgb(0 0 0 / 0.35);
}

@media (prefers-reduced-motion: reduce) {
  .mk-event-card { transition: none; }
  .mk-event-card:hover { transform: none; }
}

/* Fixed ratio so a wall of cards lines up regardless of what each client
   uploaded - portrait, square or panoramic all crop to the same band. */
.mk-event-card__media {
  display: block;
  aspect-ratio: 16 / 9;
  background: var(--color-sand-50);
  overflow: hidden;
}

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

.mk-event-card__fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: 38px;
  letter-spacing: 0.02em;
  color: hsl(var(--tile-hue, 12) 45% 32%);
  background: linear-gradient(135deg,
    hsl(var(--tile-hue, 12) 58% 93%),
    hsl(calc(var(--tile-hue, 12) + 24) 52% 86%));
}

.mk-event-card__body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 16px;
}

.mk-event-card__date {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-coral);
}

.mk-event-card__title { font-size: 17px; line-height: 1.3; margin: 0; font-weight: 700; }
.mk-event-card__title a { color: inherit; text-decoration: none; }
.mk-event-card__title a:hover { text-decoration: underline; }

.mk-event-card__org { font-size: 13px; color: var(--text-muted); }
.mk-event-card__venue { font-size: 13px; color: var(--text-body); }

.mk-event-card__tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }

/* =========================================================================
   Phone field: a country select beside the number.

   Declared here rather than as w-[42%] in the template, because styles.css is
   prebuilt and has no rule for an arbitrary value - the class would have been
   in the markup and done nothing. Narrow enough that the number still has
   room on a phone, wide enough that "United Arab Emirates (+971)" is legible.
   ========================================================================= */
.bz-phone-country {
  width: 42%;
  max-width: 230px;
  min-width: 120px;
}

@media (max-width: 480px) {
  /* Under a certain width the two will not sit side by side legibly, so they
     stop trying. */
  .bz-phone-country { width: 100%; max-width: none; }
  .bz-phone-field { flex-direction: column; }
}

/* =========================================================================
   Developer documentation.

   Code blocks and reference tables, which nothing else on the marketing site
   needed until now. Written here rather than as utility classes because the
   stylesheet is prebuilt: arbitrary values compile to nothing, and a code
   block is mostly things Tailwind has no utility for anyway.
   ========================================================================= */

/* Sized explicitly. The marketing reset strips heading sizes so that each
   page sets its own, which meant every h2 here came out at body size and the
   page read as one undifferentiated wall. */
.mk-api h2 {
  margin-top: var(--space-2xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--border-hairline);
  font-family: var(--font-display);
  font-size: var(--type-heading-lg);
  font-weight: var(--weight-display);
  line-height: 1.3;
  scroll-margin-top: 90px;
}

.mk-api h3 {
  margin-top: var(--space-xl);
  font-family: var(--font-display);
  font-size: var(--type-heading-md);
  font-weight: var(--weight-semibold);
}

/* Markers restored, for the same reason: the reset removes them globally and
   a numbered list with no numbers is three sentences in a box. */
.mk-api-steps {
  margin: var(--space-base) 0;
  padding-inline-start: var(--space-xl);
  list-style-type: decimal;
}

.mk-api ul {
  margin: var(--space-base) 0;
  padding-inline-start: var(--space-xl);
  list-style-type: disc;
}

.mk-api ul li { margin-bottom: var(--space-sm); }

.mk-api-steps li { margin-bottom: var(--space-sm); }

/* A line that the reader must not skim past: a secret shown once, a scope
   that returns passport numbers. */
.mk-api-note {
  border-left: 3px solid var(--color-coral);
  background: var(--color-coral-tint);
  padding: var(--space-md) var(--space-base);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: var(--type-body-sm);
  color: var(--color-ink-2);
}

/* ---- Code ---- */

.mk-code {
  margin: var(--space-base) 0 var(--space-lg);
  border: 1px solid var(--color-usiku-line);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-usiku);
}

.mk-code__head {
  padding: var(--space-sm) var(--space-base);
  border-bottom: 1px solid var(--color-usiku-line);
  font-size: var(--type-eyebrow);
  font-weight: var(--weight-semibold);
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--text-on-dark-muted);
}

.mk-code pre {
  margin: 0;
  padding: var(--space-base);
  /* The one place on the site that scrolls sideways on purpose: wrapping a
     curl command or a JSON body makes it unreadable and uncopyable. */
  overflow-x: auto;
}

.mk-code code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.7;
  color: #E8EAF2;
  white-space: pre;
}

.mk-api :not(pre) > code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .9em;
  padding: 2px 6px;
  border-radius: var(--radius-xs);
  background: var(--color-sand-100);
  color: var(--color-coral-press);
  white-space: nowrap;
}

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

.mk-api-table-wrap {
  margin: var(--space-base) 0 var(--space-lg);
  overflow-x: auto;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
}

.mk-api-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--type-body-sm);
}

.mk-api-table th,
.mk-api-table td {
  padding: var(--space-md) var(--space-base);
  text-align: start;
  border-bottom: 1px solid var(--border-hairline);
  vertical-align: top;
}

.mk-api-table thead th {
  background: var(--color-sand-50);
  font-weight: var(--weight-semibold);
  white-space: nowrap;
}

.mk-api-table tbody tr:last-child td { border-bottom: 0; }

.mk-api-table tr.is-sensitive td { background: var(--color-coral-tint); }

.mk-api-flag {
  display: inline-block;
  margin-inline-start: var(--space-sm);
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  background: var(--color-coral-press);
  color: #fff;
  font-size: 11px;
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: .5px;
}

.mk-api-flag--quiet {
  background: transparent;
  color: var(--color-ink-3);
  border: 1px solid var(--border-input);
}

/* ---- Endpoints ---- */

.mk-endpoint {
  margin: var(--space-base) 0;
  padding: var(--space-base);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  background: var(--color-sand-50);
}

.mk-endpoint__line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}

.mk-endpoint__method {
  padding: 2px 10px;
  border-radius: var(--radius-xs);
  background: var(--color-bahari-deep);
  color: #fff;
  font-size: 11px;
  font-weight: var(--weight-display);
  letter-spacing: .5px;
}

/* The class sits on the <code> itself, not on a parent. The first draft
   selected .mk-endpoint__path code, which matches a code inside it and so
   matched nothing at all - the paths kept the inline-code coral and read as
   links.

   Scoped under .mk-api so it outranks the inline-code rule above: two
   classes and an element beats one class and two elements. Dropping the
   !important without raising the specificity put the coral straight back. */
.mk-api code.mk-endpoint__path {
  background: transparent;
  color: var(--color-ink);
  padding: 0;
  font-size: 14px;
  font-weight: var(--weight-medium);
}

/* Pushed to the end of the line so the eye can run down the paths without
   the scope names breaking the column. */
.mk-endpoint__scope { margin-inline-start: auto; }

.mk-endpoint p { margin: 0; font-size: var(--type-body-sm); color: var(--color-ink-2); }

.mk-api-params { margin-top: var(--space-sm) !important; }

@media (max-width: 640px) {
  /* The scope no longer fits on the same line as the path. */
  .mk-endpoint__scope { margin-inline-start: 0; }
}

/* =========================================================================
   The split, shown beside a ticket price.

   An organiser setting a number needs to see what reaches their bank, not
   what the buyer is charged. Declared here because styles.css is prebuilt and
   would compile none of this from utility classes.
   ========================================================================= */

.bz-split {
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  background: var(--color-sand-50);
  padding: var(--space-base);
}

.bz-split__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-base);
  padding: var(--space-xs) 0;
  font-size: var(--type-body-sm);
  color: var(--color-ink-2);
}

.bz-split__row strong {
  /* The figures line up in a column, so they need equal-width digits. */
  font-variant-numeric: tabular-nums;
  color: var(--color-ink);
}

.bz-split__row--total {
  margin-top: var(--space-sm);
  padding-top: var(--space-md);
  border-top: 1px solid var(--border-hairline);
  font-size: var(--type-body);
}

.bz-split__row--total strong { color: var(--color-bahari-deep); font-weight: var(--weight-display); }

.bz-split__note {
  margin: var(--space-sm) 0 0;
  font-size: var(--type-caption);
  color: var(--color-ink-4);
}

/* =========================================================================
   A row of three form fields.

   Declared here rather than as grid-cols-1 lg:grid-cols-3, because
   styles.css is prebuilt: it carries only the utility classes the original
   Metronic build happened to use, and which of the responsive variants
   survived is not something to guess at from the markup. This is the third
   time this session that a plausible-looking Tailwind class turned out to
   compile to nothing here.
   ========================================================================= */
.bz-field-row-3 {
  display: grid;
  gap: var(--space-base);
  grid-template-columns: 1fr;
}

@media (min-width: 768px) {
  .bz-field-row-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* =========================================================================
   The public registration form.

   Used both on the hosted page and inside an iframe on somebody else's site,
   so everything here is self-contained and assumes no host styles.
   ========================================================================= */

.bz-reg { padding: var(--space-2xl) var(--space-base); }
.bz-reg--embedded { padding: var(--space-base); }
/* The same form inside the event page's Register tab. The page above it has
   already introduced the event and named the organiser, so this drops the
   standalone page's generous top padding and keeps only breathing room. */
.bz-reg--inline { padding: var(--space-base) 0; }

.bz-reg__inner {
  max-width: 560px;
  margin-inline: auto;
}

.bz-reg__org {
  display: block;
  font-size: var(--type-eyebrow);
  font-weight: var(--weight-semibold);
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--color-coral-text);
}

.bz-reg__head h1 { margin: var(--space-sm) 0 0; }
.bz-reg__intro { color: var(--color-ink-2); margin-top: var(--space-sm); }

.bz-reg__form { display: grid; gap: var(--space-base); margin-top: var(--space-lg); }

.bz-reg__field { display: grid; gap: 6px; }
.bz-reg__field > label,
.bz-reg__field > legend {
  font-size: var(--type-body-sm);
  font-weight: var(--weight-medium);
  color: var(--color-ink);
}

/* Text inputs and selects only. The first version of this caught the ticket
   radios too, because a fieldset is a .bz-reg__field and the radios live
   inside it - so each one rendered as a 100%-wide, 48px-tall control and
   crushed the ticket beside it into a column three words wide. */
.bz-reg__field > input,
.bz-reg__field > select,
.bz-reg__phone input,
.bz-reg__phone select {
  width: 100%;
  min-height: 48px;
  padding: 0 12px;
  border: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background: #fff;
  color: var(--color-ink);
  /* 16 and no smaller: below that, focusing a field zooms the page on iOS
     and never zooms back. An embedded form is read on a phone more often
     than the hosted one. */
  font-size: 16px;
  font-family: inherit;
}

.bz-reg__field input:focus,
.bz-reg__field select:focus {
  outline: none;
  border-color: var(--color-coral);
  box-shadow: var(--focus-ring);
}

/* A title is two or three characters. A full-width select for it looks
   like a mistake next to the name fields it belongs with. */
.bz-reg__salutation > select { max-width: 180px; }

.bz-reg__pair { display: grid; gap: var(--space-base); grid-template-columns: 1fr; }

@media (min-width: 560px) {
  .bz-reg__pair { grid-template-columns: 1fr 1fr; }
}

.bz-reg__phone { display: flex; gap: var(--space-sm); }
.bz-reg__phone select { width: 45%; flex: none; }
.bz-reg__phone input { flex: 1; }

.bz-reg__hint { font-size: var(--type-caption); color: var(--color-ink-4); }

/* Tickets, as radio cards rather than a select: a price somebody is about to
   pay should be read, not scrolled past in a dropdown. */
.bz-reg__ticket input[type="radio"] {
  width: 18px;
  height: 18px;
  min-height: 0;
  flex: none;
  accent-color: var(--color-coral);
}

.bz-reg__ticket {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md);
  margin-top: var(--space-sm);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.bz-reg__ticket:has(input:checked) {
  border-color: var(--color-coral);
  background: var(--color-coral-tint);
}

.bz-reg__ticket-body { flex: 1; display: grid; gap: 2px; }
.bz-reg__ticket-body span { font-size: var(--type-body-sm); color: var(--color-ink-3); }
.bz-reg__ticket-note {
  color: var(--color-coral-text);
  font-weight: var(--weight-semibold);
}

.bz-reg__ticket-price { font-weight: var(--weight-display); font-variant-numeric: tabular-nums; }

.bz-reg__submit {
  min-height: 48px;
  padding: 0 var(--space-lg);
  border: 0;
  border-radius: var(--radius-button);
  background: var(--cta-bg);
  color: var(--cta-fg);
  font-family: inherit;
  font-size: var(--type-heading-sm);
  font-weight: var(--weight-semibold);
  cursor: pointer;
}

.bz-reg__submit:hover { background: var(--cta-bg-hover); color: var(--cta-fg-hover); }

.bz-reg__errors {
  border-left: 3px solid var(--color-danger);
  background: var(--color-danger-tint);
  padding: var(--space-md) var(--space-base);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: var(--type-body-sm);
}

.bz-reg__errors p { margin: 0 0 4px; }

/* The fine print and a consent notice are the same kind of sentence doing
   the same job, so they are set the same way: same size, same colour, same
   measure, both flush with the form. Previously the notice sat indented
   inside its label while the line below it did not, and two sentences about
   what happens to your details read as unrelated. */
.bz-reg__fine,
.bz-reg__notice,
.bz-reg__poweredby {
  font-size: var(--type-caption);
  line-height: 1.55;
  color: var(--color-ink-4);
}

.bz-reg__fine,
.bz-reg__notice {
  margin: 0;
  max-width: 62ch;
}
.bz-reg__poweredby { text-align: center; margin-top: var(--space-base); }

.bz-reg__closed {
  padding: var(--space-lg);
  border: 1px dashed var(--border-input);
  border-radius: var(--radius-md);
  text-align: center;
  color: var(--color-ink-3);
}

/* The honeypots. Off-screen rather than display:none, because some bots skip
   anything explicitly hidden and fill everything else. */
.bz-reg__trap {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.bz-reg__done { text-align: center; }

.bz-reg__tick {
  width: 56px;
  height: 56px;
  margin: 0 auto var(--space-base);
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--color-success-tint);
  color: var(--color-success);
  font-size: 28px;
}

.bz-reg__done-event {
  margin-top: var(--space-base);
  font-weight: var(--weight-semibold);
  color: var(--color-ink-2);
}

.bz-reg__done-event span {
  display: block;
  margin-top: 2px;
  font-weight: var(--weight-regular);
  font-size: var(--type-body-sm);
  color: var(--color-ink-4);
}

/* A request waiting on a human is not a success, and a green tick would
   say it was. */
.bz-reg__tick--waiting {
  background: var(--color-coral-tint, #FDEBE6);
  color: var(--color-coral-text);
}

.bz-reg__receipt {
  margin-top: var(--space-base);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--type-body-sm);
  color: var(--color-ink-3);
}


/* Event branding on the public registration pages.
   Real rules rather than utility classes: styles.css here is prebuilt, so
   arbitrary values like max-h-[180px] compile to nothing. */

.bz-reg__brand {
  display: grid;
  justify-items: center;
  gap: var(--space-base);
  margin-bottom: var(--space-lg);
}

.bz-reg__brand-banner {
  display: block;
  width: 100%;
  height: auto;
  /* Capped rather than fixed, so a tall poster-shaped banner does not push
     the form itself below the fold on a phone. */
  max-height: 180px;
  object-fit: cover;
  border-radius: var(--radius-card);
}

.bz-reg__brand-logo {
  display: block;
  height: 44px;
  width: auto;
  max-width: 200px;
  object-fit: contain;
}

/* Inside somebody else's page the banner competes with their own header,
   so it gets out of the way and the logo carries the identity. */
.bz-reg--embedded .bz-reg__brand-banner { max-height: 110px; }
.bz-reg--embedded .bz-reg__brand-logo { height: 32px; }

@media (max-width: 640px) {
  .bz-reg__brand-banner { max-height: 120px; }
  .bz-reg__brand-logo { height: 36px; }
}

body.bz-reg-embed { margin: 0; background: transparent; }

/* ── API keys ─────────────────────────────────────────────────────
   A secret shown once has to be readable and selectable in one go:
   it is 48 characters with no word breaks, so it needs an explicit
   wrap rule or it runs off the side of its card on a laptop.
   font-mono and break-all are not in the prebuilt Tailwind build,
   which is why these are real rules rather than utility classes. */

.bz-secret { border-color: var(--color-coral); }

.bz-secret__warning {
  display: flex;
  gap: var(--space-sm);
  align-items: flex-start;
  background: var(--color-coral-tint);
  color: var(--color-coral-press);
  border-radius: var(--radius-sm);
  padding: var(--space-md) var(--space-base);
  font-size: var(--type-body-sm);
}

.bz-secret__value {
  display: block;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--type-body-sm);
  background: var(--color-sand-100);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-sm);
  padding: var(--space-md) var(--space-base);
  overflow-wrap: anywhere;
  word-break: break-all;
  user-select: all;
}

.bz-scope {
  display: flex;
  gap: var(--space-md);
  align-items: flex-start;
  padding: var(--space-md);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.bz-scope:hover { background: var(--color-sand-50); }

.bz-scope__text { display: flex; flex-direction: column; gap: 2px; }
.bz-scope__label { font-size: var(--type-body-sm); color: var(--text-body); }

.bz-scope__name {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--type-caption);
  color: var(--text-muted);
  background: var(--color-sand-100);
  border-radius: var(--radius-xs);
  padding: 1px 6px;
  align-self: flex-start;
  margin-inline-end: var(--space-xs);
}

.bz-scope__warning {
  font-size: var(--type-caption);
  color: var(--status-danger);
  margin-top: var(--space-xs);
}

/* ── Registration form: required marks, busy state, inline errors ──
   The form renders on our own page and inside a shadow root on somebody
   else's site, so everything here has to work in both. No :has(), no
   sibling selectors reaching outside the field. */

.bz-req {
  color: var(--color-coral-text);
  font-weight: var(--weight-semibold);
  margin-inline-start: 2px;
}

/* Conditional ones are quieter: they are true only once something else is
   answered, and a row of identical asterisks where half of them are "it
   depends" teaches the reader to ignore all of them. */
.bz-req--conditional { opacity: .45; }

.bz-reg__legend {
  margin: 0;
  font-size: var(--type-caption);
  color: var(--text-subtle);
}

/* Title, first name, last name on one line. Title is a short select and
   should not claim a third of the row, so it is given its own narrow
   track. Collapses to a single column on a phone, like the pair does. */
.bz-reg__trio {
  display: grid;
  gap: var(--space-base);
  grid-template-columns: 1fr;
}

@media (min-width: 560px) {
  .bz-reg__trio { grid-template-columns: minmax(0, 7.5rem) minmax(0, 1fr) minmax(0, 1fr); }
}

/* The standalone rule that used to cap this select is wrong inside the
   row: the track decides the width now. */
.bz-reg__trio .bz-reg__salutation > select { max-width: none; }

/* ── The button while it is working ──
   Named states rather than only a spinner: a disabled button with no
   wording reads as broken, and this one can sit there for a second or two
   while a payment session is opened. */
.bz-reg__submit[aria-busy="true"],
.bz-reg__submit:disabled {
  opacity: .72;
  cursor: progress;
}

.bz-reg__submit:disabled { pointer-events: none; }

.bz-reg__spinner {
  display: inline-block;
  width: 1em;
  height: 1em;
  margin-inline-end: .5em;
  vertical-align: -.125em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: bz-spin .6s linear infinite;
}

@keyframes bz-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .bz-reg__spinner { animation: none; opacity: .6; }
}

/* ── Inline validation ──
   Said under the field it belongs to. The browser's own bubble points at
   one field at a time and vanishes on the next click, which is no use on a
   form where three things are missing. */
.bz-reg__field input[aria-invalid="true"],
.bz-reg__field select[aria-invalid="true"] {
  border-color: var(--status-danger);
}

.bz-reg__error {
  font-size: var(--type-caption);
  color: var(--status-danger);
}

.bz-reg__error:empty { display: none; }

/* The confirmation, once it has replaced the form in place. Inherits the
   done styles; this only gives it room and removes the focus ring that a
   tabindex=-1 container would otherwise draw when focused by script. */
.bz-reg__confirmation { display: block; }
.bz-reg__confirmation:focus { outline: none; }
.bz-reg__confirmation .bz-reg__inner { padding: 0; }


/* Recovery codes, laid out to be read aloud or copied in one go. */
.bz-recovery-codes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-sm);
  background: var(--color-sand-50);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-sm);
  padding: var(--space-base);
  user-select: all;
}

.bz-recovery-codes code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--type-body-sm);
  letter-spacing: .04em;
}

/* ── Photo gallery ────────────────────────────────────────────────
   Real rules rather than utilities: aspect-square, object-cover,
   inset-0 and the sm:/lg: grid columns this wants are all absent from
   the prebuilt Tailwind build, so the utility spelling would compile
   to nothing and the grid would stack. */

.bz-gallery {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-md);
}

@media (min-width: 640px) { .bz-gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .bz-gallery { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.bz-gallery__item {
  position: relative;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--color-sand-100);
  border: 1px solid var(--border-hairline);
}

.bz-gallery__item img {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

/* Unpublished ones are visibly held back on the organiser's screen, so
   nobody assumes a grid full of pictures is a grid delegates can see. */
.bz-gallery__item--draft img { opacity: .45; filter: grayscale(.4); }

.bz-gallery__badge {
  position: absolute;
  inset-block-start: var(--space-sm);
  inset-inline-start: var(--space-sm);
  background: var(--color-usiku);
  color: #fff;
  font-size: var(--type-caption);
  border-radius: var(--radius-pill);
  padding: 2px 10px;
}

.bz-gallery__bar {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-sm);
  border-top: 1px solid var(--border-hairline);
  background: var(--surface-card);
}

.bz-gallery__caption {
  flex: 1;
  min-width: 0;
  font-size: var(--type-caption);
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The delegate's view: the whole tile is the download. */
.bz-gallery__link { display: block; }
.bz-gallery__link:focus-visible { outline: 2px solid var(--color-coral); outline-offset: 2px; }

/* ── A long biography, folded ─────────────────────────────────────
   One speaker with four paragraphs used to stretch their card and,
   because the grid rows align, every card beside it. <details> keeps
   the cards even until somebody asks for the rest. */

/* ---- Opening a biography ------------------------------------------------
   The card leaves the grid and becomes a full-width panel: portrait on one
   side, everything known about the person on the other. A modal would read
   better still, but this markup also renders inside a shadow root on the
   organiser's own site where injected script never runs, and one behaviour
   that works everywhere beats a better one that works in two places out of
   three.

   :has() rather than a class toggled by script, for the same reason. */
.bz-speakers:has(.bz-speaker__more[open]) .bz-speaker:has(.bz-speaker__more[open]) {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: flex-start;
  text-align: start;
  gap: 24px;
  padding: 24px;
  border-color: var(--color-coral);
}

/* The identity block becomes the left-hand column, and the portrait in it
   grows to the size somebody actually wants when they asked to see more. */
.bz-speaker:has(.bz-speaker__more[open]) .bz-speaker__head {
  align-items: flex-start;
  text-align: start;
  flex: 0 0 220px;
  max-width: 220px;
}

.bz-speaker:has(.bz-speaker__more[open]) .bz-speaker__avatar {
  width: 180px;
  height: 180px;
  font-size: 56px;
}

.bz-speaker:has(.bz-speaker__more[open]) .bz-speaker__name { font-size: 18px; }
.bz-speaker:has(.bz-speaker__more[open]) .bz-speaker__role,
.bz-speaker:has(.bz-speaker__more[open]) .bz-speaker__org { font-size: 13px; }

.bz-speaker:has(.bz-speaker__more[open]) .bz-speaker__more {
  flex: 1 1 auto;
  min-width: 0;
  margin-top: 0;
}

.bz-speaker:has(.bz-speaker__more[open]) .bz-speaker__bio--full {
  font-size: 14px;
  line-height: 1.65;
  color: var(--text-secondary);
}

/* Narrow screens keep the stacked card: two columns inside 360px is two
   columns of nothing. */
@media (max-width: 640px) {
  .bz-speakers:has(.bz-speaker__more[open]) .bz-speaker:has(.bz-speaker__more[open]) {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 12px;
  }

  .bz-speaker:has(.bz-speaker__more[open]) .bz-speaker__head {
    align-items: center;
    text-align: center;
    flex: none;
    max-width: none;
  }

  .bz-speaker:has(.bz-speaker__more[open]) .bz-speaker__avatar {
    width: 128px;
    height: 128px;
    font-size: 40px;
  }
}

/* The head is a column of its own now, so the card's gap does not also
   space the name away from the portrait. */
.bz-speaker__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.bz-speaker__more { margin-top: 2px; }

/* One cue element, two words. "Read more" while shut, "Show less" while
   open: a disclosure whose cue still says "Read more" after it has opened
   leaves the reader hunting for the way back. */
.bz-speaker__cue {
  display: inline-block;
  margin-top: 4px;
  font-size: var(--type-caption);
  font-weight: var(--weight-medium);
  color: var(--text-link);
}

.bz-speaker__cue--less { display: none; }
.bz-speaker__more[open] .bz-speaker__cue--less { display: inline-block; }

.bz-speaker__more > summary {
  display: block;
  cursor: pointer;
  list-style: none;
}

/* Safari draws its own triangle without this. */
.bz-speaker__more > summary::-webkit-details-marker { display: none; }

.bz-speaker__bio--teaser { display: block; }

.bz-speaker__more[open] .bz-speaker__bio--teaser,
.bz-speaker__more[open] .bz-speaker__cue--more { display: none; }

.bz-speaker__more > summary:focus-visible {
  outline: 2px solid var(--color-coral);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

/* ── Reorderable list ─────────────────────────────────────────────
   Used for the speaker line-up. Rows are real list items so the order
   is announced to a screen reader, and the drag handle is decorative:
   the move buttons are the accessible path. */

.bz-order-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  counter-reset: bz-order;
}

.bz-order-item {
  counter-increment: bz-order;
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-sm);
  background: var(--surface-card);
}

.bz-order-item::before {
  content: counter(bz-order);
  min-width: 1.5rem;
  font-size: var(--type-caption);
  font-variant-numeric: tabular-nums;
  color: var(--text-subtle);
  text-align: end;
}

.bz-order-item.is-dragging { opacity: .5; }

.bz-order-handle { color: var(--text-subtle); cursor: grab; }
.bz-order-item:active .bz-order-handle { cursor: grabbing; }

/* ── Attendee avatar ──────────────────────────────────────────────
   One definition for the reorder screen and the attendee list, which
   had grown their own copies of the same circle. */
.bz-avatar {
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  /* Behind the image, not only behind the initials. A path can outlive its
     file: a portrait deleted from the bucket leaves the row pointing at
     nothing, and without this the circle becomes a hole in the column
     rather than an empty avatar. The box keeps its size either way, so the
     names stay aligned regardless. */
  background: var(--color-sand-100);
}

.bz-avatar--sm { width: 28px; height: 28px; }
.bz-avatar--md { width: 36px; height: 36px; }

.bz-avatar--initial {
  display: grid;
  place-items: center;
  background: var(--color-sand-100);
  color: var(--text-muted);
  font-weight: var(--weight-medium);
  /* Not a photograph, so it must not be mistaken for one at a glance in
     a column of real faces. */
  letter-spacing: 0.01em;
}

.bz-avatar--sm.bz-avatar--initial { font-size: var(--type-caption); }
.bz-avatar--md.bz-avatar--initial { font-size: var(--type-body-sm); }

.bz-order-body { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.bz-order-name { font-size: var(--type-body-sm); font-weight: var(--weight-medium); color: var(--text-body); }
.bz-order-meta { font-size: var(--type-caption); color: var(--text-muted); }
.bz-order-moves { display: flex; gap: 2px; flex: none; }

/* ── Upload progress ──────────────────────────────────────────────
   A batch of camera originals is minutes of transfer, and a blank tab
   for two minutes is indistinguishable from a page that has died. */
.bz-progress {
  height: 6px;
  border-radius: 999px;
  background: var(--color-slate-100, #F1F5F9);
  overflow: hidden;
}

.bz-progress__meter {
  width: 0;
  height: 100%;
  border-radius: 999px;
  background: var(--color-coral, #F26B4A);
  transition: width 120ms linear;
}

.bz-upload-status[data-tone='bad'] { color: var(--color-destructive, #DC2626); }
.bz-upload-status[data-tone='good'] { color: var(--color-emerald-600, #059669); }
.bz-upload-status[data-tone='neutral'] { color: var(--text-secondary, #6B7280); }

/* ── Albums ───────────────────────────────────────────────────────
   Native <details>, so a closed album is still reachable by the
   browser's own find-on-page and works with the script blocked. */
.bz-album {
  border: 1px solid var(--color-border, #E5E7EB);
  border-radius: var(--radius-md, 8px);
  overflow: hidden;
}

.bz-album__summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  padding: 12px 14px;
  cursor: pointer;
  list-style: none;
  background: var(--color-slate-50, #F8FAFC);
}

.bz-album__summary::-webkit-details-marker { display: none; }

/* The twisty, drawn rather than borrowed, so it points the right way
   in Arabic without a separate rule for the flipped direction. */
.bz-album__summary::before {
  content: '';
  width: 0;
  height: 0;
  border-inline-start: 6px solid currentColor;
  border-block: 4px solid transparent;
  transition: transform 150ms ease;
  flex: 0 0 auto;
  opacity: 0.55;
}

.bz-album[open] > .bz-album__summary::before { transform: rotate(90deg); }

/* The closed twisty points along the reading direction, which is handled
   by border-inline-start. The open one has to point down in both, and a
   logical property cannot express "turn the other way", so Arabic needs
   the opposite rotation: turning the mirrored triangle clockwise lands it
   pointing up. */
[dir='rtl'] .bz-album[open] > .bz-album__summary::before { transform: rotate(-90deg); }

.bz-album__name { font-weight: var(--weight-medium, 500); }

/* The edition an album belongs to, shown only on an earlier conference a
   delegate has been let into. A quiet pill rather than part of the name:
   it is the same album title it has always had, filed under a different
   year, and the year is the thing being distinguished. */
.bz-album__edition {
  flex: 0 0 auto;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface-sunken, #F7F4EF);
  color: var(--text-secondary, #6B7280);
  font-size: var(--type-caption, 12px);
  font-weight: var(--weight-medium, 500);
  white-space: nowrap;
}

.bz-album__count,
.bz-album__date {
  font-size: var(--type-caption, 12px);
  color: var(--text-secondary, #6B7280);
}

.bz-album__date { margin-inline-start: auto; }

.bz-album__description {
  padding: 0 14px;
  margin-top: 10px;
  font-size: var(--type-caption, 12px);
  color: var(--text-secondary, #6B7280);
}

.bz-album > .bz-gallery { padding: 14px; }

.bz-album__summary:focus-visible {
  outline: 2px solid var(--color-coral, #F26B4A);
  outline-offset: -2px;
}

/* ── Lightbox ─────────────────────────────────────────────────────
   Opened over the gallery so a delegate can check four hundred
   thumbnails for a picture of themselves without a page load each
   time. Every tile is still an ordinary link to a real file, so none
   of this is required for the gallery to work. */
.bz-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-rows: auto minmax(0, 1fr);
  align-items: center;
  gap: 8px;
  padding: 12px;
  /* Nearly opaque on purpose. At 0.92 the page heading behind the bar
     stayed legible and collided with the counter, which read as two
     interfaces drawn on top of each other rather than one over the other. */
  background: rgba(10, 12, 24, 0.97);
}

.bz-lightbox[hidden] { display: none; }

body.bz-lightbox-open { overflow: hidden; }

.bz-lightbox__bar {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  color: #FFFFFF;
}

.bz-lightbox__counter {
  font-size: var(--type-caption, 12px);
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
  /* "2 / 5" is two numbers either side of a neutral character, and the
     bidi algorithm reorders that whole run in an Arabic page: it rendered
     as "5 / 2", which reads as photograph five of two. Isolated and
     forced to LTR, because this is a fraction rather than prose and its
     order carries the meaning. */
  direction: ltr;
  unicode-bidi: isolate;
}

.bz-lightbox__tools { display: flex; align-items: center; gap: 8px; }

.bz-lightbox__btn {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.08);
  color: #FFFFFF;
  border-radius: var(--radius-sm, 6px);
  padding: 6px 12px;
  font-size: var(--type-caption, 12px);
  cursor: pointer;
  text-decoration: none;
  /* 44px is the smallest target a thumb reliably hits, and this is a
     control people use one-handed while scrolling a gallery. */
  min-height: 36px;
  display: inline-flex;
  align-items: center;
}

.bz-lightbox__btn:hover { background: rgba(255, 255, 255, 0.18); }

.bz-lightbox__stage {
  grid-column: 2;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 0;
  max-height: 100%;
  overflow: auto;
}

.bz-lightbox__stage img {
  max-width: 100%;
  max-height: 78vh;
  object-fit: contain;
  border-radius: var(--radius-sm, 6px);
  cursor: zoom-in;
}

/* Zoomed, the image leaves the box and the stage scrolls, which is how
   somebody checks whether a face in the third row is theirs. */
.bz-lightbox__stage img.is-zoomed {
  max-width: none;
  max-height: none;
  width: auto;
  cursor: zoom-out;
}

.bz-lightbox__caption {
  color: rgba(255, 255, 255, 0.85);
  font-size: var(--type-caption, 12px);
  text-align: center;
}

.bz-lightbox__nav {
  appearance: none;
  border: 0;
  background: rgba(255, 255, 255, 0.08);
  color: #FFFFFF;
  width: 44px;
  height: 64px;
  border-radius: var(--radius-sm, 6px);
  cursor: pointer;
  font-size: 20px;
  line-height: 1;
}

.bz-lightbox__nav:hover { background: rgba(255, 255, 255, 0.18); }
.bz-lightbox__nav[hidden] { display: none; }
.bz-lightbox__nav--prev { grid-column: 1; grid-row: 2; }
.bz-lightbox__nav--next { grid-column: 3; grid-row: 2; }

/* Drawn rather than an icon font, so they flip with the writing
   direction instead of pointing backwards in Arabic. */
.bz-lightbox__nav--prev::before { content: '\2039'; }
.bz-lightbox__nav--next::before { content: '\203A'; }

.bz-lightbox__btn:focus-visible,
.bz-lightbox__nav:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: 2px;
}

/* On a phone the two nav buttons were taking 88px of a 390px screen, plus
   gaps, which left the photograph about half the width it could have had.
   They become overlays at the edges instead: the same targets, in the same
   places, but no longer stealing room from the thing being looked at. */
@media (max-width: 560px) {
  .bz-lightbox { grid-template-columns: minmax(0, 1fr); }

  .bz-lightbox__stage { grid-column: 1; }

  .bz-lightbox__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(0, 0, 0, 0.45);
    width: 38px;
  }

  .bz-lightbox__nav--prev { inset-inline-start: 4px; }
  .bz-lightbox__nav--next { inset-inline-end: 4px; }

  /* "Download this photograph" is a long label on a narrow bar. Allowed
     to wrap onto a second line rather than truncated, because a clipped
     verb is worse than a taller bar. */
  .bz-lightbox__bar { flex-wrap: wrap; row-gap: 6px; }
  .bz-lightbox__btn { padding: 6px 10px; }
}

@media (prefers-reduced-motion: reduce) {
  .bz-progress__meter,
  .bz-album__summary::before { transition: none; }
}

/* ---- A session's description, folded ------------------------------------
   A programme is scanned before it is read. Twenty cards each carrying a
   paragraph is a page nobody reaches the bottom of, and the thing being
   looked for is a title and a time. Native <details>, because this also
   renders inside a shadow root where injected script never runs. */
.bz-session__more { margin-top: 2px; }

.bz-session__more > summary {
  display: block;
  cursor: pointer;
  list-style: none;
}

.bz-session__more > summary::-webkit-details-marker { display: none; }

.bz-session__desc {
  display: block;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-secondary, #454A66);
}

.bz-session__desc--full {
  margin-top: 6px;
  color: var(--text-secondary, #454A66);
}

.bz-session__cue {
  display: inline-block;
  margin-top: 4px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-link, #B8432A);
}

.bz-session__cue--less { display: none; }
.bz-session__more[open] .bz-session__cue--less { display: inline-block; }

.bz-session__more[open] .bz-session__desc--teaser,
.bz-session__more[open] .bz-session__cue--more { display: none; }

.bz-session__more > summary:focus-visible {
  outline: 2px solid var(--color-coral, #F26B4A);
  outline-offset: 2px;
  border-radius: 4px;
}

/* A heading inside the registration form, grouping the event's own extra
   questions. Government accreditation forms run long enough that "Personal
   Data" and "Travel" need telling apart. */
.bz-reg__section {
  margin: 10px 0 0;
  font-size: var(--type-body-sm, 13px);
  font-weight: var(--weight-semibold, 600);
  color: var(--text-body, #1E2340);
}

/* Paragraph breaks in a privacy notice are meaningful; the organiser typed
   them and a security office will be asked to produce the wording. */
.bz-reg__notice { white-space: pre-line; }

.bz-reg__check {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: var(--type-body-sm, 13px);
}

.bz-reg__check input[type='checkbox'] {
  /* Sized up from the browser default of about 13px. The rest of this form
     is on 16px controls with 44px targets for exactly the reason a
     government form needs it most: it is filled in on a phone, once, by
     somebody who will not try twice. */
  width: 18px;
  height: 18px;
  flex: none;
  margin: 1px 0 0;
  accent-color: var(--color-coral, #F26B4A);
}

/* A list of choices needs air between the rows, or seven of them read as
   one block of text with ticks in it. */
.bz-reg__field > div > .bz-reg__check { padding: 3px 0; }

@media (max-width: 767px) {
  .bz-reg__check input[type='checkbox'] { width: 22px; height: 22px; }
  .bz-reg__field > div > .bz-reg__check { padding: 6px 0; }
}

/* ── Answers on a registration request ────────────────────────────
   A reviewer deciding whether to issue an accreditation pass is reading
   a document type, a role and a scan. Bare values in a column tell them
   none of the three, so each answer carries its question. */
.bz-request-answers {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--color-border, #E5E7EB);
}

.bz-request-answer {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  font-size: var(--type-caption, 12px);
  line-height: 1.5;
}

.bz-request-answer__label {
  color: var(--text-subtle, #6F7389);
  /* The question is the quieter half: the reviewer is scanning the
     answers and using the labels only to tell which is which.

     Allowed to shrink, because some of these questions are a sentence
     long: fixed, "Copy of the biodata page of the identification
     document" pushed its own preview buttons onto the next line while
     the shorter question beside it kept them inline, so two identical
     controls sat in two different places. */
  flex: 0 1 auto;
  min-width: 0;
}

.bz-request-answer__label::after { content: ':'; }

.bz-request-answer__value {
  color: var(--text-body, #1E2340);
  font-weight: var(--weight-medium, 500);
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ── A request, folded ────────────────────────────────────────────
   An accredited event's request carries a dozen answers and two
   documents. Fifty of those open at once is a page nobody gets
   through, so the name and the decision stay visible and the detail is
   one click away for the request actually being read. */
.bz-request { margin-top: 6px; }

.bz-request__summary {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
  list-style: none;
  font-size: var(--type-caption, 12px);
  font-weight: var(--weight-medium, 500);
  color: var(--text-link, #B8432A);
}

.bz-request__summary::-webkit-details-marker { display: none; }

/* Drawn rather than an icon font, so it points along the reading
   direction in Arabic without a second rule. */
.bz-request__summary::before {
  content: '';
  width: 0;
  height: 0;
  border-inline-start: 5px solid currentColor;
  border-block: 3.5px solid transparent;
  transition: transform 150ms ease;
}

.bz-request[open] > .bz-request__summary::before { transform: rotate(90deg); }
[dir='rtl'] .bz-request[open] > .bz-request__summary::before { transform: rotate(-90deg); }

/* ── An uploaded answer, shown rather than only offered ───────────
   Checking a passport against a name means looking at two documents
   per request. Doing that by downloading each one and hunting through
   a downloads folder is not reviewing, it is filing. */
/* Two buttons beside the answer, not a thumbnail. One opens the document
   where you are; the other saves it. A thumbnail made the reviewer guess
   which of the two a click would do, and the answer was neither obvious
   nor the same for both. */
.bz-request-file__actions {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex: 0 0 auto;
  /* Pinned to the end of the row, so every document's two buttons are in
     the same place whatever the question above them is called. */
  margin-inline-start: auto;
}

.bz-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-xs, 4px);
  color: var(--text-muted, #5C6078);
  text-decoration: none;
}

.bz-icon-btn:hover {
  background: var(--color-sand-100, #F3ECE3);
  color: var(--text-link, #B8432A);
}

.bz-icon-btn:focus-visible {
  outline: 2px solid var(--color-coral, #F26B4A);
  outline-offset: 1px;
}

.bz-request__summary:focus-visible,
.bz-request-file__body a:focus-visible {
  outline: 2px solid var(--color-coral, #F26B4A);
  outline-offset: 2px;
  border-radius: var(--radius-xs, 4px);
}

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

/* ── The form, as a registrant will meet it ───────────────────────
   Two screens decide the order between them, and neither showed the
   result: an organiser was arranging questions they could only see by
   opening the public page in another tab. */
.bz-form-preview {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: bz-preview;
}

.bz-form-preview__row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 10px;
  border-radius: var(--radius-xs, 4px);
  font-size: var(--type-body-sm, 13px);
  counter-increment: bz-preview;
}

.bz-form-preview__row::before {
  content: counter(bz-preview);
  min-width: 1.4em;
  font-size: var(--type-caption, 12px);
  font-variant-numeric: tabular-nums;
  color: var(--text-subtle, #6F7389);
}

/* The event's own questions tinted, so the two kinds are told apart at a
   glance: the standard ones are the same on every form, these are not. */
.bz-form-preview__row--extra { background: var(--color-sand-50, #FBF7F2); }

.bz-form-preview__name { color: var(--text-body, #1E2340); }

.bz-form-preview__tag {
  margin-inline-start: auto;
  font-size: var(--type-caption, 12px);
  color: var(--text-subtle, #6F7389);
  flex: 0 0 auto;
}

/* Only the first tag is pushed to the far edge; the rest follow it. */
.bz-form-preview__tag ~ .bz-form-preview__tag { margin-inline-start: 0; }

.bz-form-preview__tag--extra { color: var(--text-link, #B8432A); }

/* ── A question, with its editor folded underneath ────────────────
   Opening twelve edit forms at once on an accreditation event is a page
   of forms rather than a list of questions. */
.bz-order-item--stacked {
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
}

.bz-order-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.bz-field-edit { margin-inline-start: 26px; }

.bz-field-edit__summary {
  display: inline-block;
  cursor: pointer;
  list-style: none;
  font-size: var(--type-caption, 12px);
  font-weight: var(--weight-medium, 500);
  color: var(--text-link, #B8432A);
}

.bz-field-edit__summary::-webkit-details-marker { display: none; }

.bz-field-edit__body {
  display: grid;
  gap: 14px;
  margin-top: 10px;
  padding: 14px;
  border: 1px solid var(--color-border, #E5E7EB);
  border-radius: var(--radius-sm, 6px);
  background: var(--color-sand-50, #FBF7F2);
}

/* A row being dragged should not also be trying to open its editor. */
.bz-order-item[draggable='true'] .bz-field-edit__summary { cursor: pointer; }


/* ── Previewing a submitted document ──────────────────────────────
   Opened over the review screen so a passport can be checked against a
   name without leaving the list. Every trigger is still a link to a
   real URL, so with the script blocked it opens in a tab instead. */
.bz-preview {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  gap: 10px;
  padding: 14px;
  background: rgba(10, 12, 24, 0.97);
}

.bz-preview[hidden] { display: none; }

body.bz-preview-open { overflow: hidden; }

.bz-preview__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  color: #FFFFFF;
}

.bz-preview__title {
  font-size: var(--type-caption, 12px);
  opacity: 0.8;
  min-width: 0;
  overflow-wrap: anywhere;
}

.bz-preview__tools { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }

.bz-preview__btn {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.08);
  color: #FFFFFF;
  border-radius: var(--radius-sm, 6px);
  padding: 6px 12px;
  font-size: var(--type-caption, 12px);
  cursor: pointer;
  text-decoration: none;
  min-height: 36px;
  display: inline-flex;
  align-items: center;
}

.bz-preview__btn:hover { background: rgba(255, 255, 255, 0.18); }

.bz-preview__btn:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: 2px;
}

.bz-preview__stage {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  overflow: auto;
}

.bz-preview__stage img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: var(--radius-sm, 6px);
}

/* A PDF gets the whole stage and the browser's own reader, which is
   better than anything we would write. */
.bz-preview__stage iframe {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: var(--radius-sm, 6px);
  background: #FFFFFF;
}

/* A heading inside a block of answers, telling the standard registration
   details apart from the event's own questions. Quiet: it is a divider,
   not a title. */
.bz-answers__heading {
  margin: 8px 0 2px;
  font-size: var(--type-caption, 12px);
  font-weight: var(--weight-medium, 500);
  color: var(--text-subtle, #6F7389);
  letter-spacing: 0.02em;
}

.bz-answers__heading:first-child { margin-top: 0; }

/* ── A question that came back empty ──────────────────────────────
   The attendee list shows the whole form rather than only its answers,
   so an unanswered question is a row like any other and has to read as
   one without reading as a value. Set in the body face at normal weight,
   unlike a real answer, so a column of them is visibly a column of gaps.

   Three states, two tones. Required-and-unanswered is the only one that
   is anybody's failing, so it is the only one that takes the warning
   colour; an optional question nobody answered and a staff field nobody
   has filled in yet are both just facts. */
.bz-request-answer__value.bz-answer--missing,
.bz-request-answer__value.bz-answer--optional,
.bz-request-answer__value.bz-answer--staff {
  font-weight: var(--weight-normal, 400);
  font-style: italic;
}

.bz-request-answer__value.bz-answer--missing {
  color: var(--status-warning, #B26A00);
}

.bz-request-answer__value.bz-answer--optional,
.bz-request-answer__value.bz-answer--staff {
  color: var(--text-subtle, #6F7389);
}

/* ── Asking one delegate for what is missing ──────────────────────
   The control sits beside the badge that prompts it. Behind the row
   menu it was two clicks from the thing a reader is looking at, which
   on a list of four hundred is two clicks nobody takes. */
.bz-chase {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.bz-chase__btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 9px;
  border: 1px solid var(--border-input, #CFC5B8);
  border-radius: var(--radius-bubble-pill, 999px);
  background: var(--surface-card, #FFFFFF);
  color: var(--text-link, #B8432A);
  font-size: var(--type-caption, 12px);
  font-weight: var(--weight-medium, 500);
  cursor: pointer;
  line-height: 1.4;
}

.bz-chase__btn:hover { background: var(--surface-coral-tint, #FDEBE5); }
.bz-chase__btn:disabled { opacity: .55; cursor: default; }
.bz-chase__btn i { font-size: 12px; }

/* How many times, and how long ago. The thing that makes the button
   safe to press when somebody else is working the same list. */
.bz-chase__asked {
  display: block;
  margin-top: 3px;
  font-size: var(--type-caption, 12px);
  color: var(--text-subtle, #6F7389);
}

/* ── Toasts ───────────────────────────────────────────────────────
   Top right, fixed, and deliberately not the page's own flash
   messages: those sit in the flow and push the list down, and a list
   that jumps after every send is the thing being fixed. */
.bz-toasts {
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 120;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}

.bz-toast {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-width: 240px;
  max-width: 340px;
  padding: 11px 14px;
  border-radius: var(--radius-bubble-md, 16px);
  background: var(--surface-card, #FFFFFF);
  border: 1px solid var(--border-hairline, #ECE4DA);
  box-shadow: var(--shadow-2, 0 6px 20px rgb(30 35 64 / .10));
  animation: bz-toast-in 180ms ease-out both;
}

.bz-toast--leaving { opacity: 0; transition: opacity 200ms ease-out; }

.bz-toast__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--status-success-bg, #E3F2E8);
  color: var(--status-success, #2F7D4F);
}

.bz-toast--warn .bz-toast__icon {
  background: var(--status-warning-bg, #FFF1D6);
  color: var(--status-warning, #B26A00);
}

.bz-toast__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.bz-toast__title { font-size: 13px; font-weight: var(--weight-medium, 500); color: var(--text-body, #1E2340); }
.bz-toast__body { font-size: 12px; color: var(--text-subtle, #6F7389); }

@keyframes bz-toast-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .bz-toast { animation: none; }
  .bz-toast--leaving { transition: none; }
}

/* ── The admin dashboard ──────────────────────────────────────────
   Three rows answering three questions: what needs a decision, what
   is happening, how is the business doing. The first row is drawn
   only when something is waiting, so these never render as zeroes. */
.bz-queue-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 16px;
  border: 1px solid var(--status-warning, #B26A00);
  background: var(--status-warning-bg, #FFF1D6);
  border-radius: var(--radius-card, 16px);
  text-decoration: none;
}

.bz-queue-card:hover { border-color: var(--color-coral, #F26B4A); }

.bz-queue-card__count {
  font-family: var(--font-display);
  font-weight: var(--weight-medium, 500);
  font-size: 26px;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--status-warning, #B26A00);
}

.bz-queue-card__label {
  font-size: var(--type-caption, 12px);
  color: var(--text-body, #1E2340);
}

/* A plain figure. Not a chart, because a chart of one number is a
   chart that has to be decoded before it can be read. */
.bz-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 16px;
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: var(--radius-card, 16px);
  background: var(--surface-card, #FFFFFF);
}

.bz-stat__label {
  font-size: var(--type-caption, 12px);
  color: var(--text-subtle, #6F7389);
}

.bz-stat__value {
  font-family: var(--font-display);
  font-weight: var(--weight-medium, 500);
  font-size: 22px;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  color: var(--text-body, #1E2340);
}

/* Money owed is a state, not a series, so it takes the status colour
   rather than an accent that would read as one category among many. */
.bz-stat__value--owed { color: var(--status-warning, #B26A00); }
.bz-stat__value--none { font-size: 16px; color: var(--text-subtle, #6F7389); }

/* How far through the door an event is. */
.bz-meter {
  height: 8px;
  border-radius: var(--radius-xs, 4px);
  background: var(--surface-sand, #F3ECE3);
  overflow: hidden;
}

.bz-meter__fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-xs, 4px);
  background: var(--color-coral, #F26B4A);
}

/* A step that is not a narrowing of the one above it.
   On the engagement funnel, "turned up" sits below "voted or posted" and is
   larger than both: plenty of people attend having never opened the portal.
   Drawn in ink rather than the accent so it reads as a separate fact rather
   than as the bottom of the same slope. */
.bz-meter__fill--alt { background: var(--color-usiku, #1E2340); }

/* ── The answer, beside the button that asked ─────────────────────
   A send either worked or it did not, and that belongs next to the
   control rather than three columns away or in a log further down.
   Word and mark together: the tick carries at a glance and the word
   carries the distinction between "they took it" and "they already
   had it", which a colour cannot. */
.bz-sendmark {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  font-size: var(--type-caption, 12px);
  font-weight: var(--weight-medium, 500);
  padding: 2px 8px;
  border-radius: var(--radius-xs, 4px);
  border: 1px solid transparent;
}

.bz-sendmark--good {
  color: var(--status-success-text, #276A43);
  background: var(--status-success-bg, #E3F2E8);
  border-color: var(--status-success, #2F7D4F);
}

.bz-sendmark--bad {
  color: var(--status-danger-text, #B42335);
  background: var(--status-danger-bg, #FCE7EA);
  border-color: var(--status-danger, #B42335);
}

/* ── A result, as a popup ─────────────────────────────────────────
   Native <dialog>, so the backdrop, the escape key and the focus trap
   are the browser's job rather than ours. The application has no modal
   library and did not need one for this. */
.bz-dialog {
  width: min(680px, calc(100vw - 32px));
  max-height: calc(100vh - 64px);
  /* Explicit, because the stylesheet's reset zeroes margins and a dialog
     relies on auto margins to centre itself. Without this it opens hard
     against the top-left corner. */
  margin: auto;
  padding: 0;
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: var(--radius-md, 16px);
  background: var(--surface-card, #FFFFFF);
  color: var(--text-body, #1E2340);
  box-shadow: 0 24px 64px -24px rgba(30, 35, 64, .45);
}

.bz-dialog::backdrop { background: rgba(30, 35, 64, .45); }

.bz-dialog__close {
  display: flex;
  justify-content: flex-end;
  padding: 8px 8px 0;
}

.bz-dialog__body {
  display: grid;
  gap: 10px;
  padding: 0 20px 20px;
  overflow-y: auto;
}

.bz-dialog__title {
  font-family: var(--font-display, inherit);
  font-size: var(--type-body-lg, 18px);
  font-weight: var(--weight-semibold, 600);
  margin: 0;
}

.bz-dialog__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: var(--type-caption, 12px);
  color: var(--text-muted, #5C6078);
}

.bz-dialog__message { margin: 0; font-size: var(--type-body, 14px); }

/* Wide and scrollable on its own, so a long payload never makes the
   dialog itself scroll sideways. */
.bz-dialog__pre {
  margin: 6px 0 0;
  padding: 10px 12px;
  border-radius: var(--radius-xs, 4px);
  background: var(--surface-soft, #FBF7F2);
  border: 1px solid var(--border-hairline, #ECE4DA);
  font-size: 11.5px;
  line-height: 1.5;
  overflow-x: auto;
  white-space: pre;
}

/* A card header carrying a subtitle.
   .kt-card-header is built for one line: min-height 3.5rem, align-items
   center, and padding on the inline axis only. Centring does the vertical
   spacing, so the moment flex-col stacks a title above a hint the content is
   taller than the min-height, there is no block padding left to fall back on,
   and the title sits hard against the top border while the hint sits hard
   against the bottom one.

   Scoped to headers that have already opted into stacking, so single-line
   headers everywhere else keep the centring they were designed around. */
.kt-card-header.flex-col {
  padding-block: calc(var(--spacing, 0.25rem) * 4);
  align-items: flex-start;
  justify-content: flex-start;
}

/* Six figures rather than four.
   .bz-figures caps at four columns, which leaves a six-figure row as 4 + 2
   with two oddly wide cards on the second line. Same rules, one more break:
   two, three, then six. */
.bz-figures--six { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (min-width: 768px) {
  .bz-figures--six { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 1280px) {
  .bz-figures--six { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}

/* ── A long list of passes, folded ────────────────────────────────
   An accredited event offers a dozen roles, and a dozen radio cards is
   a wall the reader scrolls through before reaching the form. The
   trigger names the current choice; the real radios, with their
   descriptions, are what it opens.

   Not a <select>: a select holds a name and nothing else, and the two
   things somebody needs before choosing a pass are what it is for and
   whether it has to be approved. */
.bz-reg__ticket-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 11px 14px;
  border: 1px solid var(--border-input, #CFC5B8);
  border-radius: var(--radius-md, 8px);
  background: #FFFFFF;
  font: inherit;
  font-size: var(--type-body-sm, 13px);
  color: var(--text-body, #1E2340);
  cursor: pointer;
  text-align: start;
  /* The same 44px target the rest of the form uses, because this is the
     first control on a page filled in on a phone. */
  min-height: 44px;
}

.bz-reg__ticket-trigger:hover { border-color: var(--color-coral, #F26B4A); }

.bz-reg__ticket-trigger:focus-visible {
  outline: 2px solid var(--color-coral, #F26B4A);
  outline-offset: 1px;
}

/* Drawn rather than an icon font, so it points the right way in Arabic
   without a second rule. */
.bz-reg__ticket-caret {
  width: 0;
  height: 0;
  flex: 0 0 auto;
  border-inline: 5px solid transparent;
  border-top: 6px solid currentColor;
  opacity: 0.55;
  transition: transform 150ms ease;
}

.bz-reg__tickets--menu.is-open .bz-reg__ticket-caret { transform: rotate(180deg); }

/* Closed until opened. Only inside the folded variant, so an event with
   three passes still shows all three. */
.bz-reg__tickets--menu .bz-reg__tickets { display: none; }
.bz-reg__tickets--menu.is-open .bz-reg__tickets { display: flex; }

.bz-reg__tickets--menu .bz-reg__tickets {
  flex-direction: column;
  gap: 6px;
  margin-top: 6px;
  max-height: 340px;
  overflow-y: auto;
  padding: 2px;
}

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

/* ---- Public event page: the tab strip ----------------------------------
   The strip the delegate header already had, for the page a visitor sees
   first.

   Six tabs measure 435px. On a 390px phone they hung over the edge of the
   card and took the document with them, so the whole page scrolled sideways
   and Documents was outside it whichever way you scrolled. Scrolling the
   strip itself contains the problem where it belongs.

   Declared here rather than with utilities because styles.css is prebuilt:
   sticky, the hidden scrollbar and the full-bleed negative margin are not in
   the shipped file, so utility classes for them would compile to nothing. */
.bz-event-tabs {
  /* The panels below are long. Reaching the foot of a programme and having
     to scroll back past it to change tab is how a reader decides the other
     tabs were not worth it. */
  position: sticky;
  top: 0;
  z-index: 20;

  display: flex;
  align-items: stretch;
  gap: 2px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;

  /* Opaque, or the panel scrolls visibly through the strip it is passing
     under. */
  background: var(--background);

  /* Full bleed across the card. The card's own padding is 32px (40px from
     640px up); a strip inset by that much leaves a gap on either side for
     content to show through while it is stuck. */
  margin-inline: -32px;
  padding-inline: 32px;

  /* Each tab's underline sits on this line, so it survives the scroll. */
  box-shadow: inset 0 -1px 0 var(--color-border, #E5E7EB);
}

.bz-event-tabs::-webkit-scrollbar { display: none; }

.bz-event-tab {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 10px 12px;
  font-size: var(--type-caption, 12px);
  color: var(--text-secondary, #6B7280);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  /* 44px is the smallest target a thumb hits reliably. */
  min-height: 44px;
}

.bz-event-tab i { font-size: 16px; }

.bz-event-tab:hover { color: var(--text-primary, #1E2340); }

.bz-event-tab--active {
  color: var(--color-coral, #F26B4A);
  border-bottom-color: var(--color-coral, #F26B4A);
  font-weight: var(--weight-medium, 500);
}

.bz-event-tab:focus-visible {
  outline: 2px solid var(--color-coral, #F26B4A);
  outline-offset: -2px;
}

@media (min-width: 640px) {
  .bz-event-tabs {
    margin-inline: -40px;
    padding-inline: 40px;
  }
}

/* ---- Public event page: sharing ----------------------------------------
   Plain links into the apps people already use. No network's own widget, so
   nothing third party loads and no one is told the page was opened. */
.bz-share {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}

.bz-share__label {
  font-size: var(--type-caption, 12px);
  color: var(--text-secondary, #6B7280);
}

.bz-share__links {
  display: flex;
  align-items: center;
  gap: 4px;
}

.bz-share__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--background);
  color: var(--text-secondary, #6B7280);
  cursor: pointer;
}

.bz-share__btn svg { width: 16px; height: 16px; }
.bz-share__btn i { font-size: 16px; }

.bz-share__btn:hover {
  color: var(--color-coral, #F26B4A);
  border-color: var(--color-coral, #F26B4A);
}

.bz-share__btn:focus-visible {
  outline: 2px solid var(--color-coral, #F26B4A);
  outline-offset: 2px;
}

.bz-share__done {
  font-size: var(--type-caption, 12px);
  color: var(--color-success, #2F7D4F);
}

/* Centred with the title it sits under, which is centred on a phone only. */
.bz-share { justify-content: center; }

@media (min-width: 640px) {
  .bz-share { justify-content: flex-start; }
}

/* On a phone that has an OS share sheet, the sheet already lists WhatsApp,
   email and everything else installed. Offering the row as well asks the
   same question twice and costs a third of the width to do it.

   The trade goes the other way on a laptop, where there is room for the row
   and a share sheet is a less familiar thing to be handed. */
@media (min-width: 640px) {
  .bz-share__native { display: none; }
}

@media (max-width: 639px) {
  .bz-has-web-share .bz-share__links { display: none; }

  /* With the row gone the label and the button say the same word twice. */
  .bz-has-web-share .bz-share__label { display: none; }
}

/* ---- Public event page: the language menu ------------------------------
   Width stated here because the utility class the delegate header uses for
   the same menu is an arbitrary value, and styles.css is prebuilt. */
.bz-lang-menu { width: 180px; }

/* ---- The programme list, edited in place -------------------------------
   Editing one session used to mean opening its own page, changing a time,
   saving, and landing back at the top of a list you then had to scroll to
   find the next one. On a five-day programme that is the afternoon gone.

   Declared here rather than with utilities because styles.css is prebuilt:
   the grid template, the chevron rotation and the status colours are not in
   the shipped file. */
.bz-sessions {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.bz-sessions__day {
  font-size: var(--type-caption, 12px);
  font-weight: var(--weight-semibold, 600);
  color: var(--text-secondary, #6B7280);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-top: 14px;
}

.bz-sessions__day:first-child { margin-top: 0; }

.bz-session {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--background);
}

.bz-session.is-open {
  border-color: var(--color-coral, #F26B4A);
}

.bz-session__head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding-inline-end: 8px;
}

/* The whole row opens it. A pencil icon at the end of a row is a target the
   size of a thumbnail on a list people work down one session at a time. */
.bz-session__toggle {
  display: grid;
  /* The type badge is capped rather than given "auto": "Other
     (registration, logistics, etc.)" is a form label that happens to be
     printed here, and left to its natural width it took the room the title
     needed. The full wording is in the Type field once the row is open. */
  grid-template-columns: 16px 92px minmax(0, 132px) minmax(0, 3fr) minmax(0, 1fr) minmax(0, 1.5fr);
  align-items: center;
  gap: 10px;
  flex: 1 1 auto;
  min-width: 0;
  padding: 10px 12px;
  background: none;
  border: 0;
  text-align: start;
  cursor: pointer;
  /* Operated down a long list, often on a laptop trackpad. */
  min-height: 48px;
}

.bz-session__chevron {
  font-size: 12px;
  color: var(--text-muted, #5C6078);
  transition: transform var(--motion-base, 200ms) ease;
}

.bz-session.is-open .bz-session__chevron { transform: rotate(180deg); }

.bz-session__toggle > .kt-badge {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
}

.bz-session__time {
  font-size: var(--type-caption, 12px);
  color: var(--text-secondary, #6B7280);
}

.bz-session__title {
  font-size: var(--type-body-sm, 13px);
  font-weight: var(--weight-medium, 500);
  color: var(--text-primary, #1E2340);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bz-session__meta {
  font-size: var(--type-caption, 12px);
  color: var(--text-secondary, #6B7280);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bz-session__actions {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 0 0 auto;
}

/* Reserves its own width, so a row does not shift sideways the moment
   somebody types in it. */
.bz-session__status {
  min-width: 68px;
  text-align: end;
  font-size: var(--type-caption, 12px);
  color: var(--text-muted, #5C6078);
}

.bz-session__status.is-saved { color: var(--color-success, #2F7D4F); }
.bz-session__status.is-failed { color: var(--color-danger, #B42335); }

.bz-session__body {
  padding: 4px 16px 16px;
  border-top: 1px solid var(--border);
}

.bz-session__loading {
  padding: 16px 0;
  font-size: var(--type-caption, 12px);
  color: var(--text-secondary, #6B7280);
}

.bz-session__footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 12px;
}

/* On a narrow screen the row is two lines: what it is, then when and who.
   Six columns at 390px gives every one of them four characters. */
@media (max-width: 1023px) {
  .bz-session__toggle {
    grid-template-columns: 16px minmax(0, 1fr);
    row-gap: 4px;
  }

  .bz-session__title { grid-column: 2; white-space: normal; }
  .bz-session__time,
  .bz-session__meta { grid-column: 2; }
  .bz-session__toggle > .kt-badge { grid-column: 2; justify-self: start; }
}

/* ---- Waiting ------------------------------------------------------------
   One spinner, for anything that has started and has not finished: a
   document going up, a queue reading it, a row saving itself.

   Declared here because styles.css is prebuilt and ships no spinner, and
   because a GIF would not take the brand colour or the reduced-motion
   setting. */
.bz-spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  border: 2px solid var(--color-coral-tint-2, #FBD9CE);
  border-top-color: var(--color-coral, #F26B4A);
  border-radius: 50%;
  animation: bz-spin 700ms linear infinite;
}

@keyframes bz-spin {
  to { transform: rotate(360deg); }
}

/* Somebody who has asked for less motion still needs to know something is
   happening, so it pulses rather than spins. */
@media (prefers-reduced-motion: reduce) {
  .bz-spinner {
    animation: bz-pulse 1.4s ease-in-out infinite;
  }

  @keyframes bz-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .35; }
  }
}

/* A dashboard card that is a job rather than a measurement.

   Marked rather than coloured in: the number is the thing to read, and a
   whole card in warning amber competes with the alerts that mean something
   has gone wrong. Nothing here has gone wrong; somebody is waiting. */
.bz-stat--urgent {
  border-color: var(--color-warning-fill, #F5B23D);
  box-shadow: inset 3px 0 0 var(--color-warning-fill, #F5B23D);
}

/* ── Sending one answer back ──────────────────────────────────────────
   The third state of an answer: present, read, and wrong. Styled as a
   rejection rather than a warning, because an accreditation office
   scanning a list has to tell "they have not answered" from "they
   answered and we turned it down": those need different chasing. */

.bz-answer-reject {
  flex: 0 0 auto;
  padding: 1px 8px;
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted, #5C6078);
  font-size: var(--type-caption-sm, 11px);
  line-height: 1.6;
  cursor: pointer;
}

.bz-answer-reject:hover {
  border-color: var(--color-destructive, #C0392B);
  color: var(--color-destructive, #C0392B);
}

.bz-request-answer--sent-back { color: var(--color-destructive, #C0392B); }

.bz-request-answer__flag,
.bz-doc__flag {
  /* Its own line and the full width of the row. The reason is a
     sentence somebody typed, and sharing a baseline with the answer it
     is about made the two read as one run-on string. */
  flex: 1 0 100%;
  margin: 2px 0 0;
  color: var(--color-destructive, #C0392B);
  font-size: var(--type-caption-sm, 11px);
  line-height: 1.5;
}

/* ── Reviewing what would be sent ─────────────────────────────────────
   Documents shown rather than linked. The judgement is visual and takes
   a second once the thing is on screen; it took a new tab, a download
   and a scroll back to your place before. */

.bz-doc-grid {
  display: grid;
  gap: 16px;
  /* min-content floor, not auto: an image or a PDF frame in a grid
     track whose minimum is auto refuses to shrink below its intrinsic
     width and pushes the dialog sideways on a phone. */
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
}

.bz-doc-cell {
  display: grid;
  gap: 6px;
  align-content: start;
}

.bz-doc { display: grid; gap: 4px; margin: 0; }

.bz-doc__label {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: var(--type-caption, 12px);
  font-weight: var(--weight-medium, 500);
  color: var(--text-subtle, #6F7389);
}

.bz-doc__label a {
  font-weight: var(--weight-normal, 400);
  color: var(--brand-ink, #B4552D);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.bz-doc__image,
.bz-doc__frame {
  width: 100%;
  /* Taller than it was. A bio-data page is a page: at 260 the frame
     showed a band across the middle of it and the reviewer scrolled
     inside a box to see the thing they opened the dialog to see. */
  height: 340px;
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: var(--radius-sm, 10px);
  background: var(--surface-sunken, #F7F4EF);
  /* contain, not cover: a passport page cropped to fill the box hides
     the corner that tells you it is the wrong page. */
  object-fit: contain;
}

.bz-doc__reject { display: grid; gap: 6px; }

.bz-doc__reason {
  display: grid;
  gap: 3px;
  font-size: var(--type-caption-sm, 11px);
  color: var(--text-subtle, #6F7389);
}

.bz-doc__reason input {
  width: 100%;
  min-width: 0;
  padding: 6px 10px;
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: var(--radius-sm, 10px);
  background: var(--surface-card, #FFFFFF);
  color: var(--text-body, #1E2340);
  /* 16px below the tablet breakpoint or iOS zooms the page on focus and
     the reviewer loses the dialog they were reading. */
  font-size: var(--type-caption, 12px);
}

@media (max-width: 767px) {
  .bz-doc__reason input { font-size: 16px; min-height: 44px; }
  .bz-doc__image,
  .bz-doc__frame { height: 280px; }
}

/* The dialog carries documents now, so it needs the room to show two
   of them side by side without either being a postage stamp. */
.bz-dialog--wide { width: min(880px, calc(100vw - 32px)); }

/* ── Two records, one person ──────────────────────────────────────────
   A comparison, so it has to read as two columns rather than as a
   paragraph. Unstyled it rendered as one run-on sentence with the two
   people's facts butted together, which is the one thing this screen
   must not do: the whole decision is telling them apart. */

.bz-merge {
  display: grid;
  gap: 16px;
  padding: 16px;
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: var(--radius-md, 16px);
  background: var(--surface-sunken, #F7F4EF);
}

.bz-merge__pair {
  display: grid;
  gap: 12px;
  /* min-content floor, not auto: a long email in one column otherwise
     refuses to shrink and pushes the other off the screen. */
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}

.bz-merge__option {
  display: grid;
  gap: 10px;
  align-content: start;
  padding: 14px;
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: var(--radius-sm, 10px);
  background: var(--surface-card, #FFFFFF);
  cursor: pointer;
}

/* The chosen column, marked on the card and not only on the dot. The
   radio is 14px of the 300px somebody is actually reading. */
.bz-merge__option:has(input:checked) {
  border-color: var(--brand-ink, #B4552D);
  box-shadow: inset 0 0 0 1px var(--brand-ink, #B4552D);
}

.bz-merge__choose {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.bz-merge__name {
  font-size: var(--type-body, 14px);
  font-weight: var(--weight-semibold, 600);
  color: var(--text-mono, #1E2340);
  overflow-wrap: anywhere;
}

/* The facts, one per line. Side by side they were a list of words with
   no way to tell which column a given word belonged to. */
.bz-merge__facts,
.bz-merge__outcome {
  display: grid;
  gap: 3px;
  font-size: var(--type-caption, 12px);
  line-height: 1.5;
  min-width: 0;
}

.bz-merge__facts {
  color: var(--text-subtle, #6F7389);
  overflow-wrap: anywhere;
}

.bz-merge__outcome {
  padding-top: 10px;
  border-top: 1px solid var(--border-hairline, #ECE4DA);
  color: var(--text-body, #1E2340);
}

.bz-merge__outcome strong {
  font-weight: var(--weight-semibold, 600);
}

/* The only irreversible-feeling line on the page, so it is the one that
   is coloured. Everything above it is a gain; this is the loss. */
.bz-merge__gone {
  margin-top: 4px;
  color: var(--color-destructive, #C0392B);
  font-weight: var(--weight-medium, 500);
}

@media (max-width: 767px) {
  .bz-merge { padding: 12px; }
  .bz-merge__option { padding: 12px; }
}

/* Two records matched on a name, holding two different addresses. The
   likeliest explanation is two people, so it is said before the choice
   rather than discovered after the merge. */
.bz-merge__caution {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 0;
  color: var(--color-destructive, #C0392B);
  font-size: var(--type-caption, 12px);
  line-height: 1.5;
}

/* The other half of a chase: when something came back.
   Quiet by default, because most of the time it is simply a date. It
   earns the accent when it is later than the last time we asked, which
   is the one case somebody scanning a chase list is looking for: they
   replied, and you can stop. */
.bz-chase__answered {
  display: block;
  margin-top: 2px;
  color: var(--text-subtle, #6F7389);
  font-size: var(--type-caption-sm, 11px);
  line-height: 1.5;
}

.bz-chase__answered--after {
  color: var(--color-success, #2E7D55);
  font-weight: var(--weight-medium, 500);
}

/* ── Rearranging a day ────────────────────────────────────────────────
   One list per room, because that is the only place "which comes first"
   has an answer. The room heading has to read as a container rather than
   as another row, or four breakout lists on one day run together into
   one long list that implies an order between them. */

.bz-order-room {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0 0 8px;
  font-size: var(--type-caption, 12px);
  font-weight: var(--weight-semibold, 600);
  color: var(--text-subtle, #6F7389);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.bz-order-room span {
  font-weight: var(--weight-normal, 400);
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted, #5C6078);
}

.bz-order-pin {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: 0 0 auto;
  font-size: var(--type-caption-sm, 11px);
  color: var(--text-subtle, #6F7389);
  cursor: pointer;
  white-space: nowrap;
}

/* A row whose time moved while being dragged. Quiet, because during a
   rearrangement most rows move and a loud colour on all of them says
   nothing. */
.bz-order-item.is-retimed .bz-order-meta { color: var(--brand-ink, #B4552D); }

/* ── What the drop would do ───────────────────────────────────────────
   Before and after side by side. "Moves to 14:30" with no "from" makes
   somebody scroll back a screen to work out whether that is a change. */

.bz-retime {
  display: grid;
  gap: 1px;
  background: var(--border-hairline, #ECE4DA);
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: var(--radius-sm, 10px);
  overflow: hidden;
}

.bz-retime__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  padding: 9px 12px;
  background: var(--surface-card, #FFFFFF);
  font-size: var(--type-caption, 12px);
}

.bz-retime__row--moved { background: var(--surface-sunken, #F7F4EF); }

.bz-retime__title {
  flex: 1 1 14rem;
  min-width: 0;
  font-weight: var(--weight-medium, 500);
  color: var(--text-body, #1E2340);
  overflow-wrap: anywhere;
}

.bz-retime__pin {
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: 999px;
  font-size: var(--type-caption-sm, 11px);
  font-weight: var(--weight-normal, 400);
  color: var(--text-subtle, #6F7389);
}

.bz-retime__times {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
}

.bz-retime__from { color: var(--text-subtle, #6F7389); text-decoration: line-through; }
.bz-retime__to { color: var(--brand-ink, #B4552D); font-weight: var(--weight-semibold, 600); }
.bz-retime__same { color: var(--text-subtle, #6F7389); }

.bz-retime__conflict {
  flex: 1 0 100%;
  display: flex;
  align-items: flex-start;
  gap: 5px;
  color: var(--color-destructive, #C0392B);
  font-size: var(--type-caption-sm, 11px);
  line-height: 1.5;
}

/* ── Where a list stands, on one line ─────────────────────────────────
   Three stacked blocks became chips. Each was reasonable alone and
   together they pushed the actual list of people below the fold on the
   laptop an organiser spends the day on. */

.bz-statusbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 10px;
  padding: 10px 14px;
}

.bz-statusbar__item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 10px;
  border: 1px solid var(--border-hairline, #ECE4DA);
  border-radius: 999px;
  background: var(--surface-card, #FFFFFF);
  font-size: var(--type-caption, 12px);
  line-height: 1.4;
  /* The chip is the unit that wraps. Letting its parts wrap instead
     put a count on one line and the action it belongs to on the next,
     reading as two separate facts. */
  white-space: nowrap;
}

.bz-statusbar__item--warn {
  border-color: color-mix(in srgb, var(--color-warning, #B45309) 35%, transparent);
  background: var(--surface-sunken, #F7F4EF);
}

.bz-statusbar__item--good {
  border-color: color-mix(in srgb, var(--color-success, #2E7D55) 35%, transparent);
}

.bz-statusbar__count {
  font-weight: var(--weight-semibold, 600);
  font-variant-numeric: tabular-nums;
  color: var(--text-mono, #1E2340);
}

.bz-statusbar__label { color: var(--text-subtle, #6F7389); }

/* The action reads as a link rather than a button, because a row of
   five buttons is a toolbar and this is a sentence with a verb at the
   end of it. */
.bz-statusbar__action {
  padding: 0;
  border: 0;
  background: none;
  color: var(--brand-ink, #B4552D);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.bz-statusbar__action:hover { text-decoration-thickness: 2px; }

.bz-statusbar__toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--text-body, #1E2340);
  cursor: pointer;
}

@media (max-width: 640px) {
  /* Full width each below the fold, where a wrapped row of chips is
     harder to read than a short stack. */
  .bz-statusbar__item { width: 100%; justify-content: flex-start; white-space: normal; }
}

/* ── Finding one person on the accreditation screen ───────────────────
   Below the filter chips rather than beside them: the chips are about
   the whole event and this is about one person, and a search box in a
   row of counts reads as another count. */

.bz-gpso-find {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
}

.bz-gpso-find input[type="search"] {
  /* Wide enough for a full name and an organisation, and allowed to
     shrink: fixed, it pushed its own button off a phone. */
  flex: 1 1 18rem;
  min-width: 0;
  /* 16px below the tablet breakpoint or iOS zooms the page on focus,
     which on a desk at a door is the last thing anybody wants. */
  font-size: var(--type-body, 14px);
}

@media (max-width: 767px) {
  .bz-gpso-find input[type="search"] { font-size: 16px; min-height: 44px; }
}

/* The participant's name on the accreditation screen, which is also the
   way to their record. Underlined on hover rather than always: two
   hundred permanently underlined names read as a wall of links rather
   than as a list of people. */
.bz-gpso-name {
  font-weight: var(--weight-medium, 500);
  color: var(--text-mono, #1E2340);
  text-decoration: none;
}

.bz-gpso-name:hover {
  color: var(--brand-ink, #B4552D);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* The submission log while a page of it is being fetched. Dimmed rather
   than emptied: a table that vanishes and comes back shifts the whole
   page under the reader, and the fetch is usually quicker than noticing. */
[data-bz-log].is-loading {
  opacity: .55;
  transition: opacity .12s ease-in;
}

@media (prefers-reduced-motion: reduce) {
  [data-bz-log].is-loading { transition: none; }
}
