/* ==================================================================================================
 * b-foundation.css — Candidate B, "The living board", as the site's foundation.
 *
 * WHAT THIS FILE IS
 * A token + component LAYER that sits ON TOP of /css/theme.css. It never edits theme.css and never
 * redefines a --cc-* token, so:
 *   • deleting this one <link> returns the whole site to exactly its current look, and
 *   • a page that has not been converted yet is untouched — this file only styles the chrome
 *     (header/footer), the one job-row component, and the primitives a page opts into by class.
 *
 * LOAD ORDER (views/layout.ejs): fonts → kds tokens → kds components → theme.css → THIS FILE →
 * per-page extraCss. It is deliberately BEFORE the page stylesheets: this is a foundation, and a
 * page must still be able to override it.
 *
 * THE SYSTEM IN ONE PARAGRAPH (from views/preview/home-b.ejs)
 * A light page with a lot of air, navy ink and hairline rules, carrying ONE dark object — the board
 * — which is the page's subject. Depth comes from 1px lines and a single long shadow under that one
 * object, never from a shadow on every card. There is ONE gradient. Maple red appears exactly three
 * times: the live pulse, the "New" marker, the one primary button. Every number sits in a tabular
 * column so money lines up like a ledger.
 *
 * NAMESPACE
 * Everything here is prefixed `b-` (classes) / `--b-` (tokens). Nothing in the existing stylesheets
 * uses that prefix, so there is no collision and no duplicated rule: theme.css owns `.job-card`,
 * this file owns `.b-jobrow`. Markup carries BOTH, which is what makes the degrade-on-removal
 * property true.
 * ================================================================================================= */

/* ==================================================================================================
   1. TOKENS
   ================================================================================================= */
:root {
  /* ---- brand. Aliases of theme.css, NOT new values. Change the brand in theme.css, not here. ---- */
  --b-navy:      var(--cc-navy);        /* #1F3A5F */
  --b-navy-700:  var(--cc-navy-700);    /* #16304F */
  --b-navy-50:   var(--cc-navy-50);     /* #F1F5FA */
  --b-red:       var(--cc-red);         /* #D42E2E — see "red discipline" below */
  --b-red-700:   var(--cc-red-700);     /* #B32222 */

  /* ---- surface / ink ramp (light). Measured against #FFFFFF. ---------------------------------- */
  --b-bg:    #FFFFFF;
  --b-bg-2:  #F7F9FC;                   /* quiet band, row hover on light */
  --b-ink:   #14263C;                   /* body + headings            15.3:1 */
  --b-ink-2: #45596F;                   /* secondary text              7.2:1 */
  --b-ink-3: #5A6B7E;                   /* meta, captions, units       5.5:1 */
  /* Nothing lighter than --b-ink-3 may carry a text node. There is no --b-ink-4 on purpose. */

  /* ---- the board (dark). Measured against --b-bd. --------------------------------------------- */
  --b-bd:      #0E1D31;                 /* the panel */
  --b-bd-2:    #14263E;                 /* row hover inside the panel */
  --b-bd-fg:   #F2F7FD;                 /* titles, wages              15.7:1 */
  --b-bd-fg-2: #AFC2DA;                 /* company, location           9.3:1 */
  --b-bd-fg-3: #90A6C2;                 /* time, units, counts         6.8:1 (6.1:1 on --b-bd-2) */

  /* ---- the hairline scale. Depth is lines, not shadows. --------------------------------------- */
  --b-line:      #E3E9F1;               /* the default rule */
  --b-line-2:    #CBD6E4;               /* a rule that must be seen: input borders, ghost buttons */
  --b-bd-line:   rgba(255, 255, 255, .085);   /* the same two steps, on the board */
  --b-bd-line-2: rgba(255, 255, 255, .16);
  --b-hair:    1px solid var(--b-line);
  --b-hair-2:  1px solid var(--b-line-2);
  --b-hair-on: 1px solid var(--b-bd-line);

  /* ---- the ONE shadow and the ONE gradient ---------------------------------------------------- */
  /* Used by .b-board and by nothing else. If a second element needs a shadow, the answer is a rule. */
  --b-shadow: 0 1px 0 rgba(255,255,255,.06) inset,
              0 30px 60px -34px rgba(14,29,49,.55),
              0 2px 6px -2px rgba(14,29,49,.25);
  --b-wash: radial-gradient(80% 120% at 12% 0%, rgba(31,58,95,.075), rgba(31,58,95,0) 60%);

  /* ---- type ----------------------------------------------------------------------------------- */
  --b-sans: var(--kds-font-sans);
  --b-disp: var(--cc-font-display);
  --b-t-xs:   .6875rem;   /* 11px — eyebrows, the "New" marker. Uppercase + tracked only. */
  --b-t-sm:   .75rem;     /* 12px — relative time, units, footnotes */
  --b-t-md:   .8125rem;   /* 13px — row meta, captions */
  --b-t-base: .875rem;    /* 14px — secondary UI text */
  --b-t-ui:   .9375rem;   /* 15px — nav, buttons, list items, the row wage */
  --b-t-body: 1rem;       /* 16px — body copy, the row title */
  --b-t-lead: 1.125rem;   /* 18px */
  --b-t-h3:   1.0625rem;
  --b-t-h2:   clamp(1.6rem, 3vw, 2.125rem);
  --b-t-h1:   clamp(2rem, 5.6vw, 2.75rem);
  --b-track-caps: .1em;   /* the one tracking value for uppercase labels */

  /* ---- rhythm --------------------------------------------------------------------------------- */
  --b-r:    14px;         /* the board, and anything board-sized */
  --b-r-md: 10px;         /* buttons, inputs */
  --b-r-sm: 6px;          /* tags, the "New" marker */
  --b-pad-row: 12px 20px;
  --b-e: cubic-bezier(.22, .61, .36, 1);
  --b-tap: 44px;          /* every interactive target, at every breakpoint */

  /* ---- focus. TWO rings, because the board clips its own overflow. ---------------------------- */
  /* On a light surface the ring sits OUTSIDE the element.                                          */
  --b-ring:        2px solid var(--b-navy);
  --b-ring-offset: 3px;
  /* On a dark surface it sits INSIDE: .b-board has overflow:hidden, so an outside ring is sliced
     off at the first and last row. This is the single most important rule in this file.            */
  --b-ring-on:        2px solid #FFFFFF;
  --b-ring-offset-on: -3px;

  /* ---- audience colours. ALIASES of theme.css. See §7 — do not fork these here. ---------------- */
  --b-aud-professionals:  var(--cc-aud-professionals);
  --b-aud-new_immigrants: var(--cc-aud-new_immigrants);
  --b-aud-indigenous:     var(--cc-aud-indigenous);
  --b-aud-refugees:       var(--cc-aud-refugees);
  --b-aud-youth:          var(--cc-aud-youth);
}

/* ==================================================================================================
   2. RED DISCIPLINE
   Maple red may appear exactly three times in a view, and nowhere else:
     1. the live pulse          .b-pulse
     2. the "New" marker        .b-new            (72 hours only, or it stops meaning anything)
     3. the one primary action  .b-btn--primary   (ONE per view — never two, never in the nav)
   theme.css additionally paints link:hover, .eyebrow, .req and .badge--danger red. Those are
   pre-existing and page-owned; this file does not add a fourth use to the chrome or the row.
   A converting agent that needs a red primary on its page must check nothing else on that page
   already claims it.
   ================================================================================================= */

/* ==================================================================================================
   3. UTILITIES
   ================================================================================================= */

/* Tabular figures. EVERY money value and EVERY count wears this, so columns line up like a ledger. */
.b-tab,
.b-jobrow__wage,
.b-jobrow__when time,
.b-ticker strong,
.b-num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

.b-num { color: var(--b-navy); font-weight: 700; }

/* The one gradient, as a utility. Applies the wash behind a hero without owning its layout. */
.b-wash { position: relative; isolation: isolate; }
.b-wash::before {
  content: ""; position: absolute; inset: -80px 0 auto; height: 520px; z-index: -1;
  pointer-events: none; background: var(--b-wash);
}

/* The live pulse — maple red, use 1 of 3. */
.b-pulse { position: relative; display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--b-red); flex: none; }
.b-pulse::after { content: ""; position: absolute; inset: -4px; border-radius: 50%; border: 1px solid var(--b-red); opacity: 0; }
.b-pulse--sm { width: 6px; height: 6px; }
@media (prefers-reduced-motion: no-preference) {
  .b-pulse::after { animation: b-pulse 2.6s var(--b-e) infinite; }
}
@keyframes b-pulse { 0% { transform: scale(.55); opacity: .85; } 70%, 100% { transform: scale(1.6); opacity: 0; } }

/* A 3px separator dot. Inherits currentColor so it works on both surfaces. */
.b-dot { display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: .55; flex: none; vertical-align: middle; }

.b-arr { display: inline-block; transition: transform .18s var(--b-e); }
a:hover > .b-arr, a:hover .b-arr { transform: translateX(4px); }

/* ==================================================================================================
   4. FOCUS — visible everywhere, on both surfaces
   ================================================================================================= */
/* theme.css already sets a 2px navy ring at offset 2. This refines it and adds the dark-surface and
   inside-the-board cases, which theme.css has no concept of. */
:focus-visible { outline: var(--b-ring); outline-offset: var(--b-ring-offset); border-radius: 4px; }

/* Any dark surface: white ring. */
.b-on-dark :focus-visible,
.b-board :focus-visible,
.b-hdr .b-acct[open] > .b-acct__menu :focus-visible { outline: var(--b-ring-on); }

/* The board clips. Draw the ring INSIDE, or the first/last row loses half of it. */
.b-board :focus-visible { outline-offset: var(--b-ring-offset-on); border-radius: var(--b-r-sm); }

/* The skip link keeps theme.css's behaviour and gains B's shape. */
.b-skip.skip-link { padding: 12px 16px; border-radius: 8px; font-weight: 600; min-height: var(--b-tap); display: inline-flex; align-items: center; }
.b-skip.skip-link:focus { left: 16px; }

/* ==================================================================================================
   5. BUTTONS
   .b-btn is additive: markup keeps .kds-btn so the site still has buttons without this file.
   ================================================================================================= */
.b-btn {
  --b-bh: var(--b-tap);
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--b-bh); padding: 0 18px; border: 1px solid transparent; border-radius: var(--b-r-md);
  font: 600 var(--b-t-ui)/1 var(--b-sans); letter-spacing: -.006em; cursor: pointer; white-space: nowrap;
  text-decoration: none;
  transition: background .16s var(--b-e), border-color .16s var(--b-e), color .16s var(--b-e), box-shadow .16s var(--b-e);
}
/* Maple red, use 3 of 3. ONE of these per view. */
.b-btn--primary { background: var(--b-red); color: #fff; box-shadow: inset 0 1px 0 rgba(255,255,255,.22), 0 1px 2px rgba(20,38,60,.18); }
.b-btn--primary:hover { background: var(--b-red-700); color: #fff; box-shadow: inset 0 1px 0 rgba(255,255,255,.22), 0 6px 16px -6px rgba(212,46,46,.55); }
.b-btn--brand { background: var(--b-navy); color: #fff; }
.b-btn--brand:hover { background: var(--b-navy-700); color: #fff; }
.b-btn--ghost { border-color: var(--b-line-2); color: var(--b-navy); background: #fff; }
.b-btn--ghost:hover { border-color: var(--b-navy); background: var(--b-navy-50); color: var(--b-navy); }
.b-btn--quiet { color: #fff; border-color: rgba(255,255,255,.3); background: transparent; }
.b-btn--quiet:hover { border-color: #fff; background: rgba(255,255,255,.08); color: #fff; }
.b-btn--lg { --b-bh: 52px; padding: 0 26px; font-size: var(--b-t-body); }
.b-btn--sm { padding: 0 14px; font-size: var(--b-t-base); }   /* still 44px tall. Never shrink the target. */

/* ==================================================================================================
   6. THE BOARD — the one dark object
   A page opts in by wrapping a list of .b-jobrow in .b-board. The panel re-points the row's surface
   tokens (§8), so the SAME row component is correct inside it.
   ================================================================================================= */
.b-board {
  /* width:100% is not redundant. theme.css makes <body> a column flex container, and an auto
     left/right margin on a flex item in a column container CANCELS cross-axis stretch — the board
     then shrink-wraps to its widest nowrap row and sits as a narrow slab in the middle of the page.
     That is exactly what happened the first time this component was mounted outside .container.
     One line here saves every page agent from finding it the hard way. */
  width: 100%;
  position: relative; background: var(--b-bd); color: var(--b-bd-fg);
  border: 1px solid rgba(14,29,49,.9); border-radius: var(--b-r);
  box-shadow: var(--b-shadow);
  overflow: hidden;
}
.b-board__bar {
  display: flex; align-items: center; gap: 12px; padding: 16px 20px;
  border-bottom: var(--b-hair-on);
  background: linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,0));
}
.b-board__h { font-family: var(--b-disp); font-size: var(--b-t-ui); font-weight: 700; letter-spacing: -.008em; color: var(--b-bd-fg); margin: 0; }
.b-board__note { margin: 0 0 0 auto; font-size: var(--b-t-md); color: var(--b-bd-fg-3); }
.b-board__note .b-tab { color: var(--b-bd-fg-2); font-weight: 600; }
.b-board__foot { display: flex; align-items: center; gap: 16px; padding: 14px 20px; border-top: var(--b-hair-on); background: rgba(255,255,255,.022); }
.b-board__foot-q { margin-left: auto; font-size: var(--b-t-sm); color: var(--b-bd-fg-3); }

/* The LIVE chip. Not a fourth use of red: it is the pulse's own label and carries the pulse. */
.b-live {
  display: inline-flex; align-items: center; gap: 7px;
  font: 600 var(--b-t-xs)/1 var(--b-sans); letter-spacing: var(--b-track-caps); text-transform: uppercase;
  color: #F7C9C9; padding: 5px 9px 5px 7px; border: 1px solid rgba(212,46,46,.5); border-radius: 999px;
  background: rgba(212,46,46,.14);                   /* 10.6:1 */
}
.b-rows { list-style: none; margin: 0; padding: 0; display: block; }
.b-board .b-rows > li + li,
.b-board .b-jobrow + .b-jobrow { border-top: var(--b-hair-on); }

.b-more { display: inline-flex; align-items: center; gap: 8px; min-height: var(--b-tap); font-weight: 600; font-size: var(--b-t-ui); color: var(--b-bd-fg); text-decoration: none; }
.b-board__foot .b-more:hover { color: #fff; }

/* ==================================================================================================
   7. AUDIENCE MARKS — the ONLY place the five audience colours may appear
   --------------------------------------------------------------------------------------------------
   KNOWN BRAND DEFECT (flagged, deliberately NOT fixed here):
     theme.css maps BOTH --cc-aud-new_immigrants AND --cc-aud-refugees to --cc-teal (#35A8B0).
     The brand has five audiences and four hues, because the logo only ever had four. As dots, those
     two audiences are indistinguishable — and on the board, where the dot is the only mark, they are
     indistinguishable with no text to recover the meaning from.
     This file ALIASES theme.css exactly (§1) rather than quietly diverging, so the defect is visible
     and fixed in ONE place. The proposed fix, for theme.css, owner's call:

         --cc-aud-refugees: #8B5FB5;   /* was var(--cc-teal) */
     /*  #8B5FB5 "prairie violet": 4.77:1 on #FFFFFF and 3.55:1 on the board #0E1D31, so the dot
         clears 3:1 (SC 1.4.11) on BOTH surfaces — which the existing teal, green and orange do not
         do unaided on white. Distinct in hue from navy, teal, green, orange and red; it is not red,
         so the three-uses rule is intact.
         Fallback if a sixth hue is refused: keep both teal and make refugees a HOLLOW dot
         (.b-aud--refugees { background: transparent; box-shadow: inset 0 0 0 2px <teal>; }). Shape
         is the only other channel available, and the legend must then show it. */
   Until that lands, any view showing bare dots MUST also show .b-audkey.
   ================================================================================================= */
.b-auds { display: inline-flex; align-items: center; gap: 3px; vertical-align: middle; }
.b-aud {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--b-c, var(--b-navy));
  /* The ring is what gives a 7px dot a ≥3:1 edge on white: teal 2.9:1 bare → 5.1:1 ringed,
     green 2.4:1 → 4.5:1, orange 2.0:1 → 3.8:1. */
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--b-c, var(--b-navy)) 72%, #000);
}
.b-aud--professionals  { --b-c: var(--b-aud-professionals); }
.b-aud--new_immigrants { --b-c: var(--b-aud-new_immigrants); }
.b-aud--indigenous     { --b-c: var(--b-aud-indigenous); }
.b-aud--refugees       { --b-c: var(--b-aud-refugees); }
.b-aud--youth          { --b-c: var(--b-aud-youth); }
/* On the board the hues are bright enough against #0E1D31 (teal 6.0:1, green 6.9:1, orange 8.3:1)
   but navy is not (1.5:1) — so every dot takes a light ring there instead. 5.9:1. */
.b-board .b-aud,
.b-on-dark .b-aud { box-shadow: 0 0 0 1px rgba(255,255,255,.55); }

/* The key. Decodes the dots AND is the fastest filter into the five audiences. */
.b-audkey { border-top: var(--b-hair); padding-top: 18px; }
.b-audkey__h { font-size: var(--b-t-xs); font-weight: 600; letter-spacing: var(--b-track-caps); text-transform: uppercase; color: var(--b-ink-3); margin: 0 0 8px; }
.b-audkey ul { display: flex; flex-wrap: wrap; gap: 0 16px; list-style: none; margin: 0; padding: 0; }
.b-audkey a { display: inline-flex; align-items: center; gap: 8px; min-height: var(--b-tap); font-size: var(--b-t-base); color: var(--b-ink-2); text-decoration: none; transition: color .14s var(--b-e); }
.b-audkey a:hover { color: var(--b-navy); }

/* ==================================================================================================
   8. THE JOB ROW — ONE component, three partials, two surfaces, two container widths
   --------------------------------------------------------------------------------------------------
   Markup: views/public/_job-card.ejs (used directly and through views/public/_job-row.ejs and
   views/seeker/_jobcard.ejs). Every element carries BOTH its legacy .job-card__* class and its
   .b-jobrow__* class, so deleting this file returns the current card verbatim.

   Field order, B's board row:
       title [New]                                wage — right, tabular
       company · location · type · [remote]       audience dots + relative time
       [chips: exceptions only]
       [actions]

   WHY CONTAINER QUERIES AND NOT MEDIA QUERIES
   This same partial renders in a 270px grid cell on the home page AND in a 760px results column on
   /jobs AND in a 1100px board — at the SAME viewport width. A viewport media query cannot tell those
   apart, and the first build of this file proved it: at 1440 the home grid put the title and the wage
   on top of each other and wrapped the company name one word per line. The row therefore makes
   ITSELF the container (`container-type: inline-size`) and its CHILDREN place themselves with
   grid-column / grid-row, which a container query can set. One component, no wrapper element, no
   second markup path.
   The default (no @container support, or a narrow container) is the STACKED layout — readable at any
   width — and the two-column row is the enhancement. The fallback never goes the dangerous way.

   ROW MODE vs CARD MODE
   A list is a row; a grid cell is a card. The row sheds the card box only in list contexts —
   .b-board, .b-jobrows, [data-job-row] (which is /jobs, and only /jobs) and the explicit
   .b-jobrow--row. Everywhere else it keeps theme.css's card box, so the home page, the seeker
   dashboard, the company page and the posting page's "similar jobs" grid are NOT restyled by this
   file. A page agent converting one of those opts in by wrapping its list in .b-jobrows.
   ================================================================================================= */
.b-jobrow {
  /* surface contract — the whole light/dark story is these six lines */
  --b-row-fg:    var(--b-ink);
  --b-row-fg-2:  var(--b-ink-2);
  --b-row-fg-3:  var(--b-ink-3);
  --b-row-line:  var(--b-line);
  --b-row-hover: var(--b-bg-2);
  --b-row-edge:  var(--b-navy);

  container-type: inline-size;
  container-name: jobrow;
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; column-gap: 20px; row-gap: 6px;
  min-height: var(--b-tap);
  color: var(--b-row-fg);
  transition: background .16s var(--b-e), border-color .16s var(--b-e);
}
/* Stacked by default: every part owns the full width, in source order. */
.b-jobrow > * { grid-column: 1 / -1; }

/* Dark: inside the board, or forced with cardOnDark. */
.b-board .b-jobrow,
.b-jobrow--on-dark {
  --b-row-fg:    var(--b-bd-fg);
  --b-row-fg-2:  var(--b-bd-fg-2);
  --b-row-fg-3:  var(--b-bd-fg-3);
  --b-row-line:  var(--b-bd-line);
  --b-row-hover: var(--b-bd-2);
  --b-row-edge:  var(--b-bd-fg-2);
}

/* ---- ROW MODE: shed the card box, take the row padding and the hairline ------------------------ */
.b-board .b-jobrow,
.b-jobrows .b-jobrow,
.b-jobrow[data-job-row],
.b-jobrow--row {
  background: none; border: 0; border-radius: 0; box-shadow: none;
  padding: var(--b-pad-row);
}
.b-board .b-jobrow + .b-jobrow,
.b-jobrows .b-jobrow + .b-jobrow,
.b-jobrow[data-job-row] + .b-jobrow[data-job-row],
.b-jobrow--row + .b-jobrow--row { border-top: 1px solid var(--b-row-line); }
.b-jobrows { list-style: none; margin: 0; padding: 0; }

/* Hover. Depth is a line, never a shadow — in BOTH modes. */
.b-jobrow:hover { box-shadow: none; }
.b-board .b-jobrow:hover,
.b-jobrows .b-jobrow:hover,
.b-jobrow[data-job-row]:hover,
.b-jobrow--row:hover { background: var(--b-row-hover); }
.b-jobrow:not([data-job-row]):not(.b-jobrow--row):hover { border-color: var(--b-line-2); }

/* The leading-edge keyline: the row lights up on its own edge. Row mode only — inside a card box it
   would be a bar floating against a border. */
.b-board .b-jobrow::before,
.b-jobrows .b-jobrow::before,
.b-jobrow[data-job-row]::before,
.b-jobrow--row::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; background: var(--b-row-edge);
  transform: scaleY(0); opacity: 0; transition: transform .2s var(--b-e), opacity .2s var(--b-e);
}
.b-jobrow:hover::before,
.b-jobrow:focus-within::before { transform: scaleY(1); opacity: .5; }

/* ---- title ------------------------------------------------------------------------------------ */
.b-jobrow__title {
  margin: 0;
  font: 600 var(--b-t-body)/1.3 var(--b-sans); letter-spacing: -.011em; color: var(--b-row-fg);
}
.b-jobrow__title a { color: inherit; text-decoration: none; }
.b-jobrow__title a:hover { color: inherit; }
/* The whole row is the link target. theme.css already draws this ::after for .job-card__title a;
   inline-size containment makes .b-jobrow the containing block for it, so it covers the row and
   nothing else. The actions strip sits above it on z-index. */
.b-jobrow__title a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }

/* "New" — maple red, use 2 of 3. 72 hours only. White on #D42E2E is 5.0:1. */
.b-new {
  display: inline-block; margin-left: 8px; padding: 2px 7px; border-radius: var(--b-r-sm);
  font: 700 .625rem/1.35 var(--b-sans); letter-spacing: .05em; text-transform: uppercase;
  color: #fff; background: var(--b-red); vertical-align: 1px;
}

/* ---- meta line -------------------------------------------------------------------------------- */
.b-jobrow__meta {
  margin: 0; min-width: 0;
  display: flex; align-items: center; flex-wrap: wrap; gap: 2px 7px;
  font-size: var(--b-t-md); color: var(--b-row-fg-2);
}
/* Each separator dot travels INSIDE the part it introduces (.b-bit), so a wrapping line can never
   be left ending in an orphaned dot. That bug was in the first build of this file. */
.b-bit { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
/* Narrow rows wrap the meta line; a part must move to the next line whole, never squeeze until
   "Full-time" breaks one word per line (seen in the posting's "More jobs" grid, 2026-10-16). */
.b-jobrow__meta > .b-bit { flex-shrink: 0; white-space: nowrap; }
.b-jobrow__co { color: var(--b-row-fg-2); font-weight: 600; max-width: 26ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.b-jobrow__loc { color: var(--b-row-fg-2); white-space: nowrap; }
.b-jobrow__more,
.b-jobrow__hours { color: var(--b-row-fg-3); white-space: nowrap; }
.b-jobrow__dist { color: var(--b-row-fg); font-weight: 700; white-space: nowrap; }
/* TWO separators, exactly one of them visible at a time. Stacked, the company and the city usually
   land on different lines, so the separator is the non-breaking "&nbsp;·" glued to the END of the
   company — it can never start a line. Wide, the whole line fits and B's dot takes over. */
.b-jobrow__co + .b-bit > .b-dot { display: none; }
/* The "·" must take the ROW's muted ink, not theme.css's --kds-fg-faint. That token is a
   light-surface value (#5E6D80) and it measured 3.2:1 against the board — the only contrast
   failure in the whole audit, and it came from inheriting a token across a surface boundary. */
.b-jobrow__sep { color: var(--b-row-fg-3); }
/* Parts that appear only once the ROW is wide enough for them — container width, not screen width. */
.b-wide { display: none; }

/* Inline arrangement tag (remote / hybrid). Teal here is the arrangement tag, not an audience use:
   it is the only tag in the row and it never appears as a dot. */
.b-tagi {
  font-size: var(--b-t-xs); font-weight: 600; letter-spacing: .02em; text-transform: uppercase;
  color: #15585E; border: 1px solid var(--cc-teal); background: var(--cc-teal-100);
  padding: 2px 6px; border-radius: 5px; white-space: nowrap;                          /* 7.1:1 */
}
.b-board .b-tagi,
.b-jobrow--on-dark .b-tagi { color: #BFE6EA; border-color: rgba(53,168,176,.45); background: rgba(53,168,176,.14); }  /* 10.2:1 */

/* ---- wage: tabular, and right-aligned the moment there is a second column ---------------------- */
.b-jobrow__wage {
  margin: 0; white-space: nowrap;
  font-size: var(--b-t-ui); font-weight: 650; color: var(--b-row-fg);
}
.b-jobrow__wage small { font-size: var(--b-t-sm); font-weight: 500; color: var(--b-row-fg-3); margin-left: 1px; }
.b-jobrow__wage--none { font-size: var(--b-t-base); font-weight: 500; color: var(--b-row-fg-3); }

/* ---- when: audience dots + relative time ------------------------------------------------------- */
.b-jobrow__when {
  margin: 0; white-space: nowrap;
  display: flex; align-items: center; gap: 8px;
  font-size: var(--b-t-sm); color: var(--b-row-fg-3);
}

/* ---- chips: exceptions only (reference listing, applications closed) --------------------------- */
.b-jobrow__chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.b-jobrow__chips:empty { display: none; }
.b-jobrow__chips .badge { font-size: var(--b-t-xs); }
.b-board .b-jobrow__chips .badge,
.b-jobrow--on-dark .b-jobrow__chips .badge { background: rgba(255,255,255,.07); border-color: var(--b-bd-line-2); color: var(--b-bd-fg-2); }

/* ---- actions: above the whole-row link overlay -------------------------------------------------- */
.b-jobrow__actions {
  position: relative; z-index: 1;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-top: 4px; padding-top: 10px; border-top: 1px solid var(--b-row-line);
}
.b-jobrow__actions:empty { display: none; }
.b-jobrow__score { font-size: var(--b-t-md); color: var(--b-row-fg-3); }

/* ==================================================================================================
   8b. THE ROW, WIDE — two columns, wage and time right-aligned. Keyed on the ROW's own width.
   520px is where "Company · City, PROV · Full-time" and a wage stop competing for the same line.
   ================================================================================================= */
/* Phone-width list (B's own narrow row): title, then meta, then wage and time sharing the last
   line. Below this the row is in a grid cell, not a list, and stays fully stacked. */
@container jobrow (min-width: 300px) {
  .b-jobrow__title   { grid-column: 1 / -1; grid-row: 1; }
  .b-jobrow__meta    { grid-column: 1 / -1; grid-row: 2; }
  .b-jobrow__wage    { grid-column: 1; grid-row: 3; }
  .b-jobrow__when    { grid-column: 2; grid-row: 3; justify-content: flex-end; }
  .b-jobrow__chips   { grid-column: 1 / -1; grid-row: 4; }
  .b-jobrow__actions { grid-column: 1 / -1; grid-row: 5; }
}
@container jobrow (min-width: 520px) {
  .b-jobrow__title   { grid-column: 1; grid-row: 1; }
  .b-jobrow__wage    { grid-column: 2; grid-row: 1; text-align: right; }
  .b-jobrow__meta    { grid-column: 1; grid-row: 2; flex-wrap: nowrap; overflow: hidden; }
  .b-jobrow__when    { grid-column: 2; grid-row: 2; justify-content: flex-end; }
  .b-jobrow__chips   { grid-column: 1 / -1; grid-row: 3; }
  .b-jobrow__actions { grid-column: 1 / -1; grid-row: 4; }
  .b-wide            { display: inline-flex; }
  /* swap the separators over: the dot in, the glued "·" out */
  .b-jobrow__co + .b-bit > .b-dot { display: inline-block; }
  .b-jobrow__sep { display: none; }
}
/* Wider still: the row can afford the padding and the type B gives it on a desktop board. */
@container jobrow (min-width: 820px) {
  .b-board .b-jobrow { padding: 13px 24px; }
  .b-jobrow__title { font-size: var(--b-t-h3); }
  .b-jobrow__wage  { font-size: var(--b-t-body); }
}
/* No container-query support: keep the stacked layout, but still right-align the wage on a wide
   screen so a desktop list is not a column of left-aligned numbers. */
@supports not (container-type: inline-size) {
  @media (min-width: 900px) {
    .b-jobrow[data-job-row] .b-jobrow__wage,
    .b-board .b-jobrow .b-jobrow__wage { text-align: right; }
  }
}

/* A row rendered on its own, outside a list and outside a grid cell, still wants an edge. */
.b-jobrow--boxed { border: var(--b-hair); border-radius: var(--b-r); padding: 16px 18px; }
.b-jobrow--boxed:hover { border-color: var(--b-line-2); }

/* ==================================================================================================
   9. HEADER
   Rebuilt in B's language — wordmark, quiet links, a live ticker, one ghost button, a hairline, no
   shadow. It keeps every class site.js and theme.css depend on (.site-header, .nav-toggle,
   #site-nav.site-nav, .is-open, .site-nav__tabs, .site-nav__auth), so the hamburger, the Escape
   handler and the signed-in state all keep working. B's prototype had four links and no hamburger;
   the real site has six plus auth, so the hamburger stays below 1024. That is a deliberate deviation.
   ================================================================================================= */
.b-hdr.site-header {
  background: rgba(255,255,255,.88);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: var(--b-hair);
  box-shadow: none;
}
.b-hdr .site-header__inner { gap: 14px; min-height: 68px; }
/* flex: none — the header is a flex row and theme.css gives every img max-width:100%, so without
   this the wordmark is the first thing the browser squeezes when the row gets tight. It shrank to a
   16px smudge the first time the ticker was switched on. */
.b-hdr .site-logo { display: flex; align-items: center; min-height: var(--b-tap); flex: none; }
.b-hdr .site-logo img { height: 34px; width: auto; max-width: none; display: block; }

/* the live ticker — the first proof the page is a board, not a brochure.
   Renders only when a route supplies res.locals.liveJobs (see the report); absent, the header is
   simply quieter. Nothing is ever invented here. */
.b-ticker {
  display: none; align-items: center; gap: 8px; margin: 0; padding: 6px 12px 6px 10px;
  border: var(--b-hair); border-radius: 999px; background: #fff;
  font-size: var(--b-t-md); color: var(--b-ink-2);
}
.b-ticker strong { color: var(--b-navy); font-weight: 700; }
.b-ticker__sep { width: 1px; height: 12px; background: var(--b-line-2); }
.b-ticker__quiet { color: var(--b-ink-3); }
/* It must never wrap — a two-line ticker makes the whole header two lines tall. And it appears only
   where there is genuinely room beside SIX nav links plus the auth controls: 1280, not B's 900,
   because B's prototype header carried four links and no account. */
.b-ticker, .b-ticker__quiet, .b-ticker strong { white-space: nowrap; }
@media (min-width: 1280px) { .b-ticker { display: inline-flex; } }

/* nav links: quieter than theme's, navy-50 on hover, red underline only on the active tab */
.b-hdr .site-nav__tabs a {
  display: inline-flex; align-items: center; min-height: var(--b-tap); padding: 0 10px;
  border-radius: 8px; font-weight: 500; font-size: var(--b-t-ui); color: var(--b-ink-2);
  transition: color .14s var(--b-e), background .14s var(--b-e);
}
.b-hdr .site-nav__tabs a:hover { color: var(--b-navy); background: var(--b-navy-50); }
.b-hdr .site-nav__tabs a.is-active { color: var(--b-navy); font-weight: 600; }
.b-hdr .site-nav__auth { align-items: center; gap: 8px; }
.b-hdr .nav-toggle { border-color: var(--b-line-2); border-radius: var(--b-r-md); }

@media (max-width: 1023px) {
  /* the open panel is a sheet under the hairline, not a floating card */
  .b-hdr .site-nav.is-open { border-top: var(--b-hair); margin-top: 8px; padding-top: 12px; }
  .b-hdr .site-nav__tabs a { padding: 0 10px; }
  /* theme.css marks the open panel's active tab with a RED inset bar. Red is spent three times in
     this system and the nav is not one of them, so the marker is navy here. */
  .b-hdr .site-nav__tabs a.is-active { background: var(--b-navy-50); box-shadow: inset 3px 0 0 var(--b-navy); }
  .b-hdr .site-nav__auth { flex-wrap: wrap; }
  .b-hdr .site-nav__auth > * { flex: 1 1 auto; }
}
@media (min-width: 1024px) {
  .b-hdr .site-nav__tabs a.is-active { background: none; box-shadow: none; }
  .b-hdr .site-nav__tabs a.is-active::after { left: 10px; right: 10px; bottom: -3px; height: 2px; background: var(--b-navy); }
}
@media (max-width: 419px) {
  .b-hdr .site-header__inner { gap: 10px; min-height: 62px; }
  .b-hdr .site-logo img { height: 28px; }
}

/* ---- the account menu (signed in). A native <details> disclosure: no JS, no dependency, and the
   summary is a real button with native aria-expanded. ------------------------------------------- */
.b-acct { position: relative; }
.b-acct > summary {
  display: inline-flex; align-items: center; gap: 8px; min-height: var(--b-tap); padding: 0 12px;
  border: var(--b-hair-2); border-radius: var(--b-r-md); background: #fff;
  font: 600 var(--b-t-ui)/1 var(--b-sans); color: var(--b-navy); cursor: pointer; list-style: none;
  white-space: nowrap;
}
.b-acct > summary::-webkit-details-marker { display: none; }
.b-acct > summary:hover { border-color: var(--b-navy); background: var(--b-navy-50); }
.b-acct__caret { width: 10px; height: 10px; flex: none; transition: transform .16s var(--b-e); }
.b-acct[open] .b-acct__caret { transform: rotate(180deg); }
.b-acct__menu { margin: 0; padding: 6px; }
/* theme.css only strips list markers inside .site-footer and .site-nav__tabs, so this one must do
   its own — otherwise the account menu renders as a bulleted list. */
.b-acct__menu ul { list-style: none; margin: 0; padding: 0; }
.b-acct__menu li { margin: 0; }
.b-acct__menu form { display: block; margin: 0; }
.b-acct__menu a,
.b-acct__menu button {
  display: flex; align-items: center; width: 100%; min-height: var(--b-tap); padding: 0 12px;
  border: 0; border-radius: 8px; background: none; text-align: left;
  font: 500 var(--b-t-ui)/1 var(--b-sans); color: var(--b-ink-2); text-decoration: none; cursor: pointer;
}
.b-acct__menu a:hover,
.b-acct__menu button:hover { background: var(--b-navy-50); color: var(--b-navy); }
.b-acct__menu hr { border: 0; border-top: var(--b-hair); margin: 6px 8px; }
.b-acct__who { padding: 8px 12px 6px; font-size: var(--b-t-md); color: var(--b-ink-3); }
@media (min-width: 1024px) {
  .b-acct[open] > .b-acct__menu {
    position: absolute; right: 0; top: calc(100% + 8px); z-index: 60; min-width: 232px;
    background: #fff; border: var(--b-hair); border-radius: var(--b-r); box-shadow: 0 18px 40px -26px rgba(14,29,49,.5);
  }
}
@media (max-width: 1023px) {
  /* inside the open nav sheet there is no room to float: the menu is just the next block */
  .b-acct { width: 100%; }
  .b-acct > summary { width: 100%; }
  .b-acct > summary .nav-label { margin-right: auto; }   /* label left, caret hard right */
  .b-acct__menu { padding: 6px 0 0; }
}

/* The avatar initial. theme.css paints it teal; teal is an audience colour, so on the chrome it is
   navy — the five hues stay reserved for audience marks. */
.b-hdr .avatar, .b-acct .avatar { background: var(--b-navy); color: #fff; width: 26px; height: 26px; font-size: var(--b-t-sm); }

/* ==================================================================================================
   10. FOOTER
   B's footer: white, one hairline above, the wordmark and a sentence, the link columns as quiet
   lists, the legal line last. Every existing link and the audience strip are kept.
   ================================================================================================= */
.b-ft.site-footer { background: #fff; border-top: var(--b-hair); margin-top: 48px; padding: 56px 0 28px; font-size: var(--b-t-ui); }
.b-ft .site-footer__grid { gap: 34px; }
.b-ft .site-footer__brand img { height: 32px; width: auto; }
.b-ft .site-footer__brand p { margin-top: 14px; color: var(--b-ink-3); max-width: 36ch; }
.b-ft h3 { font-family: var(--b-disp); font-size: var(--b-t-sm); font-weight: 700; letter-spacing: var(--b-track-caps); text-transform: uppercase; color: var(--b-ink-3); margin-bottom: 8px; }
.b-ft ul { gap: 0; }
.b-ft li a { display: inline-flex; align-items: center; min-height: var(--b-tap); font-size: var(--b-t-ui); color: var(--b-ink-2); text-decoration: none; }
.b-ft li a:hover { color: var(--b-red-700); }
.b-ft .site-footer__legal {
  margin-top: 36px; padding-top: 18px; border-top: var(--b-hair);
  display: flex; flex-wrap: wrap; gap: 8px 24px; justify-content: space-between;
  font-size: var(--b-t-md); color: var(--b-ink-3);
}
.b-ft .site-footer__legal p { margin: 0; }
/* the audience strip is the one place the five hues live in the chrome */
.b-ft .audience-strip { margin-top: 18px; gap: 8px !important; }
.b-ft .aud { border-color: var(--b-line); color: var(--b-ink-2); font-size: var(--b-t-sm); min-height: 30px; }

/* ==================================================================================================
   11. MOTION — and the absence of it
   Nothing loops except the pulse. Nothing moves on scroll. Rows arrive once, 22ms apart, and only
   when the document has opted in with class="js" on <html> — so a row can never be left invisible.
   ================================================================================================= */
@media (prefers-reduced-motion: no-preference) {
  .js .b-rows > .b-jobrow,
  .js .b-rows > li { opacity: 0; transform: translateY(6px); animation: b-in .5s var(--b-e) forwards; animation-delay: calc(90ms + var(--i, 0) * 22ms); }
}
@keyframes b-in { to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .b-rows > .b-jobrow, .b-rows > li { opacity: 1 !important; transform: none !important; animation: none !important; }
  .b-pulse::after { animation: none; opacity: 0; }
  .b-jobrow::before, .b-arr, .b-acct__caret { transition: none !important; }
}

/* ==================================================================================================
   12. PRINT — the board is ink-expensive; print it as a plain ruled list.
   (public/css/print.css is owned elsewhere and loads after this file; it wins if it disagrees.)
   ================================================================================================= */
@media print {
  .b-board { background: #fff !important; color: #000 !important; border: 1px solid #999; box-shadow: none; }
  .b-board .b-jobrow { --b-row-fg: #000; --b-row-fg-2: #333; --b-row-fg-3: #555; --b-row-line: #bbb; }
  .b-jobrow::before, .b-ticker, .b-live, .b-pulse { display: none !important; }
}

/* ==================================================================================================
   13. ADDED 2026-10-16 (CHROME agent, full-site round) — B ON THE SHARED PRIMITIVES
   --------------------------------------------------------------------------------------------------
   The whole site now renders in B, so the theme.css primitives every page is built from (.page-head,
   .app-head, .eyebrow, .card, .stat, .field/.input, .table, .badge, .flash, .empty, .dash__side,
   .kds-btn) take B's surface here. This is still a LAYER: theme.css is not edited, every class name
   stays, and a page stylesheet (loaded after this file) can override any of it.
   Rules of the system, restated for page agents:
     · ONE gradient (the .b-wash utility) — the page heads lose their navy-50 fade.
     · .eyebrow is ink-3, not red. Red is spent three times (pulse, New, the ONE primary button).
     · depth = hairlines; no card shadows; no side-stripe borders; no nested cards.
     · every count and every money value wears .b-tab (tabular numerals).
   ================================================================================================= */
:root {
  /* added tokens (additive) */
  --b-ok:      #2F6B1E;   /* success ink   7.0:1 on --b-ok-bg  */
  --b-ok-bg:   #EEF6E6;
  --b-ok-line: #C9E2B0;
  --b-err:     #8A1B1B;   /* error ink     8.9:1 on --b-err-bg */
  --b-err-bg:  #FCEDED;
  --b-err-line:#F1C2C2;
  --b-info:    #15585E;   /* info ink      7.1:1 on --b-info-bg */
  --b-info-bg: #E9F6F7;
  --b-info-line:#B6E0E3;
  --b-warn:    #7A4A00;   /* warning ink   7.6:1 on --b-warn-bg */
  --b-warn-bg: #FDF3E1;
  --b-warn-line:#F2D49B;
  --b-focus-glow: 0 0 0 3px rgba(31,58,95,.14);   /* the input focus halo */
  --b-wrap: var(--cc-container);                  /* the one container width */
}

/* ---- type ---------------------------------------------------------------------------------- */
h1, h2, h3, h4 { color: var(--b-navy); }
h1 { letter-spacing: -.03em; }
h2 { letter-spacing: -.022em; }
.eyebrow, .b-eyebrow {
  font: 700 var(--b-t-sm)/1 var(--b-disp); letter-spacing: .14em; text-transform: uppercase;
  color: var(--b-ink-3); margin: 0 0 12px;
}
.b-eyebrow--on, .b-on-dark .eyebrow, .b-on-dark .b-eyebrow { color: #A9C1DE; }
.lead { color: var(--b-ink-2); }
.muted { color: var(--b-ink-3); }
.b-sr { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.b-quiet { margin: 16px 0 0; font-size: var(--b-t-base); color: var(--b-ink-3); max-width: 70ch; }

/* ---- page heads: white, one hairline, B's h1 --------------------------------------------------- */
.page-head, .app-head { background: var(--b-bg); border-bottom: var(--b-hair); }
.page-head h1, .app-head h1 { font-weight: 800; letter-spacing: -.03em; }
.page-head h1 { font-size: var(--b-t-h1); }
.page-head .lead { font-size: var(--b-t-lead); line-height: 1.6; }
/* opt in to the soft wash on a hero-like head: <header class="page-head b-wash"> */

/* ---- section head (B's .b-sech) ---------------------------------------------------------------- */
.b-sech { max-width: 62ch; margin-bottom: 32px; }
.b-sech h2 { font-size: var(--b-t-h2); font-weight: 800; letter-spacing: -.026em; margin: 0; }
.b-sech p { margin: 12px 0 0; color: var(--b-ink-2); }
.section--alt { background: var(--b-bg-2); border-color: var(--b-line); }

/* ---- cards and panels: hairline, no shadow ----------------------------------------------------- */
.card { border-color: var(--b-line); border-radius: var(--b-r); box-shadow: none; }
.card--flat { background: var(--b-bg-2); }
/* .b-panel: a titled block that is NOT a card — a hairline-topped column (B's "What Canada is hiring
   for"). Use it instead of a card when the content is a list or a set of numbers. */
.b-panel { min-width: 0; }
.b-panel__h, .card__head .b-panel__h {
  font: 700 var(--b-t-md)/1.2 var(--b-disp); letter-spacing: var(--b-track-caps); text-transform: uppercase;
  color: var(--b-ink-3); margin: 0 0 14px;
}
.b-panel__f { margin: 18px 0 0; font-size: var(--b-t-base); color: var(--b-ink-3); }

/* ---- ruled list with a right-aligned tabular count (B's provinces/cities list) ---------------- */
.b-list { list-style: none; margin: 0; padding: 0; border-top: var(--b-hair); }
.b-list > li > a, .b-list > li > .b-list__row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: var(--b-tap); padding: 6px 0; border-bottom: var(--b-hair);
  color: var(--b-ink); text-decoration: none; font-size: var(--b-t-ui);
}
.b-list__c { color: var(--b-ink-3); font-size: var(--b-t-base); font-variant-numeric: tabular-nums; text-align: right; }
.b-list > li > a:hover { color: var(--b-navy); }
.b-list > li > a:hover .b-list__c { color: var(--b-ink-2); }

/* ---- stats: B's ".b-now" — figures in one hairline grid --------------------------------------- */
.stat { border-color: var(--b-line); border-radius: 12px; }
.stat__value, .b-stat__v { font: 800 1.625rem/1.1 var(--b-disp); letter-spacing: -.022em; color: var(--b-navy); font-variant-numeric: tabular-nums; }
.stat__label, .b-stat__l { color: var(--b-ink-3); font-size: var(--b-t-md); }
.stats { gap: 1px; background: var(--b-line); border: var(--b-hair); border-radius: 12px; overflow: hidden; }
.stats > .stat { border: 0; border-radius: 0; }
.b-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; margin: 0; background: var(--b-line); border: var(--b-hair); border-radius: 12px; overflow: hidden; }
.b-stats > div { background: #fff; padding: 16px; display: flex; flex-direction: column-reverse; gap: 2px; }
.b-stats dt { font-size: var(--b-t-md); color: var(--b-ink-3); }
.b-stats dd { margin: 0; font: 800 1.625rem/1.1 var(--b-disp); letter-spacing: -.022em; color: var(--b-navy); font-variant-numeric: tabular-nums; }
@media (min-width: 768px) { .b-stats--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* ---- forms ----------------------------------------------------------------------------------- */
.field label, .kds-label { color: var(--b-ink); font-weight: 600; font-size: var(--b-t-base); }
.field .hint { color: var(--b-ink-3); }
.input, .kds-input, .kds-select, textarea.input, select.input {
  border-color: var(--b-line-2); border-radius: var(--b-r-md); color: var(--b-ink);
  transition: border-color .16s var(--b-e), box-shadow .16s var(--b-e);
}
.input:hover, .kds-input:hover, .kds-select:hover { border-color: #AFC0D4; }
.input:focus, .kds-input:focus, .kds-select:focus, textarea.input:focus {
  border-color: var(--b-navy); outline: none; box-shadow: var(--b-focus-glow);
}
/* keyboard focus must stay unmistakable: halo + ring */
.input:focus-visible, .kds-input:focus-visible, .kds-select:focus-visible { outline: 2px solid var(--b-navy); outline-offset: 1px; }
.input::placeholder, .kds-input::placeholder { color: var(--b-ink-3); }
.check { border-color: var(--b-line); border-radius: var(--b-r-md); min-height: var(--b-tap); }
.check:has(input:checked) { border-color: var(--b-navy); background: var(--b-navy-50); }

/* ---- buttons: the kds-btn family takes B's shape (red stays ONLY on --accent) ----------------- */
.kds-btn { border-radius: var(--b-r-md); font-weight: 600; letter-spacing: -.006em; min-height: var(--b-tap); }
.kds-btn--ghost { border: 1px solid var(--b-line-2); color: var(--b-navy); background: #fff; }
.kds-btn--ghost:hover { border-color: var(--b-navy); background: var(--b-navy-50); color: var(--b-navy); }

/* ---- tables: ledger rules, tabular figures ---------------------------------------------------- */
.table th, .table td { border-bottom: var(--b-hair); }
.table th { font-size: var(--b-t-xs); font-weight: 600; letter-spacing: var(--b-track-caps); color: var(--b-ink-3); }
.table td { font-variant-numeric: tabular-nums; }
.table tbody tr:hover { background: var(--b-bg-2); }
.b-num-col, .table .b-num-col { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 767px) { .table--stack tr { border-color: var(--b-line); border-radius: 12px; } }

/* ---- badges (status pills) ------------------------------------------------------------------- */
.badge { background: var(--b-navy-50); color: var(--b-navy-700); border: 1px solid #DCE5F0; font-weight: 600; }
.badge--positive { background: var(--b-ok-bg); color: var(--b-ok); border-color: var(--b-ok-line); }
.badge--warning  { background: var(--b-warn-bg); color: var(--b-warn); border-color: var(--b-warn-line); }
.badge--danger   { background: var(--b-err-bg); color: var(--b-err); border-color: var(--b-err-line); }
.badge--teal     { background: var(--b-info-bg); color: var(--b-info); border-color: var(--b-info-line); }

/* ---- flash messages: tinted, hairline, no stripe ---------------------------------------------- */
.flash-region { padding-top: 14px; }
.flash {
  display: flex; align-items: flex-start; gap: 10px; padding: 12px 16px; border-radius: var(--b-r-md);
  border: 1px solid var(--b-line-2); background: var(--b-bg-2); color: var(--b-ink); font-size: var(--b-t-ui); line-height: 1.45;
}
.flash::before { content: ""; flex: none; width: 8px; height: 8px; margin-top: 6px; border-radius: 50%; background: currentColor; }
.flash--success { background: var(--b-ok-bg); border-color: var(--b-ok-line); color: var(--b-ok); }
.flash--error   { background: var(--b-err-bg); border-color: var(--b-err-line); color: var(--b-err); }
.flash--info    { background: var(--b-info-bg); border-color: var(--b-info-line); color: var(--b-info); }
.flash--warning { background: var(--b-warn-bg); border-color: var(--b-warn-line); color: var(--b-warn); }

/* ---- empty state: quiet band, not a dashed box ----------------------------------------------- */
.empty { border: var(--b-hair); border-radius: var(--b-r); background: var(--b-bg-2); color: var(--b-ink-2); }

/* ---- dashboard side nav: B's nav treatment (navy-50 + navy, never red, never a filled pill) --- */
.dash__side a { border-color: var(--b-line); color: var(--b-ink-2); font-weight: 600; min-height: var(--b-tap); display: inline-flex; align-items: center; }
.dash__side a:hover { border-color: var(--b-line-2); color: var(--b-navy); background: var(--b-navy-50); }
.dash__side a.is-active { background: var(--b-navy-50); color: var(--b-navy); border-color: var(--b-navy); }

/* ---- a dark band (B's employer section) — navy surface, white type ---------------------------- */
.b-band-dark { background: var(--b-navy); color: #fff; }
.b-band-dark h2, .b-band-dark h3 { color: #fff; }
.b-band-dark p { color: #CFDDEC; }
.b-band-dark :focus-visible { outline: var(--b-ring-on); }
.b-band-dark a:not(.b-btn):not(.kds-btn) { color: #fff; }

/* ---- breadcrumb in B's ink ------------------------------------------------------------------- */
.breadcrumb { color: var(--b-ink-3); }
.breadcrumb a { color: var(--b-ink-2); min-height: 24px; display: inline-flex; align-items: center; }
.breadcrumb a:hover { color: var(--b-navy); }

/* ---- job row, wide: the one-line meta never breaks a word -------------------------------------
   At ≥520 the meta line is nowrap + overflow:hidden, and flex items shrink by default — so on the
   home board "Full-time" broke into "Full-/time" and "40 hours per week" was sliced mid-word. Only
   the company name may give way (it already ellipsises); every other part keeps its natural width.
   Between 520 and 720 there is not room for the hours as well, so they wait for a wider row (they
   are still on the posting itself and on the narrow stacked row, where the line may wrap). */
@container jobrow (min-width: 520px) {
  .b-jobrow__meta > :not(.b-jobrow__co) { flex-shrink: 0; }
  .b-jobrow__co { flex-shrink: 1; min-width: 0; }
}
@container jobrow (min-width: 520px) and (max-width: 719px) {
  .b-bit:has(> .b-jobrow__hours) { display: none; }
}

/* ---- the error page (views/error.ejs — renders with no page stylesheet, so it lives here) ------ */
.b-err { padding: 40px 0 16px; }
.b-err__in { display: grid; gap: 40px; }
.b-err__head h1 { font-size: var(--b-t-h1); font-weight: 800; letter-spacing: -.03em; margin: 0 0 12px; }
.b-err__head .lead { margin: 0; max-width: 52ch; line-height: 1.6; }
.b-err__actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 24px 0 0; }
.b-err__ways ul { list-style: none; margin: 0; padding: 0; border-top: var(--b-hair); }
.b-err__ways a {
  display: grid; gap: 4px; padding: 16px 0; min-height: var(--b-tap);
  border-bottom: var(--b-hair); color: var(--b-ink); text-decoration: none;
}
.b-err__t { font: 700 var(--b-t-h3)/1.25 var(--b-disp); color: var(--b-navy); letter-spacing: -.012em; }
.b-err__d { font-size: var(--b-t-base); color: var(--b-ink-3); line-height: 1.5; }
.b-err__go { margin-top: 4px; display: inline-flex; align-items: center; gap: 7px; font-size: var(--b-t-base); font-weight: 600; color: var(--b-navy); }
.b-err__ways a:hover { color: var(--b-ink); }
.b-err__ways a:hover .b-err__t { text-decoration: underline; text-underline-offset: 3px; }
@media (min-width: 900px) {
  .b-err { padding: 72px 0 24px; }
  .b-err__in { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: 64px; align-items: start; }
}

/* ---- footer refinements (2026-10-16) ----------------------------------------------------------
   The legal hairline was drawn on the .container box, so it ran 16–24px past the text on both
   sides; it now sits on the content edge like every other rule. On a phone the three link columns
   pair up two-across under the brand block instead of stacking into one 1,100px column. */
.b-ft .site-footer__legal { position: relative; border-top: 0; }
.b-ft .site-footer__legal::before { content: ""; position: absolute; top: 0; left: 16px; right: 16px; height: 1px; background: var(--b-line); }
@media (min-width: 768px) { .b-ft .site-footer__legal::before { left: 24px; right: 24px; } }
@media (max-width: 639px) {
  .b-ft .site-footer__grid { grid-template-columns: 1fr 1fr; column-gap: 20px; }
  .b-ft .site-footer__brand { grid-column: 1 / -1; }
}

/* ---- open mobile nav (2026-10-16): full-width rows, and NO side stripe on the active tab ------
   §9 marked the active tab with an inset 3px navy bar — a side-stripe border, which the B rules
   forbid. The active tab is now a full-width navy-50 row in navy 600, and every row is a full-width
   44px target instead of a text-width pill. */
@media (max-width: 1023px) {
  .b-hdr .site-nav__tabs a { display: flex; width: 100%; }
  .b-hdr .site-nav__tabs a.is-active { box-shadow: none; background: var(--b-navy-50); color: var(--b-navy); font-weight: 600; }
}

/* ---- header with the ticker (2026-10-16) -------------------------------------------------------
   With the ticker on, six links + Sign in/Sign up did not fit at 1440: the auth buttons wrapped
   onto two lines and doubled the header's height. The auth pair never wraps now, and the ticker's
   quiet half ("last posted …") appears only where there is room for it. */
.b-hdr .site-nav__auth { flex-wrap: nowrap; }
@media (max-width: 1023px) { .b-hdr .site-nav__auth { flex-wrap: wrap; } }
@media (max-width: 1599px) { .b-ticker__sep, .b-ticker__quiet { display: none; } }
