/* /jobb/ — the public job search. Prefix: jb-.
   Built only from web/tokens.css values and web/ui.css components: there is no colour,
   radius, shadow or motion literal in this file, so dark mode comes from the tokens
   alone and the page is the same design system as the app.

   The idea: a well-made newspaper listings page. One toolbar (search + filter
   dropdowns) over two columns on the site header's fluid gutter, hairline-separated
   rows instead of cards, dates at the right edge in tabular figures, one accent (sea)
   and exactly one card on the page — the reading pane.

   Structure below is narrow-first: the base rules are the phone shape, where the filter
   rail and the pane are sheets (web/jobb.js adds .ui-sheet from ui.css), and the two
   min-width blocks turn the filters into dropdowns and the pane into a column. */

/* ---- Page frame ------------------------------------------------------------------ */
/* The site body is not .ui-root, so the two base behaviours the components assume —
   border-box and a visible focus ring — are restated for this page only. */
.jb-page, .jb-page * { box-sizing: border-box; }

.jb-page {
  --jb-stick: calc(var(--st-head-h) + var(--s-6));
  /* v9: the list is a column you scan, not half the page; the ad gets the rest, with air
     between them. The toolbar uses the same two values so its halves line up. */
  /* v10: the list follows the screen (a third of it, 420–620 px) instead of stopping at
     480, so a wide monitor gets one-line titles and a 1440 laptop still leaves the ad its
     room. The pane's ceiling moves with it. */
  /* v10b (owner, same day): wider again on both sides. 36 % of the screen up to 720 px for
     the list; the pane's ceiling at 1240, which on a 2000 px screen means it simply takes
     everything the list and the gap leave. */
  --jb-cols: clamp(440px, 36vw, 720px) minmax(0, 1fr);
  --jb-gap: var(--s-10);
  --jb-pane-max: 1240px;

  /* .st-body reads at 17 px; a tool scans at 14. */
  font-size: var(--text-md);
  line-height: var(--lh-md);
  padding: var(--s-8) var(--st-chrome-gutter) var(--st-section);
}
/* v10b/c: on a wide screen the two columns use the whole page, so the only way to widen
   both was a tighter side margin than the site chrome's 72 px (16–44 px, fluid). The
   header and the footer take the same margin on this page, so logo, search, list, ad,
   filters and the header's buttons all share two edges. Only here: every other page
   keeps the site's own gutter. */
.st-body:has(.jb-page) { --st-chrome-gutter: clamp(16px, 2.2vw, 44px); }
.jb-page :focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--r-sm); }
/* The selected row paints its own box-shadow (wash + accent edge), which used to swallow
   the focus ring on exactly the row a keyboard reader is standing on. An outline is a
   second channel, so the two can show at once (audit 8). */
.jb-page .jb-row-a:focus-visible,
.jb-page .jb-rel-a:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
/* Visually hidden, still announced: the page's live region. */
.jb-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
/* The reader's own words, marked the way the site marks what fits in an ad. */
.jb-hl { background: var(--sun-soft); color: inherit; border-radius: var(--r-2xs); padding: 0 1px; }
.jb-page h1, .jb-page h2, .jb-page h3, .jb-page h4, .jb-page p { margin: 0; }
.jb-page a { color: var(--accent-ink); text-decoration: none; }
.jb-page a:hover { text-decoration: underline; text-underline-offset: 2px; }

/* ---- Top: one toolbar — search, filter dropdowns, Rensa alla (v8) ----------------- */
/* The page opens with its controls, not with a banner: the H1 is there for AT and for
   the outline, the corpus figure is a small line under the row. */
/* v9: no banner line and no rules. The row follows the two columns under it (--jb-cols,
   shared with .jb-shell from 1200 px): search and sort above the list, the filter
   dropdowns at the right above the ad. Under 1200 px the two halves stack. */
.jb-top { margin-bottom: var(--s-3); }
.jb-toolbar { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-2) var(--jb-gap); align-items: center; }
.jb-tb-left { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
.jb-tb-left .jb-search { flex: 1 1 auto; max-width: none; }
.jb-sort-select { flex: 0 0 auto; width: auto; min-width: 132px; }
.jb-tb-right { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); min-width: 0; }
.jb-fbtns { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.jb-clear-top { margin-left: var(--s-1); font-size: var(--text-sm); }

/* A filter button says what it filters and, when it is on, how many values it carries.
   The caret is drawn, not a glyph, so it follows the button's ink. */
.jb-fbtn { gap: var(--s-1); padding-right: var(--s-2); }
.jb-fbtn::after {
  content: "";
  width: 5px;
  height: 5px;
  margin: 0 2px 0 var(--s-1);
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  opacity: 0.7;
}
.jb-fbtn[aria-expanded="true"] { background: var(--hover); border-color: var(--line-strong); }
.jb-fbtn[aria-expanded="true"]::after { transform: translateY(1px) rotate(-135deg); }
.jb-fbtn.is-on { background: var(--accent-soft); border-color: transparent; color: var(--accent-ink); }
.jb-fbtn-n {
  display: inline-grid;
  place-items: center;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}

/* ---- Filter dropdowns: the rail's group bodies, in a popover --------------------- */
/* jobb.js moves #jb-body-<key> in and out of here, so these rules restate only what the
   sheet's own column shape would otherwise give the body. */
/* The popover hangs off <body>, outside .jb-page, so the two things the page sets for
   its own subtree — border-box and a visible focus ring — are restated here. */
.jb-pop, .jb-pop * { box-sizing: border-box; }
.jb-pop :focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--r-sm); }
.jb-pop {
  width: min(320px, calc(100vw - 16px));
  line-height: var(--lh-md);
  max-height: min(70vh, 520px);
  overflow: auto;
  overscroll-behavior: contain;
  padding: var(--s-3) var(--s-4);
  font-size: var(--text-sm);
}
.jb-pop > .jb-group-body { padding: 0; }
.jb-pop .jb-opts { max-height: 264px; }
.jb-pop .ui-seg { width: 100%; }
.jb-pop .ui-seg > button { flex: 1; }
.jb-pop .ui-check { font-size: var(--text-sm); }

/* One rounded frame holds the field and the button, the way a search box on a listings
   site should read: a single control, not an input next to a button. */
.jb-search {
  display: flex;
  align-items: center;
  flex: 1 1 320px;
  min-width: 220px;
  max-width: 520px;
  height: 40px;
  padding-right: var(--s-1);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--sunken);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.jb-search:hover { border-color: var(--line-strong); }
.jb-search:focus-within { background: var(--card); border-color: var(--focus); box-shadow: var(--focus-ring); }
/* The magnifier is a mask, not a tinted image, so it follows --ink-4 into dark mode. */
.jb-search::before {
  content: "";
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin: 0 var(--s-2) 0 var(--s-4);
  background: var(--ink-4);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E") center / contain no-repeat;
}
.jb-search-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  padding: 0 var(--s-2);
  border: none;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: var(--text-md);
}
.jb-search-input:focus { outline: none; box-shadow: none; }
.jb-search-input::placeholder { color: var(--ink-4); }
.jb-search-btn { flex: 0 0 auto; }

#jb-notice { margin-bottom: var(--s-4); }

/* ---- Shell ------------------------------------------------------------------------ */
.jb-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  column-gap: var(--s-8);
  align-items: start;
}

/* ---- Filter rail: the phone sheet, and the home of every filter control ----------- */
/* From 900 px the rail is display:none and its group bodies are lifted into the toolbar's
   popovers instead (v8). Below 900 px it is the filter sheet, with every group in place. */
.jb-rail {
  --sheet-w: 320px;
  /* Never in the page flow: the rail is either a sheet (under 900 px, jobb.js adds
     .ui-sheet) or nothing at all, with its group bodies out in the dropdowns. */
  display: none;
  gap: var(--s-1);
  align-content: start;
  padding: var(--s-4) var(--s-5) var(--s-10);
  font-size: var(--text-sm);
}
.jb-rail-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--line);
}
/* As a sheet the rail scrolls: the way out stays at the top and the way on stays at the
   bottom (audit 30, 53). As a column both are gone — the rail has no chrome there. */
.jb-rail.ui-sheet { display: grid; padding: 0; }
.jb-rail.ui-sheet .jb-rail-head {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: var(--s-4) var(--s-5) var(--s-3);
  background: var(--raised);
}
.jb-rail.ui-sheet > .jb-group { margin: 0 var(--s-5); }
.jb-rail-foot { display: none; }
.jb-rail.ui-sheet .jb-rail-foot {
  position: sticky;
  bottom: 0;
  z-index: 1;
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-2);
  padding: var(--s-3) var(--s-5) var(--s-4);
  background: var(--raised);
  border-top: 1px solid var(--line);
}
.jb-rail.ui-sheet .jb-rail-foot > :last-child { flex: 1; }
.jb-rail-title {
  flex: 1;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--ink-3);
}
.jb-rail-head .ui-link-btn { font-size: var(--text-sm); }

.jb-group { border-bottom: 1px solid var(--line-soft); }
.jb-group > summary {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-3) 0;
  list-style: none;
  cursor: pointer;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--ink-3);
}
.jb-group > summary::-webkit-details-marker { display: none; }
.jb-group > summary:hover { color: var(--ink); }
.jb-group > summary::after {
  content: "";
  width: 6px;
  height: 6px;
  margin-left: auto;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--t-fast) var(--ease);
}
.jb-group[open] > summary::after { transform: translateY(1px) rotate(-135deg); }
.jb-group summary small {
  font-weight: var(--weight-regular);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-4);
}
.jb-group-body { display: grid; gap: var(--s-2); padding-bottom: var(--s-4); }
.jb-sub { display: grid; gap: var(--s-1); }
.jb-sub .ui-label { font-size: var(--text-xs); color: var(--ink-3); }
.jb-rail .ui-check { font-size: var(--text-sm); }
.jb-rail .ui-seg { width: 100%; }
.jb-rail .ui-seg > button { flex: 1; }

/* Option rows: checkbox, ellipsised label, count right in tabular figures. */
.jb-opts {
  display: grid;
  gap: 1px;
  max-height: 224px;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
.jb-opt {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-1) var(--s-2);
  border-radius: var(--r-xs);
  color: var(--ink-2);
  cursor: pointer;
}
.jb-opt:hover { background: var(--hover); color: var(--ink); }
.jb-opt input { flex: 0 0 auto; width: 15px; height: 15px; margin: 0; accent-color: var(--accent); }
.jb-opt-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jb-opt-label .ui-source { font-size: inherit; color: inherit; max-width: 100%; }
/* Counts are content, not decoration: --ink-4 is 2.3:1 on white and this is 11 px (audit 16). */
.jb-opt-n { color: var(--ink-3); font-size: var(--text-xs); font-variant-numeric: tabular-nums; }
.jb-opt.is-active { background: var(--selected); color: var(--accent-ink); }
.jb-opt.is-active .jb-opt-n { color: inherit; }
.jb-opt-empty { padding: var(--s-2); color: var(--ink-4); }

.jb-chips { display: flex; flex-wrap: wrap; gap: var(--s-1); }
.jb-chip { height: 24px; padding: 0 var(--s-2); font-size: var(--text-xs); }
.jb-chip-n { color: var(--ink-3); font-size: var(--text-xs); }
.jb-chip[aria-pressed="true"] .jb-chip-n { color: inherit; }
/* A value no ad carries: shown so the vocabulary stays stable, but not pressable (audit 34). */
.jb-chip:disabled { color: var(--ink-4); background: var(--canvas-tint); border-color: var(--line-soft); cursor: default; }
.jb-chip:disabled .jb-chip-n { color: var(--ink-4); }
.jb-chip:disabled:hover { background: var(--canvas-tint); border-color: var(--line-soft); }

/* ---- Results bar ------------------------------------------------------------------ */
.jb-results { min-width: 0; }
.jb-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-3);
  padding-bottom: var(--s-3);
}
/* Active filters get their own line under the count and the sort, so the bar never
   wraps mid-row when a chip appears. */
.jb-active { order: 10; flex-basis: 100%; display: flex; flex-wrap: wrap; gap: var(--s-1); min-width: 0; padding-top: var(--s-1); }
.jb-active:empty { display: none; }
/* The label ellipsises, never the × (audit 10): the text sits in its own span and the
   chip itself clips. */
.jb-achip { max-width: 22ch; overflow: hidden; }
.jb-achip-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* The count claims the slack, so the switch and the sort sit at the right edge whether
   or not the (session-only) switch is on the page. */
.jb-count { margin-right: auto; color: var(--ink-3); font-size: var(--text-sm); white-space: nowrap; }

/* ---- The list: rows, not cards ----------------------------------------------------
   The shape is web/ui.css (.ui-list, .ui-job, .ui-job-a and the rest), shared with the
   app's list so the same ad reads the same way in both. What stays here is what only
   this page has: room under the site header for a scrolled-to row, the loading dim, the
   bookmark's margin and the skeleton. */
.jb-list { scroll-margin-top: calc(var(--st-head-h) + var(--s-4)); }
.jb-list:focus { outline: none; }
/* A request in flight dims the rows that are still on screen; the skeleton only takes
   over when the wait is long enough to feel (audit 23). */
.jb-list.is-loading { opacity: 0.55; transition: opacity var(--t-fast) var(--ease); }
/* The row is the link plus its bookmark: two siblings, never a button inside an anchor. */
.jb-row { scroll-margin-top: calc(var(--st-head-h) + var(--s-6)); }
.jb-row-save { margin-right: var(--s-2); }
.jb-row-age { color: var(--ink-3); }

.jb-row-skel { display: grid; grid-template-columns: var(--tile) minmax(0, 1fr); gap: var(--s-4); padding: var(--s-4) var(--s-3); }
.jb-skel-tile { flex: 0 0 auto; width: var(--tile); height: var(--tile); border-radius: var(--r-md); }
.jb-skel-lines { display: grid; gap: var(--s-2); align-content: center; }
.jb-skel-lines > * { height: 10px; }

.jb-empty { display: grid; gap: var(--s-3); justify-items: center; padding: var(--s-16) var(--s-6); text-align: center; color: var(--ink-3); }
.jb-empty .ui-h3 { color: var(--ink); }
/* The filters that are costing the results, removable on the spot (audit 36). */
.jb-empty-chips { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-1); max-width: 56ch; }

.jb-pagebar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-5) var(--s-3) 0;
}
/* Pages are links (audit 11): they get the button's shape but keep a link's behaviour. */
.jb-pagination { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1); }
.jb-pagination a { color: var(--ink-2); }
.jb-pagination a:hover { text-decoration: none; }
.jb-pagination .is-disabled { color: var(--ink-4); background: var(--canvas-tint); border-color: var(--line-soft); cursor: default; }
.jb-page-n { min-width: 30px; padding: 0 var(--s-2); }
.jb-page-n[aria-current="page"] { background: var(--accent-soft); color: var(--accent-ink); }
.jb-page-gap { padding: 0 var(--s-1); color: var(--ink-4); }

/* ---- The reading pane: the one card on the page ----------------------------------- */
/* The pane is its own container, so the head and the fit panel can answer to the width
   they actually have instead of the viewport's (audit 38, 50). */
.jb-detail { --sheet-w: 620px; min-width: 0; background: var(--card); container-type: inline-size; container-name: jbpane; }
/* On a long ad at 375 px the sheet is the whole screen: a close button that scrolls away
   leaves Escape as the only way out (audit 30). */
.jb-detail-bar { position: sticky; top: 0; z-index: 1; padding: var(--s-3) var(--s-4) var(--s-2); background: var(--card); border-bottom: 1px solid var(--line-soft); }
.jb-detail-close { display: inline-flex; }
.jb-detail-empty,
.jb-detail-skel { padding: var(--s-16) var(--s-6); }
.jb-detail-empty { display: grid; gap: var(--s-2); justify-items: center; text-align: center; color: var(--ink-3); }
.jb-detail-empty .ui-h3 { color: var(--ink); }
.jb-detail-empty .jb-d-title { font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--ink); }
.jb-detail-skel { display: grid; grid-template-columns: var(--tile-lg) minmax(0, 1fr); gap: var(--s-4); padding: var(--s-6); }
.jb-detail-skel .jb-skel-tile { width: var(--tile-lg); height: var(--tile-lg); border-radius: var(--r-md); }
/* The fit lists live in a 240 px column now, so they are always one column wide. */
.jb-d-fit .ui-fit-panel { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); }

/* The jump to the company block must not land under the bar. */
.jb-d-employer { scroll-margin-top: 64px; }

/* Logo, then the text column (title · meta · deadline). */
.jb-d-head { display: grid; grid-template-columns: var(--tile-lg) minmax(0, 1fr); gap: var(--s-4); padding: var(--s-5) var(--s-6) var(--s-4); }
.jb-d-headtext { min-width: 0; display: grid; gap: var(--s-2); align-content: start; justify-items: start; }
.jb-tool { color: var(--ink-3); }
.jb-tool:hover { color: var(--ink); }
.jb-tool.is-on { background: var(--sun-soft); border-color: transparent; color: var(--saved); }

/* The ad at the left, how you fit it at the right; one column under 1200 px, with the
   fit above the ad text because the DOM puts the side column first. */
.jb-d-body { display: grid; grid-template-columns: minmax(0, 1fr); }
.jb-d-main { min-width: 0; }
.jb-d-side { min-width: 0; padding: var(--s-4) var(--s-6); display: grid; gap: var(--s-3); align-content: start; }
/* The side box's primary is an <a> on this page, and .jb-page a would repaint it. */
.jb-page a.ui-sidebox-btn { color: var(--ink-inverse, #fff); text-decoration: none; }
@media (max-width: 1199px) { .jb-side-extra { display: none; } }
@media (min-width: 1200px) {
  /* 240 px: wide enough for a requirement per line, narrow enough to leave the ad text
     ~365 px at the 1200 px breakpoint and ~490 px at 1440. */
  /* 28 % of the pane, 240–300 px (the pane is a size container): three boxes need the
     width on a big screen, the ad text needs it more on a small one. */
  .jb-d-body.has-side { grid-template-columns: minmax(0, 1fr) clamp(240px, 28cqi, 300px); }
  .jb-d-body.has-side .jb-d-main { grid-column: 1; grid-row: 1; }
  .jb-d-body.has-side .jb-d-side {
    grid-column: 2;
    grid-row: 1;
    position: sticky;
    /* Clears the pane's sticky action bar (about 55 px) with the usual gap. */
    top: calc(56px + var(--s-4));
    align-self: start;
    padding-left: 0;
    /* A long fit list plus two boxes can outgrow the pane; the column scrolls on its own
       rather than hiding its foot under the pane's edge. */
    max-height: calc(100vh - var(--st-head-h) - var(--s-12) - 56px - var(--s-8));
    overflow: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--line) transparent;
  }
}
.jb-d-title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  line-height: var(--lh-xl);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
  color: var(--ink);
}
/* Badges ride inline on the title: "Ny", Sparad/Sökt, the salary; vertical-align keeps
   them on the title's midline rather than its baseline. */
.jb-d-badges { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--s-1); vertical-align: middle; }
.jb-d-badges:empty { display: none; }
.jb-d-badges .ui-badge { font-size: var(--text-xs); height: 20px; }
/* The closing action row at the foot of the ad. */
.jb-d-cta-foot { padding: var(--s-4) var(--s-6) var(--s-5); border-top: 1px solid var(--line-soft); border-bottom: none; }
/* Liknande annonser: compact rows on the pane's tint, the tile at 36 px. */
.jb-related { gap: var(--s-2); background: var(--canvas-tint); border-top: 1px solid var(--line-soft); padding-bottom: var(--s-5); }
.jb-rel-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.jb-rel-a {
  --tile: 36px;
  display: grid;
  grid-template-columns: var(--tile) minmax(0, 1fr) auto;
  gap: var(--s-3);
  align-items: center;
  margin: 0 calc(-1 * var(--s-2));
  padding: var(--s-2);
  border-radius: var(--r-sm);
  color: inherit;
}
.jb-rel-a:hover { background: var(--card); text-decoration: none; }
.jb-rel-a .ui-tile { font-size: var(--text-xs); border-radius: var(--r-sm); }
.jb-rel-text { min-width: 0; display: grid; gap: 1px; }
.jb-rel-title { font-weight: var(--weight-medium); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jb-rel-meta { font-size: var(--text-sm); color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jb-rel-side { display: grid; justify-items: end; gap: 1px; font-size: var(--text-xs); white-space: nowrap; }
.jb-rel-side .ui-deadline { font-size: var(--text-xs); }
.jb-rel-more { display: inline-block; margin-top: var(--s-2); font-size: var(--text-sm); font-weight: var(--weight-medium); }
/* A requirement the CV covers. */
.jb-chip-has { background: var(--ok-soft); border-color: transparent; color: var(--ok); }
.jb-chip-i { flex: 0 0 auto; width: 13px; height: 13px; }
.jb-d-cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  padding: 0 var(--s-6) var(--s-4);
  border-bottom: 1px solid var(--line-soft);
}

/* Dense on purpose: the pane is read top to bottom and the ad text should start within
   one screen, so sections keep 16 px of air, not 20, and the two figures share a row. */
.jb-sec { display: grid; gap: var(--s-2); padding: var(--s-4) var(--s-6); border-bottom: 1px solid var(--line-soft); }
.jb-sec:last-child { border-bottom: none; }
.jb-d-cta .ui-btn.is-on { background: var(--accent-soft); border-color: transparent; color: var(--accent-ink); }
.jb-d-cta:empty { display: none; }
.jb-d-title .ui-new { vertical-align: middle; margin-left: 2px; }
.jb-d-employer-link { color: var(--ink-2); font-weight: var(--weight-medium); }
.jb-d-employer-link:hover { color: var(--accent-ink); }
/* The host another module mounts the company block into (JOBB-SPEC v8). Empty until then. */
.jb-d-employer:empty { display: none; }
.jb-skills { gap: var(--s-2); }
.jb-skill-row { display: grid; grid-template-columns: 88px minmax(0, 1fr); gap: var(--s-3); align-items: start; }
.jb-skill-row .ui-caps { padding-top: var(--s-1); }
.jb-facts-plain { padding: 0; border-bottom: none; gap: var(--s-3) var(--s-4); }




.jb-d-fit .ui-fit-panel h4 { display: flex; align-items: center; gap: var(--s-2); color: var(--ink-3); }
.jb-fit-reason { color: var(--ink-2); font-size: var(--text-sm); line-height: var(--lh-md); }
/* The anonymous nudge: the same box, the three words, one sentence and the two ways in. */
.jb-d-teaser { display: grid; gap: var(--s-2); justify-items: start; }
.jb-teaser-dots { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--ink-2); }
.jb-teaser-dots > span { display: inline-flex; align-items: center; gap: var(--s-1); }
.jb-teaser-text { max-width: 56ch; color: var(--ink-3); font-size: var(--text-sm); line-height: var(--lh-md); }
.jb-teaser-alt { color: var(--ink-3); font-size: var(--text-sm); }

/* Kort om jobbet: the lede reads, the rest of the analysis waits behind a summary. */
.jb-lede { display: grid; gap: var(--s-2); max-width: 68ch; }
.jb-lede-text { color: var(--ink-2); font-size: var(--text-md); line-height: var(--lh-md); }
.jb-lede-want { color: var(--ink-3); font-size: var(--text-md); line-height: var(--lh-md); }
.jb-subgroup { display: grid; gap: var(--s-3); justify-items: start; }
.jb-subgroup > * { max-width: 100%; }
.jb-chip-list { display: flex; flex-wrap: wrap; gap: var(--s-1); }
.jb-req-kind { margin-left: var(--s-1); color: var(--ink-3); font-size: var(--text-xs); font-weight: var(--weight-regular); }
.jb-more > summary { cursor: pointer; color: var(--ink-3); font-size: var(--text-sm); }
.jb-more > summary:hover { color: var(--ink-2); }
.jb-more-body { display: grid; gap: var(--s-4); margin-top: var(--s-3); }
.jb-ideal-text { color: var(--ink-2); font-size: var(--text-sm); line-height: var(--lh-md); max-width: 68ch; }

/* v9: the ad text uses the column it has; 78ch is the ceiling for the pane without a
   side column, where the text would otherwise run the pane's full 900 px. */
.jb-prose { max-width: 86ch; border-bottom: 1px solid var(--line-soft); }
.jb-prose p { margin: 0 0 var(--s-3); }
.jb-prose ul, .jb-prose ol { margin: 0 0 var(--s-3); padding-left: var(--s-5); }
.jb-prose li { margin-bottom: var(--s-1); }
.jb-prose h3 { margin: var(--s-5) 0 var(--s-2); color: var(--ink); font-size: var(--text-lg); }

.jb-dups { display: grid; gap: var(--s-1); font-size: var(--text-sm); color: var(--ink-2); }
.jb-contact-row { color: var(--ink-2); }

/* The initials tile jobb.js puts in the site header once /api/me answers. */
.jb-me {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  overflow: hidden;
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
}
.jb-me:hover { background: var(--selected); text-decoration: none; }
.jb-me img { width: 100%; height: 100%; object-fit: cover; }

/* ---- 900 px and up: the filters are dropdowns, the rail is gone ------------------- */
@media (min-width: 900px) {
  /* .ui-sheet is only ever on the rail below 900 px, but a stale class must not bring
     the rail back into a wide page. */
  .jb-rail, .jb-rail.ui-sheet, .jb-rail-open { display: none; }
}

/* ---- 1200 px and up: list + pane, the pane sticky beside the list ------------------ */
/* Without the rail the two columns get the whole width, so the pane is wide enough for
   the ad and its fit column at 1200 already. jobb.js's wideQuery carries the same number. */
@media (min-width: 1200px) {
  .jb-shell { grid-template-columns: var(--jb-cols); column-gap: var(--jb-gap); }
  .jb-toolbar { grid-template-columns: var(--jb-cols); }
  /* v10c (owner): the filters sit at the far right of the page, under the header's own
     buttons, whatever the pane does below them. */
  .jb-tb-right { justify-content: flex-end; }
  .jb-detail {
    /* v9: the ad is a page you read, not a panel that fills whatever is left. Capped and
       centred in its column, so a wide screen gives it air on both sides. */
    width: 100%;
    max-width: var(--jb-pane-max);
    justify-self: center;
    position: sticky;
    top: var(--jb-stick);
    max-height: var(--jb-fit, calc(100vh - var(--st-head-h) - var(--s-12)));
    overflow: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--line) transparent;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
  }
  .jb-detail-bar { display: none; }
}

/* ---- Narrow ----------------------------------------------------------------------- */
@media (max-width: 899px) {
  .jb-page { padding-top: var(--s-6); }
  /* The dropdowns are gone here: one "Filter" button opens the rail as a sheet. */
  .jb-fbtns { display: none; }
  .jb-search { max-width: none; }
  .jb-d-head, .jb-d-cta, .jb-sec, .jb-prose, .jb-d-side, .ui-panebar { padding-left: var(--s-4); padding-right: var(--s-4); }
  .jb-pagebar { justify-content: center; }
}

/* Under 1200 px the pane is a sheet with its own sticky "Tillbaka till listan" bar (51 px:
   12 + 30 + 8 + the rule); the action bar sticks right under it instead of on top of it. */
@media (max-width: 1199px) {
  .ui-panebar { top: 51px; z-index: 1; }
  .jb-detail-bar { z-index: 2; }
}
/* On a phone the bar is for the actions; the jump links go. */
@media (max-width: 599px) {
  .jb-sort-select { min-width: 0; max-width: 40%; }
  /* The search field gives way before the row does: without this the field keeps its
     content width and pushes the sort dropdown 6 px past the screen edge. */
  .jb-tb-left .jb-search { flex: 1 1 0; min-width: 0; }
  .jb-tb-left .jb-search input { min-width: 0; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .jb-page *, .jb-rail, .jb-detail { transition: none !important; animation: none !important; }
}
