/* ── Library panel (direct child of #main, uses row layout like original) ── */
#library-panel { display: none; flex: 1; min-height: 0; overflow: hidden; flex-direction: row !important; }
#library-panel.visible { display: flex; }
#lib-sidebar { width: 220px; flex-shrink: 0; background: var(--bg1); border-right: 1px solid var(--bdr); padding: 14px 12px; display: flex; flex-direction: column; gap: 10px; overflow-y: auto; }
#lib-content { flex: 1; padding: 14px; display: flex; flex-direction: column; gap: 10px; overflow: hidden; }

/* Clear-filters button — sits at the top of the library / calendar-drawer
   sidebars. Outlined style so it reads as a command, not a filter chip. */
.clear-filters-btn {
  background: transparent;
  border: 1px solid var(--bdr);
  color: var(--dim);
  border-radius: 4px;
  padding: 6px 10px;
  font-size: var(--fs-xs);
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
  transition: all .15s;
  text-align: left;
}
.clear-filters-btn:hover { border-color: var(--amber-ink); color: var(--amber-ink); }
.clear-filters-btn:disabled { opacity: 0.4; cursor: default; }
.clear-filters-btn:disabled:hover { border-color: var(--bdr); color: var(--dim); }

/* Build-a-workout modal styles moved to features/generator/generator.css. */

/* Filter-group labels carry the matching rule, because it isn't the same for
   every dimension: Zone/Duration/Intensity/Load are ANY (a workout has one
   zone, so picking two means either), while Type is ALL (a workout has many
   tags, so picking two narrows). Stating it beats leaving riders to infer it
   from result counts. Used by the library sidebar and the calendar drawer. */
.sidebar-label-row { display: flex; align-items: baseline; gap: 6px; }
.sidebar-hint {
  font-size: var(--fs-micro); letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--dim2); border: 1px solid var(--bdr); border-radius: 3px;
  padding: 0 4px; line-height: 14px; flex-shrink: 0;
}

/* Filter chips */
.chip-group { display: flex; flex-wrap: wrap; gap: 4px; }
.chip { background: var(--bg3); border: 1px solid var(--bdr); color: var(--dim); border-radius: 4px; padding: 4px 9px; font-size: var(--fs-micro); cursor: pointer; letter-spacing: 1px; text-transform: uppercase; transition: all .15s; }
.chip:hover { filter: brightness(1.2); }
.chip.active { color: var(--bg0); font-weight: 600; }
.chip.unavailable { display: none; }
.chip[data-src].active       { background: var(--amber); border-color: var(--amber); color: var(--on-amber); font-weight: 700; }
/* Zone chips take the ZONE SCALE, not theme colours. They used to wear
   --blue/--sky/--green/--orange/--red/--purple, which meant the same zone was
   one colour here and another in the calendar, the zone badges and the phone —
   all of which read core/zones.js. It only showed in light mode, where the
   theme values drop to ink grade: Z5 · VO₂ Max went gold -> brown. (TKB-247) */
/* ...and their label stays DARK in both themes, because these fills do.
   --bg0 would be cream on paper: 2.37:1 on Z5, 1.82:1 on Z4. */
.chip[data-zone].active      { color: var(--on-amber); }
.chip[data-zone="Z1"].active { background: var(--z1);   border-color: var(--z1); }
.chip[data-zone="Z2"].active { background: var(--z2);   border-color: var(--z2); }
.chip[data-zone="Z3"].active { background: var(--z3);   border-color: var(--z3); }
.chip[data-zone="SS"].active { background: var(--z-ss); border-color: var(--z-ss); }
.chip[data-zone="Z4"].active { background: var(--z4);   border-color: var(--z4); }
.chip[data-zone="Z5"].active { background: var(--z5);   border-color: var(--z5); }
.chip[data-zone="Z6"].active { background: var(--z6);   border-color: var(--z6); }
.chip[data-zone="Z7"].active { background: var(--z7);   border-color: var(--z7); }
.chip[data-zone="MX"].active { background: var(--z-mx); border-color: var(--z-mx); }
.chip[data-dur].active       { background: var(--green); border-color: var(--green); }
.chip[data-reps].active      { background: var(--blue); border-color: var(--blue); }
.chip[data-if].active        { background: var(--green); border-color: var(--green); }
.chip[data-tss].active       { background: var(--orange); border-color: var(--orange); }
.chip[data-tag].active       { background: var(--purple); border-color: var(--purple); }
.chip[data-sets].active      { background: var(--orange); border-color: var(--orange); }

/* ── Favourite star ────────────────────────────────────────────────────────
   The star is an SVG (STAR_SVG in wolib-ui.js, and inline in index.php for the
   detail button), NOT the ★ character. A glyph sits where its font puts it:
   U+2605 draws well above its line box's centre, by an amount that varies with
   the font, the line-height and any fallback the browser substitutes — three
   hand-calibrated nudges here all failed for exactly that reason.

   The SVG's viewBox is centred on the star's AREA CENTROID, so centring the
   element optically centres the star. Nothing to calibrate, and it survives a
   font change.

   Centroid, not bounding box, is the load-bearing part: a 5-pointed star holds
   more mass below its bbox centre than above (top point 0.5R, bottom legs
   0.405R), so a bbox-centred star reads low by 5.28% of its height — 1px here,
   and the eye catches it. The centroid works out to exactly the circumcircle
   centre (y=50), which is why the box is 0..100 rather than 0..90.45; the star
   renders the same size, sitting 1px higher in a box 1px taller. */
.star-ico { display: block; width: 20px; height: 21.03px; }   /* 21.03 = 20 × 100/95.1 */

/* Star + zone badge are wrapped in .wo-card-actions and centred against each
   OTHER, rather than both aligning to the top of a title that may be one or two
   lines. Their box centres coincide — and since the star's box is centred on
   its centroid and the pill is a filled rect, so do the two optical centres. */
.wo-card-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.fav-btn { background: none; border: none; cursor: pointer; line-height: 0; padding: 4px; color: var(--dim3); transition: color .15s, transform .15s; flex-shrink: 0; display: flex; align-items: center; }
/* Gold, not ink — same call as .rm-star in route-manager.css. --amber-ink is
   the WRITING value and drops to #935f06 on paper; a filled star is a fill,
   so it takes --amber and stays #f59e0b on both grounds. */
.fav-btn:hover { color: var(--amber); transform: scale(1.15); }
.fav-btn.active { color: var(--amber); }
.detail-fav-btn { background: none; border: 1px solid var(--bdr); border-radius: 4px; cursor: pointer; font-size: var(--fs-base); padding: 4px 10px; color: var(--dim3); transition: all .15s; display: flex; align-items: center; gap: 5px; letter-spacing: 1px; }
.detail-fav-btn:hover { border-color: var(--amber); color: var(--amber); }
.detail-fav-btn.active { border-color: var(--amber); color: var(--amber); }
.detail-fav-btn span { font-size: var(--fs-micro); text-transform: uppercase; }
/* Favourite / Schedule / Share are one row of equal-height buttons. stretch,
   not a fixed height: the row's height comes from the colour emoji's line box,
   which is a platform detail (~33px on macOS, different elsewhere), so pinning
   a number would leave the three unequal on some machine. */
.detail-actions { display: flex; align-items: stretch; gap: 8px; flex-shrink: 0; }

/* The detail panel's Favourite star — same SVG, sized so its ink matches the
   emoji beside it rather than the --fs-micro label. The button centres its own flex
   items, so there is nothing else to correct. */
.detail-fav-btn .star-ico { width: 18px; height: 18.93px; }   /* 18 × 100/95.1 → 17.1px of ink */

/* Workout card */
.wo-card-summary { font-size: var(--fs-sm); font-weight: 600; color: var(--txt); letter-spacing: 0.3px; font-family: var(--font-data); font-variant-numeric: tabular-nums; }

/* Search */
#lib-search-wrap { flex: 1; position: relative; min-width: 120px; }
#lib-search-input { width: 100%; background: var(--bg2); border: 1px solid var(--bdr); border-radius: 4px; padding: 5px 28px 5px 28px; font-size: var(--fs-xs); font-family: inherit; color: var(--txt); outline: none; transition: border-color .2s; box-sizing: border-box; }
#lib-search-input:focus { border-color: var(--amber-ink); }
#lib-search-input::placeholder { color: var(--dim2); }
.search-icon { position: absolute; left: 9px; top: 50%; transform: translateY(-50%); color: var(--dim2); font-size: var(--fs-sm); pointer-events: none; }
#lib-search-clear { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); background: none; border: none; color: var(--dim); cursor: pointer; font-size: var(--fs-base); padding: 1px 4px; display: none; transition: color .15s; }
#lib-search-clear:hover { color: var(--txt); }
#lib-search-clear.visible { display: block; }

/* Tag typeahead — floats under the search box on both the library page and the
   calendar drawer (same markup, rendered by library-filters.js). Kept visually
   distinct from the results, and labelled: a tag filter and a text search
   answer different questions, and swapping one for the other silently is how a
   rider stops trusting either. */
.tag-suggest {
  position: absolute; top: 100%; left: 0; z-index: 20;
  min-width: 100%; width: max-content; max-width: 340px;
  margin-top: 4px; padding: 6px 7px;
  background: var(--bg2); border: 1px solid var(--bdr2); border-radius: 4px;
  box-shadow: 0 6px 18px rgba(0,0,0,.45);
  display: flex; flex-wrap: wrap; gap: 4px; align-items: center;
}
.tag-suggest[hidden] { display: none; }
.tag-sugg-lbl { font-size: var(--fs-micro); letter-spacing: 2px; color: var(--dim2); text-transform: uppercase; margin-right: 2px; }
.tag-sugg {
  background: var(--bg3); border: 1px solid var(--bdr); color: var(--txt);
  border-radius: 3px; padding: 3px 7px; font-size: var(--fs-xs); font-family: inherit;
  letter-spacing: .5px; cursor: pointer; transition: all .15s;
  display: inline-flex; align-items: center; gap: 5px;
}
.tag-sugg:hover { border-color: var(--purple); color: color-mix(in srgb, var(--purple) 80%, var(--txt));
  background: color-mix(in srgb, var(--purple) 20%, transparent); }
.tag-sugg-n { font-size: var(--fs-xs); color: var(--dim2); font-family: var(--font-data); font-variant-numeric: tabular-nums; }

/* Tile-size slider (sort bar) */
#lib-tile-size { display: flex; align-items: center; gap: 6px; padding: 0 4px; border-left: 1px solid var(--bdr); margin-left: 2px; }
#lib-tile-size .tile-size-icon-sm,
#lib-tile-size .tile-size-icon-lg { color: var(--dim2); font-size: var(--fs-sm); line-height: 1; }
#lib-tile-size .tile-size-icon-lg { font-size: var(--fs-md); }
#lib-tile-size-input { -webkit-appearance: none; appearance: none; width: 80px; height: 4px; background: var(--bg3); border-radius: 2px; outline: none; cursor: pointer; }
#lib-tile-size-input::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 12px; height: 12px; background: var(--amber); border-radius: 50%; cursor: pointer; }
#lib-tile-size-input::-moz-range-thumb { width: 12px; height: 12px; background: var(--amber); border-radius: 50%; cursor: pointer; border: none; }

/* Workout area — grid fills the row; the detail panel slides in as a
   push drawer (allocated column grows from 0 → drawer width with a transition).
   Because the first column is auto-sized and the grid stays a 2-column grid,
   the tile grid naturally re-flows into the remaining space. */
#wo-area { flex: 1; display: grid; grid-template-columns: 1fr 0fr; overflow: hidden; gap: 0; min-height: 0; transition: gap .25s ease; }
#wo-area.detail-open { grid-template-columns: 1fr minmax(420px, 34vw); gap: 12px; }

/* Workout grid — tile size is driven by the --tile-min CSS var set by the
   slider in wolib-ui.js (applyTileSize). Defaults to 240px. */
#wo-grid { --tile-min: 240px; overflow-y: auto; display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--tile-min), 1fr)); gap: 10px; align-content: start; padding: 2px 4px 0 0; min-width: 0; }
.wo-card { background: var(--bg2); border: 1px solid var(--bdr); border-radius: 8px; padding: 14px 15px; cursor: pointer; transition: all .15s; display: flex; flex-direction: column; gap: 8px; }
.wo-card:hover { border-color: var(--bdr2); transform: translateY(-1px); }
.wo-card.selected { border-color: var(--amber-ink); background: linear-gradient(135deg, #3b1f0022, var(--bg2)); }
.wo-card-top { display: flex; align-items: flex-start; gap: 8px; justify-content: space-between; }
.wo-card-name { font-size: var(--fs-base); font-weight: 600; color: var(--txt); line-height: 1.3; flex: 1; }
.zone-badge { flex-shrink: 0; font-size: var(--fs-micro); font-weight: 700; letter-spacing: 1.5px; padding: 3px 7px; border-radius: 3px; text-transform: uppercase; }
/* Sweet Spot is an OVERLAPPING band, not a zone (TKF-204), so it renders as a
   second chip joined to the zone rather than replacing it — "TEMPO · SWEET
   SPOT". Squared off on the joining edge so the pair reads as one label. */
.zone-badge:has(+ .zone-badge-band) { border-top-right-radius: 0; border-bottom-right-radius: 0; }
/* The POWER badge — where the watts sit, as opposed to what the session is for.
   Outlined rather than filled so it reads as a different KIND of fact from the
   aim badge beside it, and never competes with it for the eye (TKB-211). */
.wo-power-badge { flex-shrink: 0; font-size: var(--fs-micro); font-weight: 700; letter-spacing: 1.5px; padding: 2px 7px; border-radius: 3px; text-transform: uppercase; margin-left: 6px; color: var(--dim); border: 1px solid var(--bdr2); background: transparent; }
.zone-badge-band { flex-shrink: 0; font-size: var(--fs-micro); font-weight: 700; letter-spacing: 1.5px; padding: 3px 7px; border-radius: 0 3px 3px 0; text-transform: uppercase; margin-left: 1px; }
.wo-card-desc { font-size: var(--fs-xs); color: var(--dim); line-height: 1.5; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; }
.wo-card-stats { display: flex; gap: 12px; flex-wrap: wrap; }
.wo-stat-lbl { font-size: var(--fs-micro); letter-spacing: 2px; color: var(--dim); text-transform: uppercase; }
.wo-stat-val { font-size: var(--fs-base); font-weight: 700; color: var(--dim); margin-top: 1px; }
.wo-stat-val.amber { color: var(--amber-ink); }
.wo-stat-val.blue  { color: var(--blue); }
.wo-stat-val.green { color: var(--green); }
.wo-stat-val.kj    { color: var(--pink); }
.wo-card-tags { display: flex; gap: 4px; flex-wrap: wrap; }
/* Tags on a card are buttons that toggle the matching Type filter — the button
   reset keeps them looking exactly like the labels they replaced. */
.wo-tag { font-size: var(--fs-xs); font-family: inherit; color: var(--dim); background: var(--bg3); border: 1px solid var(--bdr); border-radius: 3px; padding: 2px 6px; letter-spacing: .5px; cursor: pointer; transition: filter .15s, border-color .15s; }
.wo-tag:hover { filter: brightness(1.35); border-color: var(--bdr2); }

/* Tile thumbnail — compact power profile preview */
.wo-card-thumb { display: block; width: 100%; height: 56px; background: var(--bg0); border: 1px solid var(--bdr); border-radius: 4px; overflow: hidden; }
.wo-card-thumb.empty { background: repeating-linear-gradient(45deg, var(--bg0), var(--bg0) 6px, var(--bg1) 6px, var(--bg1) 12px); }
.wo-card.selected .wo-card-thumb { border-color: var(--amber-ink); }

/* Grid placeholder — no-match, loading, and load-failure all render here.
   grid-column spans every track: #wo-empty is a child of the auto-fill grid,
   so without it the centred placeholder is centred inside a single ~240px
   column at the top-left rather than across the panel. */
#wo-empty { display: none; grid-column: 1 / -1; flex-direction: column; align-items: center; justify-content: center; height: 100%; gap: 10px; color: var(--dim2); }
#wo-empty.visible { display: flex; }
#wo-empty-icon { font-size: var(--fs-mega); opacity: .3; }
#wo-empty-msg  { font-size: var(--fs-sm); letter-spacing: 2px; text-transform: uppercase; text-align: center; }

/* Detail panel — push drawer. The column is sized by #wo-area's
   grid-template-columns, so the panel just needs to fill it. When closed,
   the column is 0fr and overflow hides the content during the transition. */
#detail-panel { background: var(--bg1); border: 1px solid var(--bdr); border-radius: 8px; display: flex; flex-direction: column; overflow: hidden; min-height: 0; min-width: 0; opacity: 0; visibility: hidden; transition: opacity .2s ease .05s, visibility 0s linear .25s; }
#detail-panel.visible { opacity: 1; visibility: visible; transition: opacity .2s ease .05s, visibility 0s linear 0s; }
#detail-header { padding: 14px 16px 12px; border-bottom: 1px solid var(--bdr); flex-shrink: 0; }
#detail-title  { font-size: var(--fs-md); font-weight: 700; color: var(--txt); margin-bottom: 6px; line-height: 1.3; }
#detail-badges { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.sys-badge { font-size: var(--fs-micro); letter-spacing: 1px; padding: 3px 8px; border-radius: 3px; text-transform: uppercase; background: var(--bg3); border: 1px solid var(--bdr2); color: var(--dim2); }
#detail-close { background: none; border: none; color: var(--dim2); cursor: pointer; font-size: var(--fs-lg); padding: 2px 6px; transition: color .15s; flex-shrink: 0; margin-left: auto; }
#detail-close:hover { color: var(--txt); }
#detail-scroll { flex: 1; overflow-y: auto; padding: 14px 16px; display: flex; flex-direction: column; gap: 16px; }
#detail-desc   { font-size: var(--fs-sm); color: var(--dim); line-height: 1.7; margin: 0; }

/* Coaching block — purpose / how-to-ride / phase. */
/* [hidden] must win over the display:flex below, or an empty block shows as a
   bare box (flex overrides the attribute's low-priority display:none). */
.wo-coaching[hidden] { display: none !important; }
.wo-coaching {
  display: flex; flex-direction: column; gap: 10px;
  padding: 12px 14px;
  background: var(--bg2, var(--bg1));
  border: 1px solid var(--bdr, var(--bg3));
  border-radius: 8px;
}
.wo-phase-chip {
  align-self: flex-start;
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
  padding: 2px 9px; border-radius: 4px;
  background: color-mix(in srgb, var(--blue) 14%, transparent); color: var(--blue); border: 1px solid color-mix(in srgb, var(--blue) 30%, transparent);
}
.wo-coach-row { display: flex; flex-direction: column; gap: 2px; }
.wo-coach-lbl {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
  color: var(--dim2, var(--dim2));
}
.wo-coach-row span:last-child { font-size: var(--fs-sm); color: var(--txt, var(--txt)); line-height: 1.6; }

/* Detail stats row */
#detail-stats { display: flex; gap: 16px; flex-wrap: wrap; }
.dstat-lbl { font-size: var(--fs-micro); letter-spacing: 2px; color: var(--dim); text-transform: uppercase; }
.dstat-val { font-size: var(--fs-xl); font-weight: 800; color: var(--amber-ink); line-height: 1; margin-top: 2px; }
.dstat-unit{ font-size: var(--fs-sm); color: var(--dim); margin-left: 2px; }

/* Power profile chart */
.section-lbl { font-size: var(--fs-micro); letter-spacing: 2.5px; color: var(--dim); text-transform: uppercase; margin-bottom: 6px; }
#profile-wrap { position: relative; background: var(--bg2); border: 1px solid var(--bdr); border-radius: 6px; padding: 12px 12px 8px; user-select: none; }
#profile-svg  { display: block; width: 100%; height: 260px; overflow: visible; cursor: crosshair; }
/* Hover readout. HTML, not SVG <text>: #profile-svg draws with
   preserveAspectRatio="none", which stretches any text inside it. */
#profile-tip { position: absolute; z-index: 2; pointer-events: none; border-radius: 4px; padding: 5px 8px; font-family: var(--font-data); color: var(--bg0); line-height: 1.4; white-space: nowrap; box-shadow: 0 2px 8px rgba(0,0,0,.4); }
#profile-tip[hidden] { display: none; }
.ptip-pwr  { font-size: var(--fs-base); font-weight: 700; }
.ptip-pwr .ptip-pct { font-size: var(--fs-xs); font-weight: 600; opacity: .72; }
.ptip-zone { font-size: var(--fs-xs); font-weight: 600; opacity: .85; }
.ptip-meta { font-size: var(--fs-xs); opacity: .68; }
#profile-legend { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.legend-item { display: flex; align-items: center; gap: 4px; font-size: var(--fs-micro); color: var(--dim); letter-spacing: 1px; text-transform: uppercase; }
.legend-dot { width: 8px; height: 8px; border-radius: 2px; flex-shrink: 0; }

/* Time in zone (TKF-205). Rows on a shared seconds axis, scaled to the largest
   zone so a two-zone workout still reads as a shape rather than two slivers.
   The band row sits under a rule because it measures the SAME seconds again —
   see the note on #ztime-section in index.php. */
#ztime-section { margin-top: 18px; }
#ztime-rows { background: var(--bg2); border: 1px solid var(--bdr); border-radius: 6px; padding: 10px 12px; display: flex; flex-direction: column; gap: 5px; }
.ztime-row { display: grid; grid-template-columns: 26px 1fr 52px 34px; align-items: center; gap: 8px; }
.ztime-lbl { font-family: var(--font-data); font-size: var(--fs-xs); font-weight: 700; letter-spacing: .5px; }
.ztime-track { background: var(--bg0); border-radius: 3px; height: 12px; overflow: hidden; }
.ztime-fill { display: block; height: 100%; border-radius: 3px; min-width: 2px; }
.ztime-val { font-family: var(--font-data); font-size: var(--fs-xs); color: var(--txt); text-align: right; }
.ztime-pct { font-family: var(--font-data); font-size: var(--fs-xs); color: var(--dim); text-align: right; }
/* The band row. Outlined rather than filled, so it never reads as one more
   slice of the total stacked beneath the others. */
.ztime-band { margin-top: 5px; padding-top: 8px; border-top: 1px solid var(--bdr); }
.ztime-band .ztime-fill { border: 1px solid currentColor; }
.ztime-note { font-size: var(--fs-micro); letter-spacing: 1px; color: var(--dim); text-transform: uppercase; margin-top: 6px; }

/* Segment breakdown */
/* Sits on a zone fill, which is the same in both themes — so is its ink.
   --bg0 is cream on paper and dropped this to 2.4:1. (TKB-247) */
.seg-power-pill { display: inline-block; font-size: var(--fs-xs); font-weight: 600; padding: 1px 6px; border-radius: 3px; color: var(--on-amber); }

/* Export section */
#lib-export-section { background: var(--bg2); border: 1px solid color-mix(in srgb, var(--green) 30%, transparent); border-radius: 6px; padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.export-row { display: flex; gap: 8px; align-items: center; }
.export-label { font-size: var(--fs-micro); letter-spacing: 1.5px; color: var(--dim); text-transform: uppercase; min-width: 50px; }
.export-input { background: var(--bg0); border: 1px solid var(--bdr2); border-radius: 4px; padding: 6px 10px; font-size: var(--fs-md); font-weight: 700; font-family: inherit; width: 90px; outline: none; color: var(--green); text-align: center; }
.export-input:focus { border-color: var(--green); }
.export-unit { font-size: var(--fs-sm); color: var(--dim); }
.export-btns { display: flex; gap: 8px; flex-wrap: wrap; }
#lib-zwo-btn { background: color-mix(in srgb, var(--green) 15%, transparent); color: var(--green); border: 1px solid var(--green); border-radius: 6px; padding: 10px 18px; font-size: var(--fs-sm); font-weight: 700; cursor: pointer; letter-spacing: 1px; transition: all .15s; }
#lib-zwo-btn:hover { filter: brightness(1.2); }
#lib-load-erg-btn { flex: 1; background: var(--amber); color: var(--on-amber); border: none; border-radius: 6px; padding: 10px 18px; font-size: var(--fs-base); font-weight: 700; cursor: pointer; letter-spacing: 1px; transition: background 120ms; }
#lib-load-erg-btn:hover { background: var(--amber-ink); }
/* Load in Climbs (TKF-378): outlined twin of Load in Player; index.php emits
   it only where the climbs feature is allowed. */
#lib-load-climbs-btn { flex: 1; background: transparent; color: var(--amber-ink); border: 1px solid var(--amber-ink); border-radius: 6px; padding: 10px 18px; font-size: var(--fs-base); font-weight: 700; cursor: pointer; letter-spacing: 1px; transition: background .12s; }
#lib-load-climbs-btn:hover { background: color-mix(in srgb, var(--amber) 12%, transparent); }
/* #lib-edit-btn / #lib-push-garmin-btn styles removed with their buttons —
   editor is out of the launch package, Connect IQ pulls workouts to the
   device. See index.php #lib-export-section. */
#lib-delete-btn { background: color-mix(in srgb, var(--red) 14%, transparent); color: var(--red); border: 1px solid color-mix(in srgb, var(--red) 20%, transparent); border-radius: 6px; padding: 10px 18px; font-size: var(--fs-sm); font-weight: 700; cursor: pointer; letter-spacing: 1px; transition: all .15s; }
#lib-delete-btn:hover { border-color: var(--red); color: var(--red); filter: brightness(1.2); }

/* Sort bar */
#lib-sort-bar { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
/* Source pills sit before the sorters and are ruled off from them: they answer
   "which catalogue", not "in what order". Favs and Custom used to sit in the
   sort row looking like sort keys, which they never were. */
.lib-src-pills { display: flex; gap: 6px; padding-right: 8px; margin-right: 2px; border-right: 1px solid var(--bdr); }
#lib-sort-bar .sort-lbl { font-size: var(--fs-micro); letter-spacing: 2px; color: var(--dim); text-transform: uppercase; white-space: nowrap; margin-right: 2px; }
.sort-btn  { background: var(--bg3); border: 1px solid var(--bdr); color: var(--dim); border-radius: 4px; padding: 4px 10px; font-size: var(--fs-micro); cursor: pointer; letter-spacing: 1px; text-transform: uppercase; transition: all .15s; display: flex; align-items: center; gap: 4px; }
.sort-btn:hover { filter: brightness(1.2); }
.sort-btn.active { background: var(--amber); border-color: var(--amber); color: var(--on-amber); font-weight: 700; }
#lib-sort-bar .mode-btn  { flex: 0; background: var(--bg3); border: 1px solid var(--bdr); color: var(--dim); border-radius: 4px; padding: 4px 10px; font-size: var(--fs-micro); cursor: pointer; letter-spacing: 1px; text-transform: uppercase; transition: all .15s; white-space: nowrap; }
.mode-btn:hover { filter: brightness(1.2); }
#lib-sort-bar .mode-btn.active { background: var(--amber); border-color: var(--amber); color: var(--on-amber); font-weight: 700; }
.sort-arrow { font-size: var(--fs-xs); opacity: .8; }

/* Pagination */
#lib-pagination { flex-shrink: 0; display: flex; gap: 5px; align-items: center; justify-content: center; padding: 4px 0; }
.pg-btn { background: var(--bg2); border: 1px solid var(--bdr); border-radius: 4px; padding: 5px 10px; font-size: var(--fs-xs); color: var(--dim); cursor: pointer; letter-spacing: .5px; transition: all .15s; }
.pg-btn:hover:not(:disabled) { border-color: var(--bdr2); color: var(--txt); }
.pg-btn:disabled { opacity: .35; cursor: default; }
.pg-btn.active { background: var(--amber); border-color: var(--amber); color: var(--on-amber); font-weight: 700; }
.pg-sep { color: var(--dim); font-size: var(--fs-xs); padding: 0 2px; }
.pg-info { font-size: var(--fs-sm); letter-spacing: 1px; color: var(--dim); padding: 0 6px; }


/* Free-tier library upsell, shown in the status line when the catalogue is
   gated (Tier-Sweep §5e). Deliberately understated — it sits in a status
   strip, not a modal, and interrupting a browse to sell is what makes an
   upsell feel like an ad. Target is /pricing, which is still a 404 until
   TKF-023 lands; the Durability CTA already points at the same place, so
   both start working from one change. */
.lib-upsell { color: var(--sky); text-decoration: underline; text-underline-offset: 2px; }
.lib-upsell:hover { color: #0284c7; }

/* Admin "Free-tier view" toggle (wolib-ui.js injects it — no markup in
   index.php, no i18n keys, because it is a tool and never shown to a rider).
   Deliberately looks like the clear-filters button it sits beside rather than
   a filter chip: it is a lens over the whole catalogue, not one more facet. */
#lib-free-preview.active { background: var(--sky); border-color: var(--sky); color: #fff; }
