/* ==========================================================================
   Bento-grid layout for the Community Profile widget
   Generic structure + effects only. Client-specific colours (nav buttons)
   live in custom2.css.

   TYPOGRAPHY IS LOCKED. On the /embed page custom2.css is re-included AFTER
   this file (see mod_page_embed_widget.R), so client font rules would normally
   leak into the widget. To keep the bento design consistent across every client
   without per-client testing, all bento font properties (font-family, -size,
   -weight, letter-spacing, …) are declared here with `!important` and always win
   over custom2.css. Override contract for clients (in custom2.css):
     • Rebrand the face        →  .bento-widget { --bento-font-family: <stack>; }
                                   (no !important — overrides the variable below)
     • Any other font override →  bento-prefixed rule WITH !important
                                   (wins because custom2.css loads after this file)
   Non-font overrides (e.g. nav-button colours) need no !important, as before.
   ========================================================================== */

.bento-widget {
  position: relative;            /* positioning context for expanded cards */
  width: 100%;
  min-height: 560px;
  /* Query container so the responsive rules at the bottom of this file react to
     the WIDGET's own width, not the viewport — the widget is commonly embedded
     in an iframe or sits beside other content, where viewport @media can't see
     how narrow the widget actually is. */
  container-type: inline-size;
  container-name: bento;
  --bento-gap: 14px;
  --bento-radius: 16px;
  --bento-pad: 18px;
  /* Height of the footer row — the search pill and every topic-nav button share
     it, which is what keeps them level. Both carry it as an explicit height with
     ZERO vertical padding, so no @container font-size change below can alter it. */
  --bento-btn-h: 44px;
  /* Hairline outline drawn round every tile. Applied as an OUTSET box-shadow, not
     a border: it costs no layout (so it can't disturb the 14%/44px geometry) and
     it can't be hidden by .bento-card-frost::after, which covers the card's own
     box with opaque artwork. Client rebrand hook. */
  --bento-border: rgba(31, 41, 51, 0.12);
  /* Brand colour, used by the active panel tab and focus rings. Resolves to the
     client's own theme automatically: cityviz_container_headless() builds the
     embed page's bs_theme() with primary = config$style$charts$palette[1], so
     --bs-primary is already the first colour of the chart palette the panels are
     drawn in. The literal is the Cranbrook palette head, kept as a fallback for
     any context that loads bento.css without a compiled Bootstrap. Clients that
     want the tab a different colour from their charts set --bento-accent on
     .bento-widget in custom2.css. */
  --bento-accent: var(--bs-primary, #893448);
  /* Corner radius of the boxes INSIDE an expanded panel (the chart frame and the
     data-table overlay that covers it). They must match, or the overlay's corners
     stick out past the frame when the table opens. */
  --bento-panel-radius: 12px;
  --bento-font-family: din-2014, Arial, sans-serif;  /* CityViz face; client rebrand hook */
}

/* Typography lock — bento always uses the CityViz face, never the client's
   body/brand font. Excludes chart SVG text so plotly keeps its own (Roboto)
   font set inline on its <text> nodes. Clients rebrand by overriding
   --bento-font-family on .bento-widget in custom2.css (no !important needed). */
.bento-widget,
.bento-widget :not(svg):not(svg *) {
  font-family: var(--bento-font-family) !important;
}

/* The widget embeds bslib internals (navset_card_tab → .card-header /
   .bslib-navs-card-title / .nav-link; bslib::value_box → .bslib-value-box) that
   carry generic Bootstrap class names. Client custom2.css rules target those
   hooks directly — e.g. `.card-header { text-transform: uppercase; letter-spacing }`
   and `.value-box-showcase { font-size; font-weight }` — and (unlike bento's own
   .bento-* classes) they would leak in. Re-assert neutral, inheriting values here
   so these internals match the bento design on every client. */
.bento-widget .card-header,
.bento-widget .bslib-navs-card-title,
.bento-widget .nav-link,
.bento-widget .bslib-value-box .value-box-title,
.bento-widget .bslib-value-box .value-box-value,
.bento-widget .bslib-value-box .value-box-showcase {
  text-transform: none !important;
  letter-spacing: normal !important;
}

/* Interpretation prose is rendered HTML (p / a / strong / li). Pin its size to the
   .bento-interp-text scale and strip any inherited client transform/spacing, so a
   client `p { font-size }` / `a { letter-spacing }` can't reshape the copy. */
.bento-interp a,
.bento-interp p,
.bento-interp strong,
.bento-interp li {
  font-size: inherit !important;
  letter-spacing: normal !important;
  text-transform: none !important;
}

/* Only the active topic is visible; the rest stay mounted (charts keep state) */
.bento-widget .bento-topic {
  display: none;
}
.bento-widget .bento-topic.is-active {
  display: block;
}

/* A ?panel= embed contains only the panel wrapper. Legacy cityviz.css hides
   #cityviz-widget-charts-panel on desktop because the old layout emitted both
   full and panel variants and selected between them at the mobile breakpoint.
   The bento widgets now emit just the requested variant, so a panel-only
   wrapper must remain visible at every viewport size. The extra class keeps
   this override scoped to the new conditional layout. */
.content-embed #cityviz-widget-charts-panel.bento-widget-panel-only {
  display: block;
}

/* --------------------------------------------------------------------------
   Full-surface topic (e.g. the Business Landscape "Location" map explorer):
   the body fills the whole widget area and the topic-nav row floats over it,
   so the user can still switch back to the other topics. No value boxes/cards.
   -------------------------------------------------------------------------- */
.bento-topic-full {
  position: relative;
  height: 560px;
  border-radius: var(--bento-radius);
  overflow: hidden;
}
.bento-topic-full > div:first-child {
  height: 100%;
}
.bento-topic-full .bento-nav {
  position: absolute;
  left: 50%;
  bottom: 14px;
  transform: translateX(-50%);
  z-index: 500;
  flex: 0 0 auto;
  height: auto;
  width: max-content;
  max-width: calc(100% - 28px);
  padding: 6px;
  gap: 6px;
  background: rgba(255, 255, 255, 0.92);
  border-radius: calc(var(--bento-radius) + 4px);
  box-shadow: 0 4px 16px rgba(31, 41, 51, 0.18);
}
.bento-topic-full .bento-nav-btn {
  flex: 0 0 auto;
  min-width: 92px;
  padding: 8px 14px;
}

/* Two rows: the three-column body, then a footer holding the search pill (at
   column 1's width) beside the topic nav (spanning columns 2 and 3). */
.bento-grid {
  display: flex;
  flex-direction: column;
  gap: var(--bento-gap);
  /* A DEFINITE height (not height:100% against an auto-height .bento-topic, which
     collapses to content height) so the whole flex chain resolves top-down: the
     body, every column and every chart fills this height, and no per-topic content
     can change the grid height. This is what actually stops the topic-to-topic
     bounce. */
  height: 560px;
  align-items: stretch;
}

/* Three proportional columns (mirrors the mock proportions) */
.bento-grid-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  gap: var(--bento-gap);
  align-items: stretch;
}

/* The pill's 14% flex-basis resolves against the SAME inner width as
   .bento-col-values-wrap's — both rows are full-width children of .bento-grid,
   and a percentage basis is measured before `gap` comes out of free space. With
   the same gap on both rows, the nav's left edge therefore lands exactly on
   column 2's and its right edge on column 3's. `flex-shrink: 0` plus the
   `min-width: 0` on the button (see below) are what hold that alignment. */
.bento-grid-footer {
  flex: 0 0 var(--bento-btn-h);
  display: flex;
  gap: var(--bento-gap);
  min-height: 0;
}

.bento-col {
  display: flex;
  flex-direction: column;
  gap: var(--bento-gap);
  min-width: 0;
}

.bento-col-values-wrap { flex: 0 0 14%; min-height: 0; }
.bento-col-main        { flex: 1 1 50%; min-height: 0; }
.bento-col-side        { flex: 1 1 36%; min-height: 0; }

/* bento_layout_wide(): one surface in place of columns 2 AND 3 (the Business
   Landscape "Location" map). Column 1 and the footer are unchanged, so this
   topic lines up exactly with its card-based sibling. */
.bento-col-main-wide { flex: 1 1 auto; min-height: 0; }
.bento-main-full {
  /* The explore module's controls are an absolutePanel SIBLING of the map div,
     so this is the positioned ancestor that keeps them inside the surface. */
  position: relative;
  flex: 1 1 auto;
  min-height: 0;                /* never drive the grid height */
  border-radius: var(--bento-radius);
  overflow: hidden;             /* clip the map to the rounded corners */
  box-shadow: 0 0 0 1px var(--bento-border);
}
/* The controls panel carries an INLINE max-height: calc(100vh - 120px) sized for
   a full-page map (mod_widget_explore.R); inside this ~500px surface that lets
   an open Filters accordion run past the clipped edge with Apply/Reset out of
   reach. Only !important beats the inline style.

   cityviz.js/.css implement a "grow the panel while a selectize list is open"
   hatch (.dropdown-open => max-height: none) so a long list stays visible on a
   full-page map. That hatch is actively harmful in a bounded surface — the panel
   balloons to its full content height, overflows the 500px box by ~330px and is
   clipped by the `overflow: hidden` above, putting Filters' Apply/Reset out of
   reach for as long as the control keeps focus. The bento surface opts out of it
   in both directions (hence the .dropdown-open selector, which outranks
   cityviz.css's own !important on specificity rather than load order), which is
   also what makes the open dropdown reachable — see the rule below. Do NOT drop
   the .dropdown-open half: without it the panel balloons past the clipped edge
   again the moment a list opens. */
.bento-main-full .panel-controls,
.bento-main-full .panel-controls.dropdown-open {
  max-height: calc(100% - 20px) !important;
  overflow-y: auto !important;
}
/* The panel above is the ONLY scroller in this surface, exactly as the Filters
   accordion behaves: expanding a control grows what the panel scrolls over
   rather than opening a scroll box of its own. Giving the list back its own cap
   nests a second scroller inside the first, and both bars end up on screen at
   once.
   The list can be uncapped here because .selectize-dropdown is absolutely
   positioned inside .selectize-control (`position: relative`), i.e. its
   containing block is inside the panel — so it extends the panel's SCROLLABLE
   OVERFLOW and the panel's single scrollbar reaches the whole list.
   This is also what cityviz.css sets for every other .panel-controls in the app,
   so the bento surface is no longer a special case.
   `max-height: none` is what actually removes the inner scroller; the
   `overflow-y` below still COMPUTES to `auto` (per spec, `visible` paired with
   selectize's own `overflow-x: hidden` computes to `auto`) — it just has nothing
   left to scroll. It is kept for parity with the cityviz.css rule. */
.bento-main-full .panel-controls .selectize-dropdown-content {
  max-height: none;
  overflow-y: visible;
}
/* The explore module's own bottom-centre CityViz credit (its `is_widget` footer,
   which we keep for the controls panel's widget positioning) lands on top of the
   MapLibre attribution strip in this shorter surface. The widget already carries
   .bento-powered-by below the grid, so drop the inner one rather than the flag. */
.bento-main-full .panel-footer {
  display: none;
}

/* --------------------------------------------------------------------------
   Column 1 — unified value-box card (the search pill sits in the grid footer)
   -------------------------------------------------------------------------- */
.bento-col-values {
  flex: 1 1 auto;            /* fill column 1 */
  min-height: 0;            /* don't let the value boxes grow the grid past its baseline */
  background: #f6f6f6;
  border-radius: var(--bento-radius);
  box-shadow: 0 0 0 1px var(--bento-border);
  padding: var(--bento-pad);
  gap: var(--bento-pad);
}

.bento-vbox {
  flex: 1 1 0;
  min-height: 0;            /* share the column height; never drive it (prevents topic-to-topic bounce) */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 4px;
}
.bento-vbox + .bento-vbox {
  padding-top: var(--bento-pad);
}
.bento-vbox-icon {
  font-size: 1.6rem !important;
  /*color: var(--cv-brand-color, #3E4C59);*/
  color: #afafaf;
  opacity: 0.85;
}
.bento-vbox-value {
  font-size: 2rem !important;
  font-weight: 800 !important;
  line-height: 1.05 !important;
  color: #1f2933;
}
.bento-vbox-label {
  font-size: 0.875rem !important;
  color: #1f2933;
  line-height: 1.25 !important;
}

/* --------------------------------------------------------------------------
   Column 2 — hero card (fills the body row; the nav lives in the footer)
   -------------------------------------------------------------------------- */
.bento-main-hero {
  flex: 1 1 auto;
  min-height: 0;
}

/* --------------------------------------------------------------------------
   Topic nav — the footer row's right-hand element, spanning columns 2 and 3
   -------------------------------------------------------------------------- */
.bento-nav {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  gap: var(--bento-gap);
}
.bento-nav-btn {
  flex: 1 1 0;
  min-width: 0;                   /* beat a <button>'s automatic minimum size */
  height: var(--bento-btn-h);
  display: flex;
  flex-direction: row;            /* icon beside label — 44px is too short to stack */
  align-items: center;
  justify-content: center;
  gap: 8px;
  overflow: hidden;
  border: none;
  border-radius: var(--bento-radius);
  padding: 0 12px;                /* no vertical padding: the height is font-size-proof */
  cursor: pointer;
  font-size: 14px !important;
  color: #ffffff;
  background: #7B8794;            /* fallback; per-topic colours in custom2.css */
  transition: transform 0.15s ease, opacity 0.15s ease, box-shadow 0.15s ease;
  opacity: 0.82;
}
.bento-nav-btn:hover {
  opacity: 1;
  transform: translateY(-1px);
}
.bento-nav-btn.is-active {
  opacity: 1;
  box-shadow: 0 0 0 2px rgba(31, 41, 51, 0.18) inset;
}
.bento-nav-icon { font-size: 1rem !important; line-height: 1 !important; }
/* Long captions ("Workforce Outlook", fr "Perspectives de la main-d'œuvre") get a
   SECOND line rather than an ellipsis: two 0.85rem lines are ~30px, which still
   clears --bento-btn-h. Clamped at two so a caption can never grow the button.
   The old stacked nav relied on free wrapping for these; this preserves that
   without giving up the fixed height. */
.bento-nav-label {
  font-size: 0.85rem !important;      /* matches .bento-search-btn-label */
  font-weight: 600 !important;
  text-transform: none !important;
  letter-spacing: normal !important;
  text-align: center;
  line-height: 1.1 !important;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: break-word;          /* last resort: wrap, never spill */
}

/* --------------------------------------------------------------------------
   Column 3 — one card (grow) over a row of two cards
   -------------------------------------------------------------------------- */
.bento-side-top {
  flex: 1.1 1 0;
  min-height: 0;
}
/* Top card in column 3: instead of frosted glass, a fully-opaque photo covers
   the card content. The heading still sits above it; clicking expands the card
   (the overlay is hidden in the expanded state, revealing the content). */
.bento-topic[data-topic="demographics"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-demographic.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="workforce"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-workforce.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="family"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-family.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="housing"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-housing.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="commute"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-commute.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="businesses"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-businesses.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="employment"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-employment.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="outlook"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-outlook.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="status"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-status.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="education"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-education.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="regional"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-regional.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="industry"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-industry.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="construction"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-construction.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="affordability"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-affordability.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.bento-topic[data-topic="business_counts"] .bento-side-top .bento-card .bento-card-frost::after {
  background: url("../img/bento-heading-bg-business_counts.png") center / cover no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
/* The heading's white plate (shared rule below, on .bento-card-heading::before)
   reads over the photo too — and its masked backdrop blur frosts the photo
   behind the title, so no photo-specific override is needed here. */

/* Both bottom cards in column 3 get the same treatment: opaque artwork replaces
   the frost entirely, so NO collapsed card anywhere shows a live chart. Keyed
   off data-topic like the side-top rules above (which is why a topic used by two
   widgets — housing, commute, outlook, businesses — shares its artwork).

   FULL-BLEED (`cover`), exactly like the side-top photos, and that is what gives
   these cards their frosted glass: .bento-card-heading::before is a masked
   backdrop-blur, so it can only frost what actually sits behind it. An earlier
   version contained the artwork ABOVE the heading band on white — the plate then
   had nothing but flat white to blur and the effect vanished. Anything that keeps
   artwork out of the bottom ~90px of the card loses the frost again.

   These are 3:2 illustrations in a ~0.9-aspect cell, so `cover` keeps the central
   ~60% of each image's width; the source art is centred with white margins, so
   what's cropped is mostly margin. */
.bento-side-bottom .bento-side-cell .bento-card .bento-card-frost::after {
  background-color: #ffffff;       /* opaque fallback; matches the artwork's ground */
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
/* Community Profile */
.bento-topic[data-topic="demographics"] .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-1.png"); }
.bento-topic[data-topic="demographics"] .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-2.png"); }
.bento-topic[data-topic="workforce"]    .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-3.png"); }
.bento-topic[data-topic="workforce"]    .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-4.png"); }
.bento-topic[data-topic="family"]       .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-5.png"); }
.bento-topic[data-topic="family"]       .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-6.png"); }
.bento-topic[data-topic="housing"]      .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-7.png"); }
.bento-topic[data-topic="housing"]      .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-8.png"); }
.bento-topic[data-topic="commute"]      .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-9.png"); }
.bento-topic[data-topic="commute"]      .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-10.png"); }
/* Housing (housing = 7/8 above, shared with Community Profile) */
.bento-topic[data-topic="construction"]   .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-1.png"); }
.bento-topic[data-topic="construction"]   .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-2.png"); }
.bento-topic[data-topic="affordability"]  .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-3.png"); }
.bento-topic[data-topic="affordability"]  .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-4.png"); }
/* Workforce Profile (commute = 9/10 above, shared with Community Profile) */
.bento-topic[data-topic="status"]    .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-5.png"); }
.bento-topic[data-topic="status"]    .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-6.png"); }
.bento-topic[data-topic="industry"]  .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-7.png"); }
.bento-topic[data-topic="industry"]  .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-8.png"); }
.bento-topic[data-topic="education"] .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-1.png"); }
.bento-topic[data-topic="education"] .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-2.png"); }
.bento-topic[data-topic="regional"]  .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-3.png"); }
.bento-topic[data-topic="regional"]  .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-4.png"); }
/* Industry Profiles */
.bento-topic[data-topic="outlook"]    .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-5.png"); }
.bento-topic[data-topic="outlook"]    .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-6.png"); }
.bento-topic[data-topic="businesses"] .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-7.png"); }
.bento-topic[data-topic="businesses"] .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-8.png"); }
.bento-topic[data-topic="employment"] .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-9.png"); }
.bento-topic[data-topic="employment"] .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-10.png"); }
/* Business Landscape */
.bento-topic[data-topic="business_counts"] .bento-side-bottom .bento-side-cell:nth-child(1) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-1.png"); }
.bento-topic[data-topic="business_counts"] .bento-side-bottom .bento-side-cell:nth-child(2) .bento-card .bento-card-frost::after { background-image: url("../img/bento-chart-2.png"); }

.bento-side-bottom {
  flex: 1 1 0;
  display: flex;
  gap: var(--bento-gap);
  min-height: 0;
}
.bento-side-cell {
  flex: 1 1 0;
  min-width: 0;
  min-height: 0;
}

/* --------------------------------------------------------------------------
   Bento cards + frosted glass
   -------------------------------------------------------------------------- */
.bento-card {
  position: relative;
  height: 100%;
  border-radius: var(--bento-radius);
  overflow: hidden;
  background: #ffffff;
  box-shadow: 0 0 0 1px var(--bento-border);
  cursor: pointer;
}

/* The actual card content (navset + chart) lives here */
.bento-card-frost {
  position: relative;
  height: 100%;
}
.bento-card-frost .bslib-card,
.bento-card-frost .card {
  height: 100% !important;
  border: none;
  background: transparent;
  box-shadow: none;
  padding: 15px;
}

/* Frost overlay sits ON TOP of the content and blurs it.
   FALLBACK PATH ONLY: every side card is covered by opaque artwork (the
   .bento-side-top and .bento-side-bottom rules above) and the hero has its own
   lighter frost below, so nothing renders this in practice — it shows up if a
   new topic is added without an artwork rule, or if an image 404s. Kept light so
   that failure mode stays gentle.
   NOTE the veil below is only the DEFAULT: a client `.bento-card-frost::after
   { background: … }` in custom2.css (0,1,1) ties this rule and wins on load
   order, so what actually paints here is the client's tint. It cannot reach the
   hero (0,2,1) or the artwork rules (0,5,1). Only the blur is guaranteed. */
.bento-card-frost::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: rgba(255, 255, 255, 0.35);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  transition: backdrop-filter 0.2s ease, background 0.2s ease;
}
/* Hero card: much lighter frost so it stays readable */
.bento-card--hero .bento-card-frost::after {
  background: rgba(215, 215, 215, 0.6);
  -webkit-backdrop-filter: blur(1.5px);
  backdrop-filter: blur(1.5px);
}

/* Heading hint sits ABOVE the frost, anchored to the BOTTOM of the card */
.bento-card-heading {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 3;
  padding: 28px 18px 33px 33px;
  pointer-events: none;
}
/* The white plate behind the heading lives on this pseudo-element (not the
   heading background) so its TOP edge can fade out instead of meeting the
   frosted glass on a hard line. Both layers taper together toward the top:
   the white wash via the gradient, the blur via the mask. It reaches above the
   text (top: -26px) so the fade clears the title, and z-index: -1 keeps it
   behind the (opaque) heading text. On the photo cards the masked blur also
   frosts the photo behind the title. */
.bento-card-heading::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: -26px;
  z-index: -1;
  background: linear-gradient(
    to top,
    rgba(255, 255, 255, 0.7),
    rgba(255, 255, 255, 0.7) 85%,
    rgba(255, 255, 255, 0)
  );
  -webkit-backdrop-filter: blur(5px);
          backdrop-filter: blur(5px);
  -webkit-mask-image: linear-gradient(to top, #000 75%, transparent);
          mask-image: linear-gradient(to top, #000 75%, transparent);
}
.bento-card-heading-primary {
  font-size: 1.9rem !important;
  font-weight: 800 !important;
  color: #1f2933;
  line-height: 1.1 !important;
}
.bento-card--frosted .bento-card-heading-primary {
  font-size: 1.7rem !important;
}
.bento-card-heading-secondary {
  margin-top: 4px;
  font-size: 1rem !important;
  font-weight: 600 !important;
  color: #3E4C59;
  opacity: 0.85;
}

/* Hover "twitch" hint that the card is interactive */
@keyframes bento-twitch {
  0%   { transform: scale(1) rotate(0deg); }
  30%  { transform: scale(1.012) rotate(-0.3deg); }
  60%  { transform: scale(1.012) rotate(0.3deg); }
  100% { transform: scale(1) rotate(0deg); }
}
/* Every box-shadow below RESTATES the hairline: box-shadow doesn't cascade
   per-layer, so omitting it here would drop the outline on hover/expand. */
.bento-card:not(.bento-expanded):hover {
  animation: bento-twitch 0.4s ease;
  box-shadow: 0 0 0 1px var(--bento-border), 0 8px 24px rgba(31, 41, 51, 0.18);
}

/* --------------------------------------------------------------------------
   Expanded state — fills the widget area only
   -------------------------------------------------------------------------- */
.bento-card.bento-expanded {
  position: absolute;
  inset: 0;
  /* Above .panel-controls (z-index 1450, cityviz.css): the Location topic's map
     controls share this stacking context — no ancestor between them creates one
     — and would otherwise paint on top of the expanded search card. */
  z-index: 1500;
  height: auto;
  cursor: default;
  /* INSET here, unlike the collapsed hairline: an expanded card is inset:0 against
     .bento-widget, so an outset ring would paint 1px outside the widget's box (and
     get shaved by a flush iframe edge). The frost is hidden in this state, so an
     inset ring is visible. */
  box-shadow: 0 0 0 1px var(--bento-border) inset, 0 12px 40px rgba(31, 41, 51, 0.28);
}
.bento-card.bento-expanded .bento-card-frost::after {
  display: none;            /* remove frost so content is interactive */
}
.bento-card.bento-expanded .bento-card-heading {
  display: none;            /* hide the hint; real tab pills are now visible */
}

/* Collapsed secondary cards are chart-only teasers: hide the information column
   so the frosted chart fills the card and every box keeps a constant height.
   The hero keeps its interpretation visible (lighter frost, readable). On expand
   the column is revealed automatically (the :not(.bento-expanded) stops matching). */
.bento-card--frosted:not(.bento-expanded) .bento-interp {
  display: none;
}

/* The hero keeps a HINT of its interpretation while collapsed. Pin the prose to
   a constant few-line height (faded at the bottom) so the hero's height no
   longer depends on how long each topic's interpretation is — varying prose
   length is what still made the grid bounce. The full text shows on expand. */
.bento-card--hero:not(.bento-expanded) .bento-interp-text {
  height: 4.6em;            /* ~3 lines of the 0.85rem interp text — constant */
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 60%, transparent);
          mask-image: linear-gradient(to bottom, #000 60%, transparent);
}

/* Expanded cards reveal the full interpretation; let it scroll if it's long. */
.bento-card.bento-expanded .bento-interp {
  overflow-y: auto;
}

.bento-close {
  display: none;
  position: absolute;
  top: 10px;
  right: 14px;
  z-index: 60;
  width: 34px;
  height: 34px;
  line-height: 30px;
  text-align: center;
  font-size: 1.5rem !important;
  border-radius: 50%;
  background: rgba(31, 41, 51, 0.08);
  color: #1f2933;
  cursor: pointer;
}
.bento-close:hover { background: rgba(31, 41, 51, 0.18); }
.bento-card.bento-expanded .bento-close { display: block; }

/* --------------------------------------------------------------------------
   Panel tabs — an underline strip, not Bootstrap's folder tabs

   THREE SELECTOR SHAPES, on purpose. navset_card_tab() emits BS3 markup
   (`ul.nav-tabs > li.active > a`, no .nav-item/.nav-link anywhere) and bslib's
   bs3compat Sass @extends the BS5 rules onto it, so the compiled stylesheet
   carries `.nav-link`, `.nav-tabs>li>a` AND `.card-header-tabs .nav-tabs>li>a.active`
   variants of every rule. Which one is live depends on whether .active sits on the
   <li> (server render) or on the <a> (after bs3compat's tab plugin runs). Matching
   all three is what stops a second underline appearing once a tab is clicked.

   Every selector here leads with .bento-widget .bento-card, i.e. (0,3,x) or more,
   which clears Bootstrap's (0,2,1)-and-below AND the client's
   `.content-embed .card-header` (0,2,0) in custom2.css. Fonts carry !important
   per this file's typography lock: custom2.css sets --bs-nav-link-font-size /
   -font-weight / -color, which the anchors would otherwise inherit.
   -------------------------------------------------------------------------- */
.bento-widget .bento-card .card-header {
  padding: 0;
  margin-bottom: 14px;
  background: transparent;
  border-bottom: none;
  border-radius: 0;
}
.bento-widget .bento-card .nav-tabs.card-header-tabs,
.bento-widget .bento-card .nav-tabs {
  margin: 0;
  gap: 10px;
  /* Restated because .card-header-tabs zeroes it; this hairline is the strip the
     active tab's 3px underline sits on. */
  /*border-bottom: 1px solid var(--bento-border);*/
  border-bottom: 1px solid transparent;
}
.bento-widget .bento-card .nav-tabs > li > a,
.bento-widget .bento-card .nav-tabs .nav-link {
  margin: 0 0 -1px 0;        /* pull the underline down ONTO the strip's hairline */
  padding: 4px 6px 12px;
  border: none;
  border-bottom: 3px solid transparent;
  border-radius: 0;
  background: transparent;
  color: #52606d;
  font-size: 1rem !important;
  font-weight: 600 !important;
  text-transform: none !important;
  letter-spacing: normal !important;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.bento-widget .bento-card .nav-tabs > li > a:hover,
.bento-widget .bento-card .nav-tabs .nav-link:hover {
  color: #1f2933;
  border-color: transparent transparent var(--bento-border);
}
.bento-widget .bento-card .nav-tabs > li.active > a,
.bento-widget .bento-card .nav-tabs > li > a.active,
.bento-widget .bento-card .nav-tabs .nav-link.active {
  color: var(--bento-accent);
  background: transparent;
  border-color: transparent transparent var(--bento-accent);
}
/* Bootstrap's own focus ring on these anchors is a blue glow, which lands next to
   the accent underline; match the tool buttons' ring instead. */
.bento-widget .bento-card .nav-tabs > li > a:focus-visible,
.bento-widget .bento-card .nav-tabs .nav-link:focus-visible {
  outline: 2px solid var(--bento-accent);
  outline-offset: -2px;
  box-shadow: none;
}

/* --------------------------------------------------------------------------
   Chart + interpretation split inside each panel
   -------------------------------------------------------------------------- */
.bento-panel-split {
  display: flex;
  gap: 16px;
  height: 100%;
  min-height: 0;
}
.bento-panel-chart {
  position: relative;          /* anchor for the data-table overlay */
  flex: 2 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* Hairline frame round the chart, EXPANDED ONLY — that is the state the user
   sees the frame in. Collapsed teasers are either opaque artwork (side cards) or
   frosted (hero), where a frame would only show up as a blurred ghost box.
   Padding keeps plotly's axis labels off the frame; the data-table overlay's
   `inset: 0` resolves against the PADDING box, so it covers that padding but
   leaves the frame visible — hence both share --bento-panel-radius. */
.bento-card.bento-expanded .bento-panel-chart {
  /*border: 1px solid var(--bento-border);*/
  border: 1px solid transparent;
  border-radius: var(--bento-panel-radius);
  padding: 10px;
}
.bento-panel-chart-canvas {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* Let a SINGLE chart/map fill the panel height, so it grows with the card when
   expanded. The fixed pixel height set by plotlyOutput() is overridden here.
   :only-child means KPI-gauge stacks (multiple widgets in one panel) are left
   at their fixed heights; if a panel doesn't match, it just keeps today's size. */
.bento-panel-chart-canvas > .html-widget:only-child {
  flex: 1 1 0;
  height: 100% !important;   /* beats the inline height:300px from plotlyOutput() */
  min-height: 0;
}

/* Right-hand information column: top-aligned stack of title, interpretation,
   tools, reference, and the bottom-right "Powered by CityViz" credit. */
.bento-interp {
  flex: 1 1 0;
  min-width: 0;
  min-height: 0;
  overflow: hidden;        /* clip an over-long interpretation; never grow the card */
  display: flex;
  flex-direction: column;
  align-self: stretch;
  font-size: 0.85rem !important;
  color: #52606d;
  line-height: 1.45 !important;
}
.bento-interp-title {
  font-size: 1.4rem !important;
  font-weight: 800 !important;
  line-height: 1.15 !important;
  color: #1f2933;
  margin-bottom: 10px;
}
.bento-interp-text { margin-bottom: 14px; font-size: 16px !important; }
.bslib-card .card-body .bento-interp-text p:last-child { margin-bottom: 0; }

/* Tools row: outlined "Data table" + "Download chart" buttons.
   WRAPS on purpose. .bento-interp is `flex: 1 1 0` against the chart's `flex: 2 1 0`
   and clips (`overflow: hidden`), so in a narrow widget the two buttons exceed the
   column and the second would be sliced off rather than pushed to a new line. */
.bento-chart-tools {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  row-gap: 8px;
  margin-bottom: 18px;
  margin-top: 2rem;
}
.bento-chart-tool {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  /* Wrapping the ROW can't rescue a single button that is wider than the column;
     these let one shrink and wrap its own label instead of overflowing. Measured
     at a 600px widget: "Download chart" is 163px in a 167px column — it fits, but
     with 4px to spare, so a longer translation or a client font would clip. */
  max-width: 100%;
  min-width: 0;              /* beat a <button>'s automatic minimum size */
  border: 1px solid var(--bento-border);
  border-radius: 10px;
  padding: 10px 18px;
  font-size: 0.85rem !important;
  font-weight: 600 !important;
  cursor: pointer;
  color: #1f2933;
  background: #e6e6e6;
  transition: color 0.15s ease, background-color 0.15s ease,
              border-color 0.15s ease, transform 0.15s ease;
}
/* fontawesome::fa() sets fill:currentColor and height inline, so the glyph tracks
   the label's colour on hover with no rule of its own; it only needs to be kept
   from shrinking when a long label wraps. */
.bento-chart-tool svg { flex: 0 0 auto; }
.bento-chart-tool:hover {
  background: #f5f7fa;
  border-color: rgba(31, 41, 51, 0.28);
  transform: translateY(-1px);
}
.bento-chart-tool:focus-visible { outline: 2px solid var(--bento-accent); outline-offset: 2px; }

/* Reference block (data source / region / period) */
.bento-interp-reference {
  padding-top: 16px;
  font-size: 0.72rem !important;
  line-height: 1.4 !important;
  color: #7b8794;
}
.bento-interp-reference .references p { margin-bottom: 2px; }
.bento-interp-reference .references strong { color: #52606d; }

/* Per-card credit, pushed to the bottom-right of the column */
.bento-panel-powered {
  margin-top: auto;
  padding-top: 10px;
  text-align: right;
  font-size: 0.75rem !important;
  line-height: 1.2 !important;
  color: #9aa5b1;
}
.bento-panel-powered a { color: #9aa5b1; text-decoration: none; }
.bento-panel-powered a:hover { text-decoration: underline; }

/* --------------------------------------------------------------------------
   Data-table overlay (accessible alternative to the chart)
   -------------------------------------------------------------------------- */
.bento-data-table-overlay {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: none;
  background: #ffffff;
  border-radius: var(--bento-panel-radius);   /* must match the chart frame */
  overflow: hidden;
}
.bento-data-table-overlay.is-open { display: block; padding-top: 25px; }
.bento-data-table-scroll {
  height: 100%;
  overflow: auto;
  padding: 8px 14px 14px;
}
.bento-table-close {
  position: absolute;
  top: 6px;
  right: 8px;
  z-index: 5;
  width: 30px;
  height: 30px;
  line-height: 26px;
  text-align: center;
  font-size: 1.4rem !important;
  border: none;
  border-radius: 50%;
  background: rgba(31, 41, 51, 0.08);
  color: #1f2933;
  cursor: pointer;
}
.bento-table-close:hover { background: rgba(31, 41, 51, 0.18); }

.bento-data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8rem !important;
  color: #1f2933;
}
.bento-data-table caption {
  text-align: left;
  font-weight: 700 !important;
  padding: 4px 0 10px;
  color: #1f2933;
}
.bento-data-table th,
.bento-data-table td {
  padding: 6px 10px;
  text-align: right;
  border-bottom: 1px solid #e4e7eb;
  white-space: nowrap;
}
.bento-data-table thead th { border-bottom: 2px solid #cbd2d9; }
.bento-data-table th[scope="col"]:first-child,
.bento-data-table th[scope="row"],
.bento-data-table td:first-child {
  text-align: left;
}
.bento-data-table th[scope="row"] { font-weight: 600 !important; }

/* Tab pills under frost get a little breathing room below the heading */
.bento-card .bslib-navs-card-title .nav {
  margin-top: 2px;
}

/* --------------------------------------------------------------------------
   Search button (grid footer, left of the topic nav) + search card overlay
   -------------------------------------------------------------------------- */
/* The geometric twin of .bento-nav-btn with the fill INVERTED: a white plate
   with coloured text/icon and a subtle ring, against the nav's solid pills.
   The ring is an inset box-shadow, not a border, so it can never disturb the
   14% width or the shared height. min-width: 0 is load-bearing — a <button>'s
   automatic minimum size would otherwise push the pill past 14% at narrow
   widths and pull the nav's left edge off column 2. */
.bento-grid-footer .bento-search-btn {
  flex: 0 0 14%;
  min-width: 0;
  height: var(--bento-btn-h);
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 8px;
  overflow: hidden;
  border: none;
  border-radius: var(--bento-radius);
  padding: 0 12px;
  cursor: pointer;
  color: #1f2933;                /* fallback; client colour in custom2.css */
  background: #ffffff;
  box-shadow: 0 0 0 1.5px rgba(31, 41, 51, 0.18) inset;
  transition: color 0.15s ease, background-color 0.15s ease,
              box-shadow 0.15s ease, transform 0.15s ease;
}
.bento-grid-footer .bento-search-btn:hover {
  color: #ffffff;
  background: #1f2933;
  box-shadow: 0 0 0 1.5px #1f2933 inset;
  transform: translateY(-1px);
}
.bento-search-btn-icon { font-size: 1rem !important; line-height: 1 !important; }
.bento-search-btn-label {
  font-size: 0.85rem !important;
  font-weight: 600 !important;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The search card is hidden until the search button expands it. The generic
   .bento-card.bento-expanded rules above supply the absolute overlay + the
   visible close (×); we only toggle visibility and let the body scroll. */
.bento-search-card { display: none; }
.bento-search-card.bento-expanded { display: block; }
.bento-search-card .bento-search-body {
  height: 100%;
  overflow-y: auto;
  padding: 28px;
}

/* --------------------------------------------------------------------------
   "Powered by CityViz" credit — bottom-right of the widget
   -------------------------------------------------------------------------- */
.bento-powered-by {
  text-align: right;
  padding: 8px 14px 0;
  font-size: 0.75rem !important;
  line-height: 1.2 !important;
  color: #9aa5b1;
}
.bento-powered-by a {
  color: #8f9ba8;
  text-decoration: none;
}
.bento-powered-by a:hover { text-decoration: underline; }

/* --------------------------------------------------------------------------
   Responsive — as the widget narrows, scale a few elements down so the layout
   stays legible WITHOUT changing the grid geometry. Queried against the
   .bento-widget container (see container-type above) so it reacts to the
   WIDGET's own width — embedded in an iframe or sitting beside other content in
   the app — not the viewport.

   Two tiers (≤960px, then a tighter ≤680px) each shrink:
     • side-bottom card titles — the two narrowest cards, whose long single-word
       titles ("Ethnicity", "Languages") would otherwise clip. Scoped to
       .bento-side-bottom so the wider side-top card and the column-2 hero keep
       their full size. We deliberately keep these two cards side-by-side rather
       than stacking them: stacking made column 3 hold three cards that spilled
       past the fixed-height grid and overlapped the nav row.
     • topic-nav labels/icons — smaller, with tighter button padding, so the
       captions don't crowd or ellipsise when the row is tight. These can never
       change the buttons' HEIGHT: .bento-nav-btn and .bento-search-btn both
       carry an explicit --bento-btn-h with no vertical padding, which is what
       keeps the footer row level at every width.
     • value-box values (.bento-vbox-value) — smaller/lighter so the big numbers
       don't dominate the narrowed value column.
   -------------------------------------------------------------------------- */
@container bento (max-width: 960px) {
  /* Drop the big left/right indent (keep the top padding so the heading's soft
     fade still clears the title) and trim the title so "Ethnicity" /
     "Languages" keep fitting their half-width cells — they start clipping at
     ~1.7rem well before 800px. */
  .bento-side-bottom .bento-card-heading {
    padding: 28px 14px 30px 16px;
  }
  .bento-side-bottom .bento-card-heading-primary {
    font-size: 1.4rem !important;
    overflow-wrap: break-word;   /* last resort: wrap, never hard-clip */
  }
  .bento-side-bottom .bento-card-heading-secondary {
    font-size: 0.9rem !important;
  }
  /* Topic-nav captions: smaller, with tighter button padding, so the labels stay
     on one line as the row tightens. */
  .bento-nav-label { font-size: 0.78rem !important; }
  .bento-nav-btn   { gap: 6px; padding: 0 10px; }
  /* Value-box numbers: smaller/lighter so they don't dominate the narrow column. */
  .bento-vbox-value {
    font-size: 1.8rem !important;
    font-weight: 700 !important;
  }
}

/* Tighter tier: same elements as ≤960px, shrunk further for very narrow widgets
   (only the changed properties are restated; the rest cascade from ≤960px). */
@container bento (max-width: 680px) {
  .bento-side-bottom .bento-card-heading {
    padding: 28px 12px 26px 14px;
  }
  .bento-side-bottom .bento-card-heading-primary {
    font-size: 0.85rem !important;
  }
  .bento-side-bottom .bento-card-heading-secondary {
    font-size: 0.82rem !important;
  }
  /* Shrink the ICON too: a fixed 16px glyph plus padding would otherwise eat most
     of the label's budget in the widest nav (Workforce Profile's six buttons are
     ~86px each at this width). */
  .bento-nav-label { font-size: 0.7rem !important; }
  .bento-nav-icon  { font-size: 0.85rem !important; }
  .bento-nav-btn   { gap: 4px; padding: 0 8px; }
  /* 14% of a 680px container is ~95px — tighten the pill so its label fits
     without the automatic minimum size pushing it past 14% (which would pull the
     nav's left edge off column 2). */
  .bento-grid-footer .bento-search-btn { gap: 4px; padding: 0 8px; }
  .bento-search-btn-label { font-size: 0.72rem !important; }
  .bento-vbox-value {
    font-size: 1.6rem !important;
    font-weight: 600 !important;
  }
}
