.imaptic-map-wrap{
  --imaptic-bg: #f4f4f5;
  --imaptic-point: #2271b1;
  --imaptic-point-hover: #ffffff;
  --imaptic-point-border: #ffffff;
  --imaptic-point-border-width: 3px;
  --imaptic-radar: #2271b1;
  --imaptic-text: #1d2327;
  --imaptic-map-stroke: #9ca3af;
  --imaptic-map-outline: #6b7280;
  --imaptic-hover-fill: #2271b1;
  --imaptic-point-size: 14px;
  --imaptic-list-bg: #ffffff;
  --imaptic-list-text: #1d2327;
  --imaptic-list-border: #e5e7eb;
  --imaptic-list-border-width: 1px;
  --imaptic-list-hover: #f4f4f5;
  --imaptic-tooltip-bg: #ffffff;
  --imaptic-tooltip-border: #e5e7eb;
  --imaptic-tooltip-border-width: 0px;
  --imaptic-tooltip-radius: 6px;
  --imaptic-tooltip-font-size: 13px;
  display:flex;
  flex-wrap:nowrap; /* the list must never wrap to its own line below the map — always beside it, even on narrow screens */
  gap:0;
  background:var(--imaptic-bg);
  /* overflow:visible (was :hidden) — a point tooltip near the wrap's own
     edge (top row, or a corner inset box like Canàries/Ceuta/Melilla) got
     its text cut off mid-line instead of floating above everything, in
     every layout mode (Disseny orientation/split, any breakpoint) —
     `overflow:hidden` here was clipping it at the wrap's own box edge
     regardless of z-index (a hard visual boundary, unrelated to stacking
     order — no z-index can "escape" an ancestor's overflow clip). This was
     only ever here to contain content within layout.border_radius's
     rounded corners; a tooltip always being fully readable takes priority
     over a theoretical square corner poking past the rounded border in an
     extreme edge case (an uploaded image/map SVG filling the box exactly
     to its own corner, itself uncommon since the SVG's own viewBox
     scaling and the crop margin usually leave some background showing). */
  overflow:visible;
  box-sizing:border-box;
}
/* border-radius is always set inline per-map (Imaptic_Admin_Map_Editor
   layout.border_radius, default 8px) — no stylesheet default needed. */
.imaptic-map-wrap.has-list.list-left{flex-direction:row-reverse}

/* Disseny (layout.orientation/split/split_ratio, Imaptic_Maps_Shortcode::
   render()) — orientation and split are two independent switches, not a
   fixed set of named presets.
   Orientation: reuses the SAME list-left/list-right meaning as horizontal
   (list "before" or "after" the map in visual order) instead of a separate
   top/bottom field — list-right (default) = list after the map (below, in
   a column); list-left = list before it (above). Needs MORE specificity
   (4 classes) than the existing 3-class .has-list.list-left rule above to
   reliably win regardless of stylesheet order when both apply. */
.imaptic-map-wrap.is-vertical{flex-direction:column}
.imaptic-map-wrap.is-vertical.has-list.list-left{flex-direction:column-reverse}

/* Split: an explicit map/list % (any ratio the admin picks — 50/50, 80/20,
   whatever) instead of the list's own natural size ("Lliure", unchanged
   default, no rules below ever apply then). Horizontal: pure CSS %, a
   row's own width is always definite so this just works via --imaptic-
   split-stage/-list (set inline per map). Vertical needs real computed
   pixel heights instead — a percentage flex-basis along the COLUMN axis
   has nothing definite to resolve against on an auto-height container
   (spec: falls back to `auto`, silently ignored) — so render() already did
   that math server-side and set an explicit height on the wrap AND the
   list panel, plus --imaptic-stage-max-height on the stage (reusing the
   exact same .imaptic-stage-fixed-height mechanism layout.max_height alone
   already uses, below) — flex:0 0 auto here just lets those explicit
   heights win instead of flex stretching/shrinking them. */
.imaptic-map-wrap.is-split:not(.is-vertical) .imaptic-stage{flex:0 0 var(--imaptic-split-stage, 50%)}
.imaptic-map-wrap.is-split:not(.is-vertical) .imaptic-list-panel:not(.is-collapsed){flex:0 0 var(--imaptic-split-list, 50%);min-width:0}
/* Collapsing the list still has to free its share back to the map, same
   expectation as "Lliure" — :not(.is-collapsed) above stops the fixed %
   from fighting the plain .is-collapsed{flex-basis:44px} rule (which would
   otherwise lose to this rule's higher specificity), and :has() here makes
   the map grow into the space that frees up instead of leaving a gap
   (flex:0 0 % never grows on its own). Vertical+split has no equivalent —
   the stage's height there comes from an explicit computed px height
   (--imaptic-stage-max-height, see render()), not a flex-basis %, so
   overriding flex alone wouldn't let it grow past that fixed height;
   collapsing the list in that specific combination leaves the freed space
   unused rather than reclaimed, a known, accepted gap for now. */
.imaptic-map-wrap.is-split:not(.is-vertical):has(.imaptic-list-panel.is-collapsed) .imaptic-stage{flex:1 1 auto}
.imaptic-map-wrap.is-vertical.is-split .imaptic-stage{flex:0 0 auto}
.imaptic-map-wrap.is-vertical.is-split .imaptic-list-panel:not(.is-collapsed){flex:0 0 auto;min-height:0;max-height:none}

/* Disseny, per breakpoint (layout.responsive.tablet/mobile) — Imaptic_Maps_
   Shortcode::render() always emits ONE of is-horizontal-{bp}/is-vertical-
   {bp} AND one of is-free-{bp}/is-split-{bp} together whenever a
   breakpoint override exists at all (never just one half), and every rule
   below is written against the FULL, EXPLICIT pair (e.g. `.is-horizontal-
   tablet.is-split-tablet`), not just one class — because the desktop rules
   above have NO media guard (by design, they're the fallback whenever a
   breakpoint has no override) and stay active at every width including
   inside these @media blocks, an override that only flips ONE of the two
   axes (e.g. desktop vertical+ratio, tablet wants horizontal+SAME ratio)
   would otherwise leave the desktop's OTHER, unflipped half (`.is-
   vertical`'s flex-direction:column) still winning at that width — every
   combination needs to fully restate BOTH axes' outcome, not just the one
   that changed, so there's always an explicit, higher-specificity rule
   here to override whatever the desktop classes alone would have done.
   Breakpoints match Elementor's own defaults (this site is built with
   it): tablet 768-1024px, mobile ≤767px. Vertical+split here can't reuse
   .imaptic-stage-fixed-height/--imaptic-stage-max-height the way the
   desktop version does — that class only reflects the DESKTOP setting
   (could be absent even when a breakpoint override needs a fixed height)
   — so the stage's own height/flex/media sizing is spelled out again
   directly against the -tablet/-mobile suffixed vars instead of leaning
   on that class. */
@media (min-width:768px) and (max-width:1024px) {
  .imaptic-map-wrap.is-horizontal-tablet.is-free-tablet{flex-direction:row}
  .imaptic-map-wrap.is-horizontal-tablet.is-free-tablet.has-list.list-left{flex-direction:row-reverse}
  .imaptic-map-wrap.is-horizontal-tablet.is-free-tablet .imaptic-stage{flex:1 1 640px}
  .imaptic-map-wrap.is-horizontal-tablet.is-free-tablet .imaptic-list-panel{flex:0 1 260px;min-width:150px;min-height:0;max-height:var(--imaptic-list-max-height, 100vh)}

  .imaptic-map-wrap.is-horizontal-tablet.is-split-tablet{flex-direction:row}
  .imaptic-map-wrap.is-horizontal-tablet.is-split-tablet.has-list.list-left{flex-direction:row-reverse}
  .imaptic-map-wrap.is-horizontal-tablet.is-split-tablet .imaptic-stage{flex:0 0 var(--imaptic-split-stage-tablet, 50%)}
  .imaptic-map-wrap.is-horizontal-tablet.is-split-tablet .imaptic-list-panel:not(.is-collapsed){flex:0 0 var(--imaptic-split-list-tablet, 50%);min-width:0}
  .imaptic-map-wrap.is-horizontal-tablet.is-split-tablet:has(.imaptic-list-panel.is-collapsed) .imaptic-stage{flex:1 1 auto}

  .imaptic-map-wrap.is-vertical-tablet.is-free-tablet{flex-direction:column;height:auto}
  .imaptic-map-wrap.is-vertical-tablet.is-free-tablet.has-list.list-left{flex-direction:column-reverse}
  .imaptic-map-wrap.is-vertical-tablet.is-free-tablet .imaptic-stage{flex:1 1 640px}
  .imaptic-map-wrap.is-vertical-tablet.is-free-tablet .imaptic-list-panel{flex:0 1 260px;min-width:0;min-height:120px}

  .imaptic-map-wrap.is-vertical-tablet.is-split-tablet{flex-direction:column;height:var(--imaptic-wrap-height-tablet)}
  .imaptic-map-wrap.is-vertical-tablet.is-split-tablet.has-list.list-left{flex-direction:column-reverse}
  .imaptic-map-wrap.is-vertical-tablet.is-split-tablet .imaptic-stage{flex:0 0 auto;height:var(--imaptic-stage-max-height-tablet);display:flex;align-items:center;justify-content:center}
  .imaptic-map-wrap.is-vertical-tablet.is-split-tablet .imaptic-media{width:min(100%, calc(var(--imaptic-stage-max-height-tablet) * var(--imaptic-media-ratio, 1)));flex-shrink:0}
  .imaptic-map-wrap.is-vertical-tablet.is-split-tablet .imaptic-list-panel:not(.is-collapsed){flex:0 0 auto;height:var(--imaptic-list-height-tablet);min-height:0;max-height:none}

  .imaptic-map-wrap.is-vertical-tablet .imaptic-list-panel.is-collapsed{flex-basis:44px;min-height:44px;max-height:44px;min-width:0;max-width:none}
  .imaptic-map-wrap.is-vertical-tablet .imaptic-list-panel .imaptic-list-header{width:100%;right:0;left:0}
}
@media (max-width:767px) {
  .imaptic-map-wrap.is-horizontal-mobile.is-free-mobile{flex-direction:row}
  .imaptic-map-wrap.is-horizontal-mobile.is-free-mobile.has-list.list-left{flex-direction:row-reverse}
  .imaptic-map-wrap.is-horizontal-mobile.is-free-mobile .imaptic-stage{flex:1 1 640px}
  .imaptic-map-wrap.is-horizontal-mobile.is-free-mobile .imaptic-list-panel{flex:0 1 260px;min-width:150px;min-height:0;max-height:var(--imaptic-list-max-height, 100vh)}

  .imaptic-map-wrap.is-horizontal-mobile.is-split-mobile{flex-direction:row}
  .imaptic-map-wrap.is-horizontal-mobile.is-split-mobile.has-list.list-left{flex-direction:row-reverse}
  .imaptic-map-wrap.is-horizontal-mobile.is-split-mobile .imaptic-stage{flex:0 0 var(--imaptic-split-stage-mobile, 50%)}
  .imaptic-map-wrap.is-horizontal-mobile.is-split-mobile .imaptic-list-panel:not(.is-collapsed){flex:0 0 var(--imaptic-split-list-mobile, 50%);min-width:0}
  .imaptic-map-wrap.is-horizontal-mobile.is-split-mobile:has(.imaptic-list-panel.is-collapsed) .imaptic-stage{flex:1 1 auto}

  .imaptic-map-wrap.is-vertical-mobile.is-free-mobile{flex-direction:column;height:auto}
  .imaptic-map-wrap.is-vertical-mobile.is-free-mobile.has-list.list-left{flex-direction:column-reverse}
  .imaptic-map-wrap.is-vertical-mobile.is-free-mobile .imaptic-stage{flex:1 1 640px}
  .imaptic-map-wrap.is-vertical-mobile.is-free-mobile .imaptic-list-panel{flex:0 1 260px;min-width:0;min-height:120px}

  .imaptic-map-wrap.is-vertical-mobile.is-split-mobile{flex-direction:column;height:var(--imaptic-wrap-height-mobile)}
  .imaptic-map-wrap.is-vertical-mobile.is-split-mobile.has-list.list-left{flex-direction:column-reverse}
  .imaptic-map-wrap.is-vertical-mobile.is-split-mobile .imaptic-stage{flex:0 0 auto;height:var(--imaptic-stage-max-height-mobile);display:flex;align-items:center;justify-content:center}
  .imaptic-map-wrap.is-vertical-mobile.is-split-mobile .imaptic-media{width:min(100%, calc(var(--imaptic-stage-max-height-mobile) * var(--imaptic-media-ratio, 1)));flex-shrink:0}
  .imaptic-map-wrap.is-vertical-mobile.is-split-mobile .imaptic-list-panel:not(.is-collapsed){flex:0 0 auto;height:var(--imaptic-list-height-mobile);min-height:0;max-height:none}

  .imaptic-map-wrap.is-vertical-mobile .imaptic-list-panel.is-collapsed{flex-basis:44px;min-height:44px;max-height:44px;min-width:0;max-width:none}
  .imaptic-map-wrap.is-vertical-mobile .imaptic-list-panel .imaptic-list-header{width:100%;right:0;left:0}
}

.imaptic-stage{
  flex:1 1 640px;
  min-width:0; /* let an explicit max-width (layout.max_width) actually shrink it */
}
/* layout.max_height: the stage takes it as a real height (below) instead of
   only capping the media element — in a narrow column, width (not height)
   is normally what limits the map's size, so a plain cap on the image never
   had anything to bite on and the map stayed small regardless of the value
   entered. */
.imaptic-stage.imaptic-stage-fixed-height{
  height:var(--imaptic-stage-max-height);
  display:flex;
  align-items:center;
  justify-content:center;
}

/* .imaptic-media locks the map's own aspect ratio (--imaptic-media-ratio,
   from the SVG viewBox or the uploaded image's dimensions — see
   Imaptic_Maps_Shortcode::render()) as an actual CSS box, so the points/
   texts overlay (plain % position against THIS box) always lines up with
   the visible map, whatever shape the stage itself ends up being. */
.imaptic-media{
  position:relative;
  line-height:0;
  width:100%;
  aspect-ratio:var(--imaptic-media-ratio, 1);
}
/* Fixed-height stage: the stage's own box is very likely a different shape
   than the map (e.g. a tall narrow column vs a wide world map), so .imaptic-
   media can't just stay 100% wide — it needs to solve for the largest box
   of the map's own ratio that fits both the available width AND the fixed
   height. width:min(100%, height×ratio) with height left auto (derived back
   from that resolved width via aspect-ratio) does exactly that — the same
   result object-fit:contain gives an <img>, but working for the plain <div>
   wrapper this needs to be (object-fit has no effect on the inline <svg>
   library maps use, confirmed live: the SVG's own viewBox scaling letterboxes
   the drawing correctly, but a plain width/height:100% box around it doesn't
   shrink to match, so the overlay above would stay full-size and drift off
   the actual coastline instead of following it). */
.imaptic-stage-fixed-height .imaptic-media{
  width:min(100%, calc(var(--imaptic-stage-max-height) * var(--imaptic-media-ratio, 1)));
  flex-shrink:0;
}

/* height:auto by default (unqualified) — also shared by the admin editor's
   canvas preview (Imaptic_Maps_Library::get_svg_tagged() output is reused
   there via #imaptic-canvas-svg, which has no .imaptic-media ratio wrapper
   around it, just an auto-height container) so it must keep resolving its
   size the old way, from the media's own intrinsic ratio. Only the frontend
   markup, nested inside a ratio-locked .imaptic-media, gets height:100%. */
.imaptic-bg{display:block;width:100%;height:auto}
.imaptic-map-svg{display:block;width:100%;height:auto;overflow:visible}
.imaptic-media .imaptic-bg,
.imaptic-media .imaptic-map-svg{height:100%}
/* !important throughout this block: themes/page builders (Elementor's editor
   included) sometimes ship broad `svg path{fill:...}` resets for icon
   consistency, which otherwise beat these rules and leave every map either
   solid black (no fill/stroke at all) or stuck on a default colour no matter
   what's picked in the editor. */
/* Qualified with the .imaptic-map-svg ancestor (not just the bare class) to
   raise specificity a notch above a typical theme/page-builder reset — most
   commonly something like `svg path{fill:...}` or `.elementor-widget path`. */
.imaptic-map-svg .imaptic-country{fill:var(--imaptic-bg) !important}
.imaptic-map-svg .imaptic-country[hidden]{display:none}
.imaptic-map-svg .imaptic-country-isolated{
  /* Islands etc. drawn via their own mini-projection aren't covered by the
     mainland's mesh-based borders/outline, so without their own stroke
     they're only as visible as their fill happens to contrast with the
     surrounding background. */
  stroke:var(--imaptic-map-outline) !important;
  stroke-width:1;
  vector-effect:non-scaling-stroke;
}
.imaptic-map-svg .imaptic-borders{
  fill:none !important;
  stroke:var(--imaptic-map-stroke) !important;
  stroke-width:.6;
  vector-effect:non-scaling-stroke;
  pointer-events:none;
}
.imaptic-map-svg .imaptic-outline{
  fill:none !important;
  stroke:var(--imaptic-map-outline) !important;
  stroke-width:1.2;
  vector-effect:non-scaling-stroke;
  pointer-events:none;
}
.imaptic-map-svg .imaptic-inset-box{
  fill:none !important;
  stroke:var(--imaptic-map-outline) !important;
  stroke-width:1;
  stroke-dasharray:4 3;
  vector-effect:non-scaling-stroke;
  pointer-events:none;
}

/* Per-zone hover — independent of points, toggled per map (hover_enabled) */
.imaptic-map-svg.imaptic-hover-enabled .imaptic-country{
  cursor:pointer;
  transition:fill .3s ease, filter .3s ease;
}
.imaptic-map-svg.imaptic-hover-enabled .imaptic-country:hover{
  fill:var(--imaptic-hover-fill) !important;
  filter:drop-shadow(0 0 4px var(--imaptic-hover-fill)) drop-shadow(0 0 12px var(--imaptic-hover-fill));
}
/* Hover groups: territories that should glow together even though they're
   separate shapes with their own data-region (so "Zones visibles" can still
   show/hide them one by one) share a data-hover-group value — the built-in
   Iberia template still ships everything under "es" by default, and a map's
   own "Agrupacions de hover" config can define any custom grouping instead
   (Imaptic_Maps_Shortcode::apply_zone_groups() rewrites the attribute per
   map at render time). Because the group id is arbitrary/admin-chosen, CSS
   alone can't match "siblings sharing the SAME value" generically the way
   the old id-specific :has() rule here used to (only ever worked for "es") —
   assets/js/frontend-map.js finds a hovered/externally-triggered country's
   group siblings live (by data-hover-group) and toggles this class on all of
   them. A plain, direct :hover (above) still covers the single-country/
   ungrouped case with no JS needed. */
.imaptic-map-svg.imaptic-hover-enabled .imaptic-country.imaptic-group-glow{
  fill:var(--imaptic-hover-fill) !important;
  filter:drop-shadow(0 0 4px var(--imaptic-hover-fill)) drop-shadow(0 0 12px var(--imaptic-hover-fill));
}

/* Point hover also glows the zone underneath it (point_hover_zone_enabled) —
   a JS-added class (assets/js/frontend-map.js finds the country via real SVG
   hit-testing, .imaptic-point-hover-zone), deliberately NOT the country's own
   :hover, so this never trips .imaptic-radar-enabled below (that's keyed
   strictly off a real :hover on the country itself). Same fill/glow as a
   direct zone hover, plus the same hover-group spread. */
.imaptic-map-svg.imaptic-hover-enabled .imaptic-country.imaptic-point-hover-zone{
  fill:var(--imaptic-hover-fill) !important;
  filter:drop-shadow(0 0 4px var(--imaptic-hover-fill)) drop-shadow(0 0 12px var(--imaptic-hover-fill));
}
/* Group spread for the point-hover-zone case above now goes through the same
   .imaptic-group-glow class/JS as plain zone hover (frontend-map.js adds it
   to the found zone's group siblings too) — no id-specific CSS needed here
   either, same reason as the plain-hover rule above. */

/* Radar pulse (radar_enabled): points ping like a sonar sweep while a zone is
   genuinely :hover'd — but only the points actually INSIDE that zone, not
   every point on the map. Which points are inside a given country isn't
   stored anywhere, so assets/js/frontend-map.js finds them live the same way
   it finds a point's own zone (real SVG hit-testing, isPointInFill — just in
   the opposite direction: for the hovered country, which points does IT
   contain), and toggles .imaptic-point-in-hovered-zone on those specific
   pins. Deliberately its own class, never .imaptic-point-hover-zone above,
   so hovering a POINT can't set every point on the map pulsing just because
   its own zone lit up.
   Two rings (::before/::after), one started half a cycle after the other, so
   a new ring is always mid-fade by the time the previous one vanishes — a
   single ring reads as a discrete "blip, gap, blip"; overlapping ones read as
   a continuous, fluid sweep. A soft cubic-bezier (slow start, fast middle,
   gentle finish) instead of linear ease-out for the same reason. Rings start
   already larger than the dot itself (130%) and reach further out (scale 3.4)
   so the effect has real presence instead of hugging the pin. */
/* Only two keyframes (0%/100%), not three: a mid-point opacity-only stop
   (there used to be one at 60%) forces the browser to restart the
   animation-timing-function's easing curve fresh at that boundary — for a
   soft-but-uneven curve like this cubic-bezier, that reads as a visible
   stutter/"cut" partway through the pulse (reported live: "com si tingués
   lag"), since opacity's rate of change jumps abruptly right at 60% while
   transform (which only ever had 0%/100%) keeps gliding smoothly. Letting
   opacity interpolate across the *same* single 0%→100% span as transform
   removes the seam; the bezier's own slow-start/faster-middle/gentle-finish
   shape still gives the "lingers, then fades" feel the mid-keyframe was
   going for, just without the discontinuity. */
@keyframes imaptic-radar-pulse{
  0%   { transform:translate(-50%,-50%) scale(1); opacity:.6; }
  100% { transform:translate(-50%,-50%) scale(3.4); opacity:0; }
}
.imaptic-point-dot{ position:relative }
.imaptic-point-dot::before,
.imaptic-point-dot::after{
  content:"";
  position:absolute;
  left:50%; top:50%;
  width:130%; height:130%;
  transform:translate(-50%,-50%);
  border-radius:50%;
  border:2px solid var(--imaptic-radar);
  opacity:0;
  pointer-events:none;
}
.imaptic-media.imaptic-radar-enabled .imaptic-point.is-in-hovered-zone .imaptic-point-dot::before,
.imaptic-media.imaptic-radar-enabled .imaptic-point.is-in-hovered-zone .imaptic-point-dot::after{
  animation:imaptic-radar-pulse 1.8s cubic-bezier(.2,.6,.35,1) infinite;
}
.imaptic-media.imaptic-radar-enabled .imaptic-point.is-in-hovered-zone .imaptic-point-dot::after{
  animation-delay:.9s;
}
/* Touch: tapping a zone (assets/js/frontend-map.js, `(hover: none)`) plays
   the SAME pulse a fixed 3 times instead of indefinitely — a touchscreen
   has no real hover state to hold the effect open while a finger stays
   down, and no natural "leave" gesture to end it either, so `infinite`
   (the :hover-driven version above) would never stop on its own. `3`
   (not infinite) is real, literal CSS iteration-count — the browser stops
   painting the animation on its own once done; the class itself still
   needs removing afterwards (assets/js/frontend-map.js, a matching
   timeout) so a later tap can retrigger it — re-adding a class that's
   already present doesn't restart a finished CSS animation. */
.imaptic-media.imaptic-radar-enabled .imaptic-point.is-radar-pulse-once .imaptic-point-dot::before,
.imaptic-media.imaptic-radar-enabled .imaptic-point.is-radar-pulse-once .imaptic-point-dot::after{
  animation:imaptic-radar-pulse 1.8s cubic-bezier(.2,.6,.35,1) 3;
}
.imaptic-media.imaptic-radar-enabled .imaptic-point.is-radar-pulse-once .imaptic-point-dot::after{
  animation-delay:.9s;
}

/* pointer-events:none: this full-coverage layer otherwise sits on top of the
   map (later in DOM order than the <img>/<svg>) and captures every pointer
   event across the whole area, blocking the per-zone hover glow underneath
   even where there's no actual pin. Individual points opt back in below. */
.imaptic-points{position:absolute;inset:0;pointer-events:none}

/* !important on border/background/outline/box-shadow/padding: themes
   commonly style every <button> (hover/focus states included, often with
   their own padding and an accent-colour fill) at the same specificity as
   this class selector — without !important, whichever stylesheet loads
   later silently wins the tie (same bug class as .imaptic-list-toggle's
   display:flex below). Left as a coloured box / oversized hit area
   otherwise. */
.imaptic-point{
  position:absolute;
  transform:translate(-50%,-50%);
  appearance:none;
  border:0 !important;
  background:none !important;
  outline:none !important;
  box-shadow:none !important;
  /* Clickable/hoverable area used to be a flat 10px on every side
     regardless of point size or border width — on a small dot (min 4px)
     that made the invisible hit zone read as much bigger than the dot
     itself ("s'activa abans d'arribar al punt"). Tied to the point's own
     border-ring width (+2px slack for comfortable clicking) so the hit
     area tracks what's actually drawn instead of a fixed oversized box. */
  padding:calc(var(--imaptic-point-border-width, 3px) + 2px) !important;
  margin:0;
  cursor:pointer;
  line-height:0;
  pointer-events:auto;
  /* z-index:auto (the default) means a point's tooltip — even with its own
     z-index below — only ever outranks content INSIDE that same point; a
     later point in the DOM that happens to sit nearby still paints its dot
     on top of an earlier point's open tooltip card, since sibling .imaptic-
     point boxes stack by plain DOM order otherwise. Promoting the point
     that's actually showing its tooltip (below) above every other point
     fixes that regardless of placement order. */
  z-index:1;
}
.imaptic-point:hover,
.imaptic-point:focus,
.imaptic-point:focus-visible,
.imaptic-point:active,
.imaptic-point.is-active{
  border:0 !important;
  background:none !important;
  outline:none !important;
  box-shadow:none !important;
  z-index:10;
}
.imaptic-point-dot{
  display:block;
  width:var(--imaptic-point-own-size, var(--imaptic-point-size));
  height:var(--imaptic-point-own-size, var(--imaptic-point-size));
  border-radius:50%;
  background:var(--imaptic-point-own-color, var(--imaptic-point));
  box-shadow:0 0 0 var(--imaptic-point-border-width, 3px) var(--imaptic-point-border, #ffffff);
  transition:transform .2s ease, background-color .2s ease;
}
.imaptic-point:hover .imaptic-point-dot,
.imaptic-point:focus-visible .imaptic-point-dot,
.imaptic-point.is-active .imaptic-point-dot{
  background:var(--imaptic-point-hover);
  transform:scale(1.4);
}

.imaptic-point-tooltip{
  position:absolute;
  bottom:100%;
  left:50%;
  transform:translate(-50%,6px);
  margin-bottom:8px;
  min-width:120px;
  max-width:220px;
  background:var(--imaptic-tooltip-bg, #ffffff);
  color:var(--imaptic-text);
  border:var(--imaptic-tooltip-border-width, 0) solid var(--imaptic-tooltip-border, transparent);
  border-radius:var(--imaptic-tooltip-radius, 6px);
  box-shadow:0 4px 16px rgba(0,0,0,.18);
  padding:8px 10px;
  font-size:var(--imaptic-tooltip-font-size, 13px);
  line-height:1.4;
  text-align:left;
  white-space:normal;
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transition:opacity .18s ease, transform .18s ease;
  z-index:5;
}
.imaptic-point-tooltip strong{display:block}
.imaptic-point:hover .imaptic-point-tooltip,
.imaptic-point:focus-visible .imaptic-point-tooltip,
.imaptic-point.is-active .imaptic-point-tooltip{
  opacity:1;
  visibility:visible;
  transform:translate(-50%,0);
}

.imaptic-texts{position:absolute;inset:0;pointer-events:none}
.imaptic-text-item{
  position:absolute;
  transform:translate(-50%,-50%);
  white-space:nowrap;
  font-weight:600;
  line-height:1.2;
  color:var(--imaptic-text-item-color, var(--imaptic-text));
  font-size:var(--imaptic-text-item-size, 16px);
}

.imaptic-list-panel{
  /* shrink:1 (not 0): in a narrow container the list gives up width
     proportionally alongside the map instead of staying rigidly 260px and
     forcing the map alone to absorb the whole deficit. min-width keeps it
     usable (search box, text) even when the container is very tight. */
  flex-grow:0;
  flex-shrink:1;
  flex-basis:260px;
  min-width:150px;
  max-width:100%;
  background:var(--imaptic-list-bg) !important;
  color:var(--imaptic-list-text) !important;
  display:flex;
  flex-direction:column;
  border-left:var(--imaptic-list-border-width) solid var(--imaptic-list-border);
  position:relative; /* anchors the floating .imaptic-list-header below */
  /* visible (not hidden): the heading is a position:absolute child that must
     be able to render past this panel's own edge once the panel collapses
     narrower than the heading's text — see .imaptic-list-header below. The
     body still can't spill, but it has its own overflow:auto. */
  overflow:visible;
  transition:flex-basis .28s ease, min-width .28s ease, max-width .28s ease;
  /* Capped at 85% of the map's own rendered height (--imaptic-list-max-
     height, kept in sync with .imaptic-stage's actual height by a
     ResizeObserver in assets/js/frontend-map.js — the map's height is
     itself derived from its aspect-ratio + width, not a fixed number, so
     this can't be a plain CSS percentage of a sibling) — on request, so an
     expanded list doesn't stretch to match a very tall map; whatever
     doesn't fit in that 85% scrolls internally (.imaptic-list-body's own
     overflow:auto, below) same as it always did, just against a lower
     ceiling. Falls back to 100vh (the previous behaviour, capped at the
     viewport instead) if JS hasn't run yet or ResizeObserver is
     unavailable, so this never regresses to unbounded growth either way. */
  max-height:var(--imaptic-list-max-height, 100vh);
}
.list-left .imaptic-list-panel{border-left:0;border-right:var(--imaptic-list-border-width) solid var(--imaptic-list-border)}
/* Vertical + "Lliure": flex-basis:260px above becomes the panel's default
   HEIGHT in a column context (a reasonable-enough default as-is) — only
   min-width:150px (a width concern, irrelevant/harmful once the panel
   stretches to the wrap's full width every time in this orientation) needs
   overriding, with an equivalent min-height floor instead. */
.imaptic-map-wrap.is-vertical .imaptic-list-panel{min-width:0;min-height:120px}

/* Collapsed = the panel itself narrows back down to a slim rail (frees the
   width for the map, `flex:1 1 640px`, to grow into) — but the heading
   (icon + name) is a `position:absolute` overlay anchored to the panel's
   OUTER edge (the one that never moves: `right:0` when the list sits on the
   right, `left:0` when it sits on the left — only the INNER edge, facing the
   map, actually shifts as the panel's width changes), so it stays fixed on
   screen in exactly the same spot in both states and simply floats over the
   map once the rail beneath it narrows past the text's own width. An
   earlier version tried keeping the panel's width constant instead (so the
   heading, an ordinary in-flow child, never had to move) — dropped because
   the user explicitly wanted collapsing to free real width back to the map
   ("deixem pas al mapa movent la llista, però no la paraula"), which only a
   width-collapsing panel actually does. `.imaptic-list-body`'s own
   `border-top` is "the line" the heading sits above — it's part of the
   panel's own (shrinking) box, so it starts right under the fixed heading
   and is only ever as wide as the panel currently is. */
.imaptic-list-panel.is-collapsed{
  flex-shrink:0;
  flex-basis:44px;
  min-width:44px;
  max-width:44px;
}
/* Vertical: collapsing shrinks HEIGHT back to a slim strip instead of
   width — same "frees space back to the map" mechanic, just along the
   other axis. Needs 4 classes to reliably beat the 2-class rule above
   regardless of stylesheet order. */
.imaptic-map-wrap.is-vertical .imaptic-list-panel.is-collapsed{
  flex-basis:44px;
  min-height:44px;
  max-height:44px;
  min-width:0;
  max-width:none;
}

/* width:260px matches .imaptic-list-panel's own flex-basis (its normal,
   uncollapsed width) — anchoring THIS fixed-width box to the outer edge
   (right:0, the one that never moves — see the collapse comment above)
   means its OWN left-aligned content (icon+name, justify-content:flex-
   start on the button below) lines up with the panel's left border in the
   normal expanded state, while staying put — same box, same position —
   when the panel collapses to its 44px rail: only the invisible box's
   right portion (now over the still-collapsed body) goes unused, the
   heading itself never shifts. z-index and background keep it above and
   opaque over .imaptic-list-body (position:relative, in-flow, stacks
   below by DOM order alone, but a comfortably explicit z-index avoids any
   ambiguity) — the heading must always read over the list, never be
   covered by the search box or item rows sitting right below it. */
/* Explicit height (not just padding, whose rendered total depended on the
   label's own line-height and drifted a few px depending on font/icon
   metrics) — .imaptic-list-body's margin-top below has to clear EXACTLY
   this many px or the sticky search box sits partly underneath it ("el
   buscador encara està mig tapat"), so the two are pinned to the same
   value instead of two separately hand-guessed numbers that could drift
   out of sync. */
.imaptic-list-header{
  position:absolute;
  top:0;
  right:0;
  width:260px;
  max-width:100%;
  height:48px;
  box-sizing:border-box;
  z-index:5;
  padding:0 14px;
  display:flex;
  align-items:center;
  white-space:nowrap;
  background:var(--imaptic-list-bg);
}
.list-left .imaptic-list-header{right:auto;left:0}
/* Vertical: the panel is always full-width regardless of collapsed state
   (only its HEIGHT collapses) — the fixed-260px-anchored-to-the-never-
   moving-edge trick above exists specifically to counteract a WIDTH
   collapse, so it's unneeded complexity here; just span the panel's own
   always-full width instead. 3 classes to reliably beat .list-left's 2. */
.imaptic-map-wrap.is-vertical .imaptic-list-panel .imaptic-list-header{width:100%;right:0;left:0}
/* !important throughout this block: themes ship broad `button`/`[type=button]`
   resets (background/border/color, plus a solid :hover/:focus fill in an
   accent colour) that otherwise leak into these plain, chrome-less buttons —
   same bug class as .imaptic-point above, just on the list's own controls. */
.imaptic-list-toggle{
  /* !important on display:flex too — themes' own button resets often set
     display:inline-block on every <button>, and without !important that
     silently won the cascade here (unlike the other properties on this
     rule, which were already hardened): the chevron span ended up
     display:inline as a result (not blockified as a flex item), and
     width/height are ignored on inline non-replaced boxes — it collapsed
     down to a sliver instead of the intended 7x7px chevron. */
  display:flex !important;align-items:center;justify-content:flex-start;gap:8px;
  background:none !important;border:0 !important;padding:0;font-weight:600;font-size:14px;
  cursor:pointer;color:inherit !important;text-align:left;
  white-space:nowrap;
}
/* :hover/:focus/:active used to force color:inherit — i.e. no visible
   feedback at all, indistinguishable from the resting state ("hovers...
   que no podem canviar res") — now picks up the list's own accent colour
   instead, which the fallback chevron (border-color:currentColor) and any
   text both follow automatically; an admin-chosen icon image can't be
   recoloured this way, same limitation as any other image swap in this
   plugin. */
.imaptic-list-toggle:hover,
.imaptic-list-toggle:focus,
.imaptic-list-toggle:active{
  background:none !important;border:0 !important;color:var(--imaptic-list-accent, var(--imaptic-point)) !important;
}

/* Toggle icon/arrow: two separate elements — one shown while expanded (the
   "will collapse" state), one while collapsed (the "will expand" state) —
   each is either an admin-chosen image (list.icon_open/icon_closed) or,
   when that's not set, a chevron built from a rotated border corner (no
   icon asset needed). Only one of the pair is ever visible at a time, so
   each can have a fixed rotation instead of needing an is-collapsed-
   conditional flip like a single shared arrow would. */
.imaptic-list-toggle-icon,
.imaptic-list-toggle-arrow,
.imaptic-list-toggle-iconfont{ flex:0 0 auto }
.imaptic-list-toggle-icon{ width:14px; height:14px; object-fit:contain; display:block }
.imaptic-list-toggle-arrow{
  width:7px;height:7px;
  border-style:solid;
  border-width:0 2px 2px 0;
  border-color:currentColor;
  transition:transform .25s ease;
}
/* A CSS icon-font class (list.icon_open_class/icon_closed_class — Dashicons,
   Font Awesome, Elementor's own eicons…) instead of an uploaded image —
   takes priority over icon_open/icon_closed when set (Imaptic_Maps_
   Shortcode::render()'s own if/elseif/else). display:block (not inline,
   these libraries' own base styles usually already set that but not always)
   and font-size fixed rather than inherited from the button's own 14px, so
   a much larger glyph a library ships by default doesn't blow out the
   heading's line height. color comes from the button's own `color`
   (inherit normally, --imaptic-list-accent on hover — see below) via
   currentColor, same mechanism the fallback chevron already uses. */
.imaptic-list-toggle-iconfont{ display:block; font-size:14px; line-height:1; color:currentColor }
.imaptic-list-panel.is-collapsed .imaptic-list-toggle-icon-open,
.imaptic-list-panel.is-collapsed .imaptic-list-toggle-arrow-open,
.imaptic-list-panel.is-collapsed .imaptic-list-toggle-iconfont-open{display:none}
.imaptic-list-toggle-icon-closed,
.imaptic-list-toggle-arrow-closed,
.imaptic-list-toggle-iconfont-closed{display:none}
.imaptic-list-panel.is-collapsed .imaptic-list-toggle-icon-closed,
.imaptic-list-panel.is-collapsed .imaptic-list-toggle-arrow-closed,
.imaptic-list-panel.is-collapsed .imaptic-list-toggle-iconfont-closed{display:block}

/* Open → right, collapsed → left (the reverse) for the default list-right
   panel; mirrored for list-left (open → left, collapsed → right) — back to
   per-side mirroring on request, since a horizontally-collapsing panel
   reads better with a horizontal (left/right) arrow than the previous
   down/up pair. */
.imaptic-list-toggle-arrow-open{transform:rotate(-45deg)}
.imaptic-list-toggle-arrow-closed{transform:rotate(135deg)}
.list-left .imaptic-list-toggle-arrow-open{transform:rotate(135deg)}
.list-left .imaptic-list-toggle-arrow-closed{transform:rotate(-45deg)}

/* margin-top clears the floating .imaptic-list-header — 48px, matching its
   own explicit height exactly (both used to be separately hand-guessed
   numbers, ~44px each, that could drift apart depending on font/icon
   metrics; the sticky search box below sat partly underneath the header
   whenever they did, "el buscador encara està mig tapat"). border-top is
   "the line" itself, starting right under the heading and only as wide as
   the panel currently is — see the collapse comment above .imaptic-list-
   panel.is-collapsed. flex:1 (not a fixed max-height) so the item list
   fills whatever height the panel actually has — matching the map's own
   height via the wrap's stretch — instead of always stopping at an
   arbitrary number regardless of how tall the map ends up being.
   min-height:0 is required for overflow:auto to actually kick in on a flex
   child rather than growing past its parent. */
/* padding-right (not 0): the scrollbar .imaptic-list-body's own
   overflow:auto draws otherwise sits flush against the item text with no
   breathing room ("el scroll lateral que no tapi el text") — a few px of
   extra right padding gives it its own lane, closer to the panel's own
   edge than the text. NO top padding (unlike the other three sides) — a
   scrolling container's own padding is still part of its visible
   scrollport (overflow only clips at the BORDER edge, not the padding
   edge), so a nonzero padding-top here left an uncovered strip between
   the header above and wherever .imaptic-list-search-wrap's sticky
   top:0 actually landed (offset by that same padding) — content scrolling
   underneath could still show through in exactly that strip ("el que hi
   ha sota el buscador no s'ha de veure"). The vertical breathing room that
   padding-top used to give now lives on .imaptic-list-search-wrap's own
   padding-top (safely part of its opaque sticky block) and on
   .imaptic-list's own padding-top (for when there's no search box to
   provide it) instead. */
.imaptic-list-body{
  margin-top:48px;
  border-top:1px solid rgba(0,0,0,.06);
  padding:0 18px 10px 14px;
  overflow:auto;
  flex:1 1 auto;
  min-height:0;
  transition:opacity .15s ease;
}
.imaptic-list-panel.is-collapsed .imaptic-list-body{opacity:0;visibility:hidden}

/* .imaptic-list-search-wrap (not the <input> itself) is what's sticky: a
   thin sticky input on its own left a 1px seam at scroll boundaries where
   whatever row was scrolling past it could still bleed through for a
   frame ("el que hi ha sota el buscador no s'ha de veure") — wrapping it in
   a block with its own solid, definitely-opaque background and the actual
   vertical gaps (padding, not the input's own margin, and not
   .imaptic-list-body's — see above) gives sticky a noticeably taller,
   gap-free footprint to mask anything scrolling underneath, instead of
   relying on the bare input's own thin box. Without it, the search box
   scrolled away with the items as soon as the list was long enough to
   scroll — it would pass *underneath* the fixed heading overlay above
   (visibly getting cut off/covered mid-scroll) before disappearing
   entirely, "sempre al seu lloc" (always in its place) was the actual ask. */
.imaptic-list-search-wrap{
  position:sticky;
  top:0;
  z-index:1;
  background:var(--imaptic-list-bg);
  padding:10px 0 8px;
}
.imaptic-list-panel.is-collapsed .imaptic-list-search-wrap{opacity:0;visibility:hidden}
/* background/color driven by their OWN vars (--imaptic-list-search-bg/
   -text), independent from --imaptic-list-bg/-text — a first attempt tied
   the INPUT's own background to the list's theme, which on a dark-themed
   list (black bg) turned the field's border and placeholder text invisible
   ("es veu malament"); defaulting these to plain white + dark text (same
   as a browser's own default input background) keeps that same safe
   fallback while still letting an admin who KNOWS their list stays light
   pick something else ("el cercador... no podem canviar res"). */
.imaptic-list-search{
  background:var(--imaptic-list-search-bg, #fff);
  color:var(--imaptic-list-search-text, #1d2327);
  width:100%;box-sizing:border-box;padding:8px 10px;
  border:1px solid rgba(0,0,0,.12);border-radius:6px;font-size:13px;
}
/* padding-top: replaces .imaptic-list-body's own (removed, see above) as
   the breathing room above the first row when there's no search box to
   provide it (list.searchable off) — harmless when there IS one too,
   since it then just sits right after .imaptic-list-search-wrap's own
   padding-bottom, both purely blank space either way. */
.imaptic-list{list-style:none;margin:0;padding:10px 0 0}
/* display:flex so a row with a link (.imaptic-list-row-link) sits beside
   its own select button instead of stacking — added specifically so
   clicking the row only ever selects it, never also navigates the CURRENT
   tab away ("si no salta al seleccionar i perdem el mapa"); opening the
   link is now the link's own job, a real <a target="_blank">, not
   something the row's click handler does in JS. */
.imaptic-list li{border-bottom:1px solid rgba(0,0,0,.05);display:flex;align-items:stretch}
.imaptic-list li[hidden]{display:none}
.imaptic-list button{
  display:block;width:100%;text-align:left;background:none !important;border:0 !important;padding:9px 4px;
  font-size:13px;cursor:pointer;color:inherit !important;
}
.imaptic-list-row-select{flex:1 1 auto;min-width:0}
.imaptic-list-row-link{
  flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;
  width:26px;
  text-decoration:none;
  color:inherit;
  opacity:.6;
  font-size:13px;
}
.imaptic-list-row-link:hover,
.imaptic-list-row-link:focus-visible{
  opacity:1;
  color:var(--imaptic-list-accent, var(--imaptic-point));
}
.imaptic-list button:hover,
.imaptic-list button:focus,
.imaptic-list button:active{
  background:none !important;color:inherit !important;
}
/* Opt-in row highlight (list.hover_enabled) — the admin's own colour, not
   whatever accent colour the theme's button reset happens to use. */
.imaptic-list.imaptic-list-hover-enabled li button:hover,
.imaptic-list.imaptic-list-hover-enabled li button:focus-visible{
  background:var(--imaptic-list-hover) !important;
}
.imaptic-list li.is-active button{color:var(--imaptic-list-accent, var(--imaptic-point)) !important;font-weight:600}

/* Inserted at the top of the list when a map point is selected (assets/js/
   frontend-map.js's filterListByPoint()) — the way back to the unfiltered
   list, not a real catalog row (never has data-row-id/data-point-ids, so
   it's untouched by search/point filtering, click-to-select, etc.). Bold +
   accent colour so it reads as an action, not just another entry. */
.imaptic-list-clear-filter button{color:var(--imaptic-list-accent, var(--imaptic-point)) !important;font-weight:700}

/* The list always stays on its chosen side (left/right), never stacks below
   the map, regardless of viewport or max-width — the admin's explicit call. */
