/* ============================================================================
   EmployeeIQ - Job Fair theme
   ----------------------------------------------------------------------------
   The single source of truth for what this product looks like. Every colour the
   job fair uses is a custom property declared here; no view, no page-level style
   block and no inline attribute may name a colour of its own, and there is a
   test that fails when one does.

   The reason is per-tenant branding. A property sets one colour, and the layout
   emits a handful of values into :root to override the defaults below. That only
   works if the components read variables - a hardcoded purple in one card is a
   card that stays purple on an orange property's registration page, and nobody
   notices until a candidate does.

   Palette shape and proportions come from docs/design/EmployeeIQ-JobFair-Overview.html.
   ============================================================================ */
:root {
  /* -- brand: overridden per tenant, in the layout head, values only -------- */
  --jf-brand: #8d3a96;
  --jf-brand-dark: #6b2c73;
  --jf-brand-light: #f4ecf5;
  --jf-on-brand: #ffffff;
  /* The same purple, as the three numbers a CSS rgba() needs.

       It exists because Metronic builds several of its own effects as
       rgba(var(--bs-primary-rgb), .n), and the admin skin cannot point that at a
       variable holding a hex. Kept here, beside the colour it restates, so the two
       are changed together - and used by the admin skin only. The candidate pages,
       where a tenant's own colour is emitted into :root, never read it, because a
       tenant overriding --jf-brand would not know to override this as well. */
  --jf-brand-rgb: 141, 58, 150;
  /* -- neutrals: not tenant configurable ----------------------------------
       Warm, not cool. These are the paper set from the approved user guide, and
       the warmth is the whole difference between this product and the grey
       framework the admin used to be built out of: paper rather than white,
       ink rather than blue-black, a hairline the colour of a fold rather than a
       grey rule.

       Three text weights, and they mean different things. Ink is what you are
       reading. Muted is prose around it. Faint is metadata - a timestamp, a
       column header, the label above a field - and is the quietest thing on a
       page that still has to be legible: 4.84 on paper, which clears AA. */
  --jf-ink: #171717;
  --jf-muted: #4A4A4A;
  --jf-faint: #6E6E6E;
  --jf-line: #E9E6DD;
  --jf-bg: #FAF9F6;
  --jf-card: #ffffff;
  /* Paper, as the three numbers an rgba() needs - the same arrangement, and the
       same reason, as --jf-brand-rgb above. Bootstrap builds its .bg-light utility
       as rgba(var(--bs-light-rgb), var(--bs-bg-opacity)), which a variable holding
       a hex cannot feed, so every bg-light block on an admin page stayed the
       framework's cool grey while everything around it went warm. Checked against
       --jf-bg by the same guard test. */
  --jf-bg-rgb: 250, 249, 246;
  /* -- the product's own accent -------------------------------------------
       Gold, and #d4af37 rather than anything darker because contrast decided it
       rather than taste. The one use the brand rules mandate is the wordmark's
       second line on the purple hero, and that is display-size text, so the bar
       is 3:1. Measured against the gradient: 4.47 on the deep end, 3.14 on the
       base purple, and 1.78 on the light end - which is why the wordmark sits on
       the deep half and never drifts down the gradient.

       At the other end of the permitted range #c9a227 manages only 2.73 on base
       purple, so it fails the one thing gold is for here.

       On white it is 2.10, which is exactly why gold is never a text colour on
       white. As a fill it is fine: ink on gold is 7.38.

       Not tenant settable. The admin side wears the product's brand; the tenant's
       colours belong to the pages their candidates see. */
  --jf-gold: #d4af37;
  --jf-gold-light: #faf3e0;
  /* -- status ------------------------------------------------------------- */
  --jf-green: #1e9e6a;
  --jf-amber: #d97706;
  --jf-red: #c0392b;
  /* The washes behind a notice, and the ink that goes on them. Tokens rather
       than literals repeated per sheet: the admin chrome needs the same danger
       wash for a failed login that the candidate pages use for a refused upload.

       The inks are darker than the status colours above them, and deliberately.
       A status colour is sized for a dot, a bar or a fill; as small text on its
       own wash it manages about 3:1, which is under the bar. These clear it:
       6.14, 6.33 and 7.93 on their own backgrounds. */
  --jf-success-bg: #e7f6ef;
  --jf-success-ink: #12674a;
  --jf-danger-bg: #fdeeec;
  --jf-danger-ink: #8c2119;
  --jf-warning-bg: #fdf6ec;
  --jf-warning-ink: #8a4b06;
  /* -- shape -------------------------------------------------------------- */
  --jf-radius: 14px;
  --jf-radius-sm: 9px;
  --jf-radius-pill: 20px;
  --jf-shadow: 0 1px 3px rgba(23, 23, 23, 0.06);
  --jf-shadow-lift: 0 8px 24px rgba(23, 23, 23, 0.1);
  /* The one card shadow, and it is not really a shadow: a hairline ring drawn
       with a spread of zero, plus a single pixel of weight underneath. Cards in
       the guide sit on paper without floating above it, and a soft blur under
       every card is what makes an interface look like a slide deck. */
  --jf-ring: 0 0 0 1px rgba(23, 23, 23, 0.08), 0 1px 0 rgba(23, 23, 23, 0.06);
  /* A thumb, not a mouse pointer. Every interactive element on a candidate
       page is at least this tall. */
  --jf-touch: 44px;
}
/* ============================================================================
   Candidate-facing page shell
   ============================================================================ */
.jf-page {
  background: var(--jf-bg);
  color: var(--jf-ink);
  min-height: 100vh;
  /* Room for the sticky call to action, so the last opening in a list is never
       hidden behind it. */
  padding-bottom: 6.5rem;
  -webkit-text-size-adjust: 100%;
}
/* The brand bar. Gradient rather than flat, matching the pitch document's hero,
   and it degrades to a solid brand colour wherever gradients are not painted. */
.jf-appbar {
  background: var(--jf-brand);
  background: linear-gradient(135deg, var(--jf-brand-dark), var(--jf-brand) 75%);
  color: var(--jf-on-brand);
}
.jf-appbar a,
.jf-appbar .btn-link {
  color: var(--jf-on-brand);
}
/* ---------------------------------------------------------------------------
   The language switcher.

   This is where the first live browser pass found two bugs with one cause. The
   bar sets color: var(--jf-on-brand) on itself, and that cascades into anything
   inside it - so a Bootstrap .btn-light rendered as a white pill with white text,
   and the dropdown menu it opened was white text on a white menu. Both were
   invisible to a structural test, which only ever asked whether the classes were
   present.

   So the switcher gets a treatment of its own rather than borrowing one: an
   outlined button that carries the bar's own text colour, and a menu that leaves
   the bar's cascade behind and goes back to ink on card.
   --------------------------------------------------------------------------- */
.jf-appbar-action {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: var(--jf-touch);
  padding: 0.4rem 0.85rem;
  border-radius: var(--jf-radius-sm);
  /* currentColor, so it tracks --jf-on-brand: white on a dark brand, ink on a
       light one, and legible on both without a second variable. */
  border: 1.5px solid currentColor;
  background: transparent;
  color: var(--jf-on-brand);
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
}
.jf-appbar-action:hover,
.jf-appbar-action:focus,
.jf-appbar-action[aria-expanded="true"] {
  /* A wash of the bar's own text colour. Works whichever way round the pair is,
       which a fixed rgba(255,255,255,...) would not. */
  background: color-mix(in srgb, currentColor 15%, transparent);
  color: var(--jf-on-brand);
}
/* The menu is not on the brand colour, so it must not inherit the brand's text
   colour. Stated rather than left to the cascade - that inheritance is the bug. */
.jf-appbar .dropdown-menu {
  background: var(--jf-card);
  border: 1px solid var(--jf-line);
  border-radius: var(--jf-radius-sm);
  box-shadow: var(--jf-shadow-lift);
  padding: 0.35rem;
  min-width: 11rem;
}
.jf-appbar .dropdown-item {
  color: var(--jf-ink);
  border-radius: 6px;
  /* A menu on a phone is a list of tap targets. */
  min-height: var(--jf-touch);
  display: flex;
  align-items: center;
  padding: 0.5rem 0.75rem;
}
.jf-appbar .dropdown-item:hover,
.jf-appbar .dropdown-item:focus {
  background: var(--jf-brand-light);
  color: var(--jf-brand-dark);
}
/* The language they are already reading in. Solid brand, with the text colour the
   derivation proved readable on it. */
.jf-appbar .dropdown-item.active,
.jf-appbar .dropdown-item:active {
  background: var(--jf-brand);
  color: var(--jf-on-brand);
}
/* The tenant's own mark, when they have uploaded one.

   Its own class, and that is the fix rather than the tidying. It was .jf-logo,
   which is also the product wordmark's wrapper class further down this file -
   two unrelated components sharing one name. The wordmark's rules were written
   second and landed on this image as well, including display:inline-flex, which
   an <img> in the flex header has no business being.

   Sized rather than bounded, which is the other half. A logo uploaded as an SVG
   commonly carries a viewBox and no width or height - it has a ratio and no
   intrinsic size - and an element like that, with only max-* constraints, in a
   flex row, is a box the browser is free to compute as nothing at all. A
   definite height gives it something to scale from; max-width then catches a
   very wide mark, and object-fit keeps it letterboxed rather than squashed.

   flex: 0 0 auto because the header is a flex container and the neighbouring
   .min-w-0 removes the automatic minimum that would otherwise protect this. */
.jf-brand-logo {
  height: 40px;
  max-width: 190px;
  width: auto;
  flex: 0 0 auto;
  object-fit: contain;
}
.jf-appbar-title {
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.25;
}
.jf-appbar-sub {
  font-size: 0.78rem;
  opacity: 0.85;
}
/* Reading widths. A candidate page is one column on a phone and must not become a
   wall of text on a laptop; a kiosk is a desk-mounted tablet and gets more room. */
.jf-narrow {
  max-width: 34rem;
  margin-left: auto;
  margin-right: auto;
}
.jf-form {
  max-width: 40rem;
  margin-left: auto;
  margin-right: auto;
}
.jf-kiosk-width {
  max-width: 44rem;
  margin-left: auto;
  margin-right: auto;
}
/* ============================================================================
   The logo
   ----------------------------------------------------------------------------
   One asset, three shapes.

   Full, for anywhere with room for it. Compact, for the minimized sidebar rail -
   which is about seventy pixels wide, where the full lockup would either wrap or
   be sliced through the middle of a word; that one shows the mark alone, by
   clipping the image rather than by shipping a second file that could drift from
   this one. And a knockout, for the login page, where the logo's own purple sits
   on the brand gradient and would disappear into it.

   The knockout is a filter rather than a white PNG for the same reason the crop
   is a crop: one asset, so a new logo replaces one file and every surface follows.
   brightness(0) makes every pixel black and invert(1) makes it white, and the
   alpha channel is untouched - which is exactly a reverse of a single-colour
   lockup.
   ============================================================================ */
.jf-logo {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}
.jf-logo:hover,
.jf-logo:focus {
  text-decoration: none;
}
.jf-logo img {
  display: block;
  width: auto;
}
/* Sizes. Display for the login page, small for a header or sidebar slot. */
.jf-logo-lg img {
  height: 58px;
}
.jf-logo-sm img {
  height: 30px;
}
/* The mark on its own: the image at full height in a box the width of the glyph,
   with the rest of the lockup clipped off. The mark is 320 of the artwork's 1164
   columns, so the box is .87 of its height - a ratio rather than a pixel count,
   so the two sizes above cannot drift apart from it. */
.jf-logo-compact {
  overflow: hidden;
}
.jf-logo-compact.jf-logo-sm {
  width: 26px;
}
.jf-logo-compact.jf-logo-lg {
  width: 50px;
}
/* On the brand gradient the logo's own purple has nothing to stand on. */
.jf-logo-on-brand img {
  filter: brightness(0) invert(1);
}
/* ============================================================================
   Cards
   ============================================================================ */
.jf-card {
  background: var(--jf-card);
  border: 1px solid var(--jf-line);
  border-radius: var(--jf-radius);
  box-shadow: var(--jf-shadow);
}
.jf-card + .jf-card {
  margin-top: 1.25rem;
}
.jf-card-body {
  padding: 1.375rem;
}
.jf-card-head {
  padding: 1rem 1.375rem;
  border-bottom: 1px solid var(--jf-line);
  font-weight: 700;
  font-size: 1.0625rem;
}
/* Rows inside a card that reads as a list - the openings under a category. */
.jf-row + .jf-row {
  border-top: 1px solid var(--jf-line);
}
.jf-row {
  padding: 1rem 1.375rem;
}
/* ============================================================================
   Type
   ============================================================================ */
.jf-h1 {
  font-size: 1.75rem;
  line-height: 1.2;
  font-weight: 700;
  color: var(--jf-ink);
}
.jf-h2 {
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--jf-ink);
}
.jf-lede {
  color: var(--jf-muted);
  font-size: 1rem;
}
.jf-muted {
  color: var(--jf-muted);
}
.jf-fine {
  color: var(--jf-muted);
  font-size: 0.78rem;
  line-height: 1.5;
}
/* The uppercase brand kicker above a section heading. */
.jf-kicker {
  color: var(--jf-brand);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
/* ---------------------------------------------------------------------------
   Colour utilities. These exist so that a view never carries a style attribute:
   the rule is that markup names a role, and only this file knows what colour a
   role is. A test enforces the hex half of that; these classes are what make the
   rule liveable.
   --------------------------------------------------------------------------- */
.jf-text-brand {
  color: var(--jf-brand);
}
.jf-text-success {
  color: var(--jf-green);
}
.jf-text-warning {
  color: var(--jf-amber);
}
.jf-text-danger {
  color: var(--jf-red);
}
.jf-text-ink {
  color: var(--jf-ink);
}
.jf-bg-brand-light {
  background: var(--jf-brand-light);
}
a.jf-text-brand:hover {
  color: var(--jf-brand-dark);
}
/* ============================================================================
   Buttons
   ============================================================================ */
.jf-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: var(--jf-touch);
  padding: 0.7rem 1.15rem;
  border: 1.5px solid transparent;
  border-radius: var(--jf-radius-sm);
  background: var(--jf-brand);
  color: var(--jf-on-brand);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease-in-out;
}
.jf-btn:hover,
.jf-btn:focus {
  background: var(--jf-brand-dark);
  color: var(--jf-on-brand);
  text-decoration: none;
}
.jf-btn:disabled,
.jf-btn.disabled {
  opacity: 0.55;
  cursor: default;
}
.jf-btn-ghost {
  background: var(--jf-card);
  color: var(--jf-brand);
  border-color: var(--jf-brand);
}
.jf-btn-ghost:hover,
.jf-btn-ghost:focus {
  background: var(--jf-brand-light);
  color: var(--jf-brand-dark);
}
.jf-btn-block {
  display: flex;
  width: 100%;
}
/* Visible focus, everywhere, on the brand colour rather than the browser's blue -
   which on some brand colours is nearly invisible. Never removed: keyboard and
   switch users have no other way of knowing where they are. */
.jf-page :focus-visible,
.jf-brandable :focus-visible {
  outline: 3px solid var(--jf-brand);
  outline-offset: 2px;
}
/* The sticky action bar at the bottom of a candidate page. */
.jf-cta-bar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  padding: 0.75rem 0 calc(0.75rem + env(safe-area-inset-bottom));
  background: rgba(255, 255, 255, 0.97);
  border-top: 1px solid var(--jf-line);
}
/* ============================================================================
   Pills and chips
   ============================================================================ */
/* A pill states a status. Solid, small, and it carries its own colour by
   modifier - the default is the brand. */
.jf-pill {
  display: inline-block;
  border-radius: var(--jf-radius-pill);
  padding: 0.2rem 0.75rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  background: var(--jf-brand);
  color: var(--jf-on-brand);
}
.jf-pill-success {
  background: var(--jf-green);
  color: #ffffff;
}
.jf-pill-warning {
  background: var(--jf-amber);
  color: #ffffff;
}
.jf-pill-quiet {
  background: var(--jf-brand-light);
  color: var(--jf-brand-dark);
}
/* A chip labels a thing rather than a state: an employment type, a category, a
   count. Tinted, never solid, so a row of them does not read as six alarms. */
.jf-chip {
  display: inline-block;
  border-radius: var(--jf-radius-pill);
  padding: 0.15rem 0.6rem;
  font-size: 0.72rem;
  font-weight: 600;
  background: var(--jf-brand-light);
  color: var(--jf-brand-dark);
  white-space: nowrap;
}
.jf-chip-neutral {
  background: var(--jf-bg);
  color: var(--jf-muted);
  border: 1px solid var(--jf-line);
}
/* ============================================================================
   Stat tiles
   ============================================================================ */
.jf-stat-tile {
  background: var(--jf-card);
  border: 1px solid var(--jf-line);
  border-radius: 12px;
  padding: 0.875rem 1rem;
}
.jf-stat-tile b {
  display: block;
  font-size: 1.6rem;
  line-height: 1.15;
  font-weight: 700;
}
.jf-stat-tile span {
  font-size: 0.78rem;
  color: var(--jf-muted);
}
/* The one tile that is shouting. Amber rather than red: a bottleneck is a thing
   to go and look at, not a failure. */
.jf-stat-tile.jf-hot {
  border-color: var(--jf-amber);
  background: #fdf6ec;
}
.jf-stat-tile.jf-hot span {
  color: var(--jf-amber);
  font-weight: 600;
}
/* ============================================================================
   Form fields
   ============================================================================ */
.jf-field {
  margin-bottom: 1.15rem;
}
.jf-label {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--jf-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 0.3rem;
}
.jf-label.jf-required::after {
  content: " *";
  color: var(--jf-brand);
}
.jf-input,
.jf-page .form-control,
.jf-page .form-select {
  width: 100%;
  min-height: var(--jf-touch);
  border: 1.5px solid var(--jf-line);
  border-radius: var(--jf-radius-sm);
  padding: 0.6rem 0.75rem;
  font-size: 1rem;
  color: var(--jf-ink);
  background: var(--jf-card);
}
.jf-input:focus,
.jf-page .form-control:focus,
.jf-page .form-select:focus {
  border-color: var(--jf-brand);
  box-shadow: none;
}
/* Filled by the resume parser rather than typed. The pitch document tints these,
   and the tint is what makes "the AI did this, check it" legible without a
   sentence of explanation. */
.jf-input.jf-prefilled {
  border-color: var(--jf-brand);
  background: var(--jf-brand-light);
}
.jf-help {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.78rem;
  color: var(--jf-muted);
}
/* Checkboxes on a candidate page are targets, not decorations. */
.jf-page .form-check-input {
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 0.1rem;
  border-color: var(--jf-line);
}
.jf-page .form-check-input:checked {
  background-color: var(--jf-brand);
  border-color: var(--jf-brand);
}
.jf-page .form-check {
  min-height: var(--jf-touch);
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding-left: 0;
}
.jf-page .form-check .form-check-input {
  flex: 0 0 auto;
  margin-left: 0;
}
.jf-page .form-check-label {
  cursor: pointer;
}
/* The consent block. Bordered and tinted so it reads as a thing being agreed to
   rather than as another checkbox in a list. */
.jf-consent {
  border: 1.5px solid var(--jf-brand);
  background: var(--jf-brand-light);
  border-radius: var(--jf-radius-sm);
  padding: 0.875rem 1rem;
}
.jf-consent .form-check-label {
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--jf-ink);
}
/* The honeypot's hiding place. Off-screen rather than display:none, because some
   bots skip inputs they can tell are hidden. */
.jf-offscreen {
  position: absolute;
  left: -10000px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
/* The availability grid. Each cell is a tap target on a phone, which a default
   table cell is not. */
.jf-shift-grid td .form-check-input {
  width: 1.5rem;
  height: 1.5rem;
}
.jf-shift-grid td,
.jf-shift-grid th {
  padding: 0.5rem 0.25rem;
  vertical-align: middle;
}
/* ============================================================================
   Notices
   ============================================================================ */
.jf-notice {
  border-radius: var(--jf-radius-sm);
  padding: 0.875rem 1rem;
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  font-size: 0.9rem;
  border: 1px solid var(--jf-line);
  background: var(--jf-card);
}
.jf-notice-brand {
  border-color: var(--jf-brand);
  background: var(--jf-brand-light);
  color: var(--jf-brand-dark);
}
.jf-notice-success {
  border-color: var(--jf-green);
  background: #edf8f3;
  color: #106844;
}
.jf-notice-warning {
  border-color: var(--jf-amber);
  background: #fdf6ec;
  color: #8a4b04;
}
.jf-notice-danger {
  border-color: var(--jf-red);
  background: var(--jf-danger-bg);
  color: var(--jf-danger-ink);
}
/* ============================================================================
   The pass
   ----------------------------------------------------------------------------
   The one screen a candidate screenshots and shows to a stranger, so it is the
   one that most has to look like the property. The QR itself stays black on
   white at all times - branding lives around it, never in it, because a tinted
   code is a code that a cheap scanner in bad lobby light cannot read.
   ============================================================================ */
.jf-pass {
  text-align: center;
  overflow: hidden;
}
.jf-pass-head {
  background: var(--jf-brand);
  background: linear-gradient(135deg, var(--jf-brand-dark), var(--jf-brand) 75%);
  color: var(--jf-on-brand);
  padding: 1.125rem 1rem;
}
.jf-pass-body {
  padding: 1.5rem 1.125rem 1.75rem;
}
.jf-pass-qr {
  display: inline-block;
  background: #ffffff;
  border: 10px solid #ffffff;
  outline: 2px solid var(--jf-line);
  border-radius: 6px;
  line-height: 0;
}
.jf-pass-qr img {
  display: block;
  width: 240px;
  max-width: 62vw;
  height: auto;
}
.jf-pass-kiosk .jf-pass-qr img {
  width: 420px;
  max-width: 80vw;
}
.jf-pass-name {
  font-size: 1.35rem;
  font-weight: 700;
  margin-top: 0.9rem;
}
.jf-pass-meta {
  font-size: 0.82rem;
  color: var(--jf-muted);
  margin-top: 0.35rem;
}
/* The code in text, for the scanner that will not focus. Monospaced so a member
   of staff can read it out without losing their place. */
.jf-pass-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.75rem;
  color: var(--jf-muted);
  word-break: break-all;
  margin-top: 0.5rem;
}
/* ============================================================================
   The day-of brand strip is gone from the staff screens
   ----------------------------------------------------------------------------
   It was a purple band across the top of the station view, the coordinator board
   and the fair dashboard, and it was designed for a neutral-grey admin that no
   longer exists. Three things ended it: the paper skin carries the product's
   brand now, the strip repeated the page title word for word underneath it, and
   its full-bleed sizing broke against the new layout - it escaped the content
   gutter and ran off the right edge.

   The rule it existed for has not changed: a candidate looks at the property's
   brand, and the kiosk and the public pages still wear it. What changed is that a
   member of staff looking at their own tool does not need to be told whose
   building they are standing in.
   ============================================================================ */
/* ============================================================================
   Admin branding screen
   ----------------------------------------------------------------------------
   The preview renders with the real component classes rather than a mock-up of
   them, so it cannot drift from the page it is previewing. .jf-brandable is the
   scope the overriding variables are written into: inside it the property's
   colours apply, outside it Metronic keeps its own.
   ============================================================================ */
.jf-swatch {
  height: 46px;
  border-radius: var(--jf-radius-sm);
  border: 1px solid var(--jf-line);
}
/* A stand-in for a QR code, drawn rather than generated. Its whole job is to show
   that the code stays black on white whatever colour the property picks. */
.jf-qr-stub {
  width: 118px;
  height: 118px;
  background: repeating-linear-gradient(0deg, #111 0 6px, transparent 6px 12px), repeating-linear-gradient(90deg, #111 0 6px, #fff 6px 12px);
}
/* ============================================================================
   Wall display
   ----------------------------------------------------------------------------
   The coordinator board runs on a TV at the side of a ballroom, read from ten or
   fifteen feet away. Everything on it scales up together at the width a TV
   reports, rather than being sized for the laptop it was built on.
   ============================================================================ */
@media (min-width: 1600px) {
  .jf-wall {
    font-size: 1.2rem;
  }
  .jf-wall .jf-stat-tile b {
    font-size: 2.6rem;
  }
  .jf-wall .jf-stat-tile span {
    font-size: 1.05rem;
    /* Muted grey is legible on a laptop at arm's length and is not from
           across a room. On the wall it goes to full ink. */
    color: var(--jf-ink);
  }
  .jf-wall .jf-pill,
  .jf-wall .jf-chip {
    font-size: 0.95rem;
    padding: 0.25rem 0.85rem;
  }
  /* The coordinator board's own markup, which predates this stylesheet. Its
       totals and column headers get the same treatment as a stat tile: the
       number grows, and the label under it stops being grey. */
  .jf-wall .board-total .fs-1 {
    font-size: 3.4rem;
  }
  .jf-wall .board-total .text-muted,
  .jf-wall .board-column .text-muted {
    color: var(--jf-ink) !important;
    font-size: 1rem;
  }
  .jf-wall .board-column {
    min-width: 19rem;
  }
  .jf-wall .board-card {
    font-size: 1.05rem;
  }
}
/* ============================================================================
   Small screens
   ============================================================================ */
@media (max-width: 400px) {
  .jf-card-body,
  .jf-row {
    padding: 1rem;
  }
  .jf-h1 {
    font-size: 1.5rem;
  }
  .jf-pass-qr img {
    width: 200px;
  }
}
@media print {
  .jf-cta-bar,
  .jf-appbar {
    display: none;
  }
  .jf-page {
    background: #ffffff;
    padding-bottom: 0;
  }
  .jf-card {
    box-shadow: none;
  }
}
