/*
 * OUTSKIRT — player profile v2 "One ranked scroll" (theme assets/player-v2.css)
 * Renderer: includes/coc-player-v2.php · script: scripts/player-v2.js
 *
 * Loaded AFTER assets/clan-v3.css, which supplies the tokens (--oc3-*), resets, cards,
 * tabs, meters, tiles, readout + chart, source pill, state chip and tooltip. This file adds
 * the player-only parts (op2-*). Colours come only from tokens: the clan page's --oc3-*
 * set and the page's own --op2-* set (WP: Player page v2 — Colours, col_p2_* keys; the
 * renderer emits the overrides in one inline <style>). Light + dark read the same rules.
 * Phone first (402 design width, checked at 360); ≥480 tab labels come back; ≥768 the jump
 * strip gets labels; ≥1024 the stat slots run beside the name and the page is a two-column grid
 * (half-width boards pair up). fix3: .op2-ph = phones & tablets only (<1024), .op2-dt = desktop only.
 * Motion (2026-09-26 animate pass, the block at the end): Félix lifted the Data-Moves rule for this page — the first card
 * deals in, boards rise into view, figures count, tabs slide; every family is a Player Page → Motion switch, and all of it
 * stops under reduced motion and on paper. Nothing is hidden without the arming class (JS off = the whole page).
 */

/* the page is a flex column (not the clan page's grid) so the jump bar can stick for the whole scroll */
#oc3.op2 {
  --op2-page: #f5fafd;
  --op2-jump-on: var(--oc3-ink);
  --op2-jump-on-ink: #ffffff;
  --op2-rank-1: var(--oc3-lead);
  --op2-rank-23: var(--oc3-podium);
  --op2-miss: var(--oc3-red);
  --op2-avg: var(--oc3-ink);
  --op2-chart: var(--oc3-chart);
  /* fix5 F1: every bar's fill and track (WP: Player page v2 — Colours → Bars); by default the clan page's sorted-column green */
  --op2-bar: var(--oc3-hero-bar-a);
  --op2-bar-b: var(--oc3-hero-bar-b);
  --op2-track: var(--oc3-well);
  --op2-stick: 55px;
  --op2-jpy: 6px;   /* the pinned jump strip's top / bottom padding (player-v2.js reads it to land a board under the strip) */
  display: flex; flex-direction: column; align-items: stretch; gap: 12px;
}
html[data-theme="dark"] #oc3.op2 {
  --op2-page: var(--osp-bg-0, #0d1117);
  --op2-jump-on-ink: var(--oc3-panel);
}
#oc3.op2 > * { min-width: 0; }
/* fix3: the devices of a block or board (p2_dev_* selects) — the markup keeps everything, one side hides it */
@media (min-width: 1024px) { #oc3.op2 .op2-ph { display: none !important; } }
@media (max-width: 1023.98px) { #oc3.op2 .op2-dt { display: none !important; } }
/* the theme sets every li / ol / ul to Clash !important: lists here start in the sans, components set Clash where they want it */
#oc3.op2 :is(ol, ul, li) { font-family: var(--oc3-sans) !important; }
/* zero-weight resets against the theme's table styles (every .op2-tbl rule below wins on class weight) */
:where(#oc3.op2 table) { border-collapse: collapse; width: 100%; margin: 0; }
:where(#oc3.op2 .op2-tbl) :where(th, td) { padding: 0; }
/* …except the theme's th / td paint (a light #f8f8f8 cell in dark mode): cancelled on those cells only, at id weight */
#oc3.op2 .op2-tbl :is(th, td) { border: 0; background: none; }
/* the site's WebP rewrite wraps a PNG in a <picture> that takes the img's class: that box takes the size, its image fills it */
#oc3.op2 picture { display: inline-block; flex: none; line-height: 0; vertical-align: middle; }
#oc3.op2 picture[class] > img { display: block; width: 100%; height: 100%; object-fit: contain; }

/* ── shared bits ── */
.op2-h { margin-bottom: 12px; }
.op2-h-i { width: 22px; height: 22px; object-fit: contain; flex: none; margin-right: -2px; }
.op2-h .oc3-h-t { margin-right: auto; }
.op2-h .oc3-state + .oc3-h-r, .op2-h .oc3-h-t + .oc3-state { margin-left: 0; }
.op2-week .op2-h .oc3-h-t { margin-right: 0; }
.op2-week .op2-h .oc3-state { margin-right: auto; }
.op2-h .oc3-h-r b { font-family: var(--oc3-data); font-weight: 700; color: var(--oc3-ink); font-size: calc(13.5px * var(--oc3-ts, 1)); }
#oc3.op2 .op2-h-fig.is-max, #oc3.op2 .is-max > b, #oc3.op2 b.is-max { color: var(--oc3-green); }
.op2-sh {
  display: flex; align-items: baseline; gap: 8px; margin: 0 0 8px; padding-bottom: 5px; border-bottom: 1px solid var(--oc3-line);
  font-family: var(--oc3-clash); font-weight: 700; font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--oc3-ink-2);
}
.op2-sh > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.op2-sh small { margin-left: auto; font-family: var(--oc3-sans); font-size: calc(12px * var(--oc3-ts, 1)); font-weight: 400; letter-spacing: normal; text-transform: none; color: var(--oc3-mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op2-sh--rule { margin-top: 16px; }
.op2-none, .op2-empty { font-size: calc(13.5px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); margin: 4px 0 2px; }
.op2-empty { padding: 4px 2px; }
.op2-miss { font-style: normal; font-weight: 600; color: var(--op2-miss); }
.op2-ok {
  display: inline-block; flex: none; width: 13px; height: 13px; margin-left: 4px; vertical-align: -1px; background: var(--oc3-green);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0Zm3.6 5.2a.9.9 0 0 0-1.3 0L7 8.6 5.7 7.3a.9.9 0 1 0-1.3 1.3l2 2a.9.9 0 0 0 1.3 0l4-4a.9.9 0 0 0 0-1.4Z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0Zm3.6 5.2a.9.9 0 0 0-1.3 0L7 8.6 5.7 7.3a.9.9 0 1 0-1.3 1.3l2 2a.9.9 0 0 0 1.3 0l4-4a.9.9 0 0 0 0-1.4Z'/%3E%3C/svg%3E") center / contain no-repeat;
}
/* medal discs (the roster's): gold / silver / bronze; a place without a medal is a plain Clash numeral */
.op2-md1 { --oc3-m: var(--oc3-medal-1); --oc3-mi: var(--oc3-medal-1-ink); }
.op2-md2 { --oc3-m: var(--oc3-medal-2); --oc3-mi: var(--oc3-medal-2-ink); }
.op2-md3 { --oc3-m: var(--oc3-medal-3); --oc3-mi: var(--oc3-medal-3-ink); }
.op2-md {
  display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  font-family: var(--oc3-clash); font-weight: 700; font-size: 11px; line-height: 1; color: var(--oc3-mi);
  background: linear-gradient(160deg, var(--oc3-shimmer), transparent 70%) var(--oc3-m);
  box-shadow: inset 0 -1.5px 0 rgba(16, 24, 40, .16), 0 1px 2px rgba(16, 24, 40, .16);
}
/* a medal place with its own icon (ic_p2_med_N): the icon in place of the disc */
.op2-md.has-mi { background: none; box-shadow: none; border-radius: 0; width: 24px; height: 24px; }
.op2-mi { display: block; width: 24px; height: 24px; object-fit: contain; }
.op2-md--xs { width: 17px; height: 17px; font-size: 9.5px; vertical-align: -4px; margin: 0 1px; }
.op2-md--xs.has-mi, .op2-md--xs .op2-mi { width: 17px; height: 17px; }
.op2-pl { font-family: var(--oc3-clash); font-weight: 700; font-size: 13px; color: var(--oc3-ink-3); font-variant-numeric: tabular-nums; text-align: center; }
.op2-pl small { font-size: 9.5px; margin-right: 1px; color: var(--oc3-mute); }
.op2-pl--s { width: 18px; height: 18px; font-size: 9.5px; vertical-align: -4px; }
.op2-pl.op2-md { color: var(--oc3-mi); }
.op2-pl--s.has-mi, .op2-pl--s .op2-mi { width: 18px; height: 18px; }
.op2-stars { display: inline-flex; gap: 0; }
.op2-st { width: 13px; height: 13px; object-fit: contain; }

/* tappable stats: the roster's affordance (a ring on the open one, one tooltip at a time) */
#oc3.op2 [data-tt-l] { cursor: pointer; -webkit-tap-highlight-color: transparent; }
#oc3.op2 [data-tt-l].is-tt { box-shadow: 0 0 0 1.5px var(--oc3-ink-3); border-radius: 3px; }

/* ════ 1 · the first card ════ */
.op2-score { overflow: hidden; }
.op2-id { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 0 12px; align-items: center; }
.op2-th { width: 64px; height: 64px; object-fit: contain; }
.op2-name { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.op2-role {
  display: inline-flex; align-items: center; gap: 4px; padding: 1px 7px 1px 5px; border-radius: 3px; background: var(--oc3-raised);
  font-family: var(--oc3-sans); font-size: calc(13px * var(--oc3-ts, 1)); font-weight: 400; letter-spacing: normal; line-height: 1.45; color: var(--oc3-ink-2);
}
.op2-role img, .op2-role picture { width: 16px; height: 16px; object-fit: contain; }
.op2-id .oc3-chips { margin-top: 6px; }
.op2-lbls { gap: 2px; padding-right: 6px; }
.op2-clan { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 7px; margin-top: 7px; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
.op2-clan-b { width: 20px; height: 20px; object-fit: contain; }
#oc3 .op2-clan-n { font-family: var(--oc3-clash); font-weight: 700; font-size: 13px; letter-spacing: .03em; color: var(--oc3-ink); }
#oc3 a.op2-name-a { color: var(--oc3-ink); }
#oc3 a.op2-name-a:hover { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 4px; }
#oc3 a.op2-clan-n:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ══ [merge life builder] the clan timeline (History's clans played in + clan moves, retired with its board): a button on the
   clan line folds open, under the identity, the clans played in (the current one first, each one's days to scale) and the
   moves of the last 60 days. The markup is open; the arming script marks .op2-id [data-ctl] ("" = JS runs, "o" = open on a
   wide screen before player-v2.js takes over) — only then is the panel folded and the button shown, so JS off, a blocked
   script (3 s failsafe) and print show it whole. States are attributes (data-open / data-all), never classes. ══ */
#oc3 .op2-ctl-b {
  position: relative; display: inline-flex; align-items: center; gap: 5px; margin: 0; padding: 2px 6px 2px 5px; border: 0; border-radius: 3px;
  background: var(--oc3-raised); font-family: var(--oc3-sans); font-size: calc(12.5px * var(--oc3-ts, 1)); font-weight: 400; line-height: 1.45;
  letter-spacing: normal; text-transform: none; color: var(--oc3-ink-2); cursor: pointer; -webkit-tap-highlight-color: transparent;
}
#oc3 .op2-ctl-b::before { content: ""; position: absolute; inset: -8px -3px; }   /* a finger-sized target on a 22px chip */
#oc3 .op2-ctl-b:hover { color: var(--oc3-ink); box-shadow: inset 0 0 0 1px var(--oc3-line); }
#oc3 .op2-ctl-b:focus-visible { outline: 2px solid var(--oc3-ink-3); outline-offset: 2px; }
#oc3 .op2-ctl-b[aria-expanded="true"] { color: var(--oc3-ink); box-shadow: inset 0 0 0 1px var(--oc3-line); }
.op2-ctl-bi { width: 16px; height: 16px; object-fit: contain; }
.op2-ctl-cv { flex: none; color: var(--oc3-ink-3); }
#oc3 .op2-ctl-b[aria-expanded="true"] .op2-ctl-cv { transform: rotate(180deg); }
#oc3 .op2-id:not([data-ctl]) .op2-ctl-b, #oc3 .op2-id:not([data-ctl]) .op2-ctl-more { display: none; }   /* (the #oc3 rule above draws it) */
/* the panel spans the identity box (TH + name) under it; contain: inline-size = it never widens the desktop name column */
.op2-ctl { grid-column: 1 / -1; display: grid; grid-template-rows: 1fr; min-width: 0; contain: inline-size; }
.op2-ctl-in { min-height: 0; overflow: hidden; }
.op2-ctl-body { padding: 14px 0 2px; }
.op2-id[data-ctl=""] > .op2-ctl[data-open="0"] { grid-template-rows: 0fr; visibility: hidden; }
.op2-ctl .op2-sh { margin-bottom: 4px; }
.op2-ctl-l { list-style: none; margin: 0; padding: 0; }
.op2-id[data-ctl] .op2-ctl-l:not([data-all]) > .is-x { display: none; }
/* a clan: badge · name (+ "now") · days, then its bar (days to scale: the longest stay = the full track), then its stays */
.op2-ctl-c { display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; column-gap: 8px; row-gap: 4px; align-items: center; padding: 6px 0; }
.op2-ctl-c + .op2-ctl-c { border-top: 1px solid var(--oc3-line); }
.op2-ctl-bd { grid-row: 1 / span 2; width: 20px; height: 20px; object-fit: contain; }
.op2-ctl-n { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.op2-ctl-n b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--oc3-clash); font-weight: 700; font-size: 12px; letter-spacing: .02em; color: var(--oc3-ink); }
.op2-ctl-n small { flex: none; font-size: calc(11px * var(--oc3-ts, 1)); color: var(--oc3-mute); white-space: nowrap; }
.op2-ctl-now { flex: none; align-self: center; padding: 0 5px; border-radius: 3px; background: color-mix(in srgb, var(--oc3-green) 15%, transparent);
  font-style: normal; font-family: var(--oc3-sans); font-size: calc(11px * var(--oc3-ts, 1)); font-weight: 600; line-height: 1.5; color: var(--oc3-green); }
.op2-ctl-d { white-space: nowrap; text-align: right; font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
.op2-ctl-d b { font-family: var(--oc3-clash); font-weight: 700; font-size: 13px; letter-spacing: .02em; color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-ctl-bar { grid-column: 2 / -1; display: block; height: 5px; border-radius: 999px; background: var(--op2-track); overflow: hidden; }
.op2-ctl-bar > i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--op2-bar), var(--op2-bar-b)); transform-origin: 0 50%; }
.op2-ctl-c:not(.is-cur) .op2-ctl-bar > i { opacity: .5; }   /* the same green, quieter for the clans left */
.op2-ctl-x { grid-column: 2 / -1; font-size: calc(11.5px * var(--oc3-ts, 1)); line-height: 1.3; color: var(--oc3-mute); }
/* a move: its arrow (in = joined a family clan · out = left one · two ways = between two other clans) · from → to · when */
.op2-ctl-m { display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; column-gap: 8px; align-items: center; padding: 6px 0; font-size: calc(12.5px * var(--oc3-ts, 1)); }
.op2-ctl-m + .op2-ctl-m { border-top: 1px solid var(--oc3-line); }
.op2-ctl-mi { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; color: var(--oc3-ink-3); }
.op2-ctl-mi img { width: 16px; height: 16px; object-fit: contain; }
.op2-ctl-m.is-in .op2-ctl-mi { color: var(--oc3-green); }
.op2-ctl-m.is-out .op2-ctl-mi { color: var(--op2-miss); }
.op2-ctl-mt { display: flex; align-items: center; gap: 5px; min-width: 0; color: var(--oc3-ink-2); }
.op2-ctl-mt > span, .op2-ctl-mt > b, .op2-ctl-mt > i { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.op2-ctl-mt > b { font-family: var(--oc3-clash); font-weight: 700; font-size: 12px; letter-spacing: .02em; color: var(--oc3-ink); }
.op2-ctl-mt i { color: var(--oc3-mute); }
/* checker (life): from → to wraps before it clips ("Elixr Enforcers → OUTSKIRT 2.0" on a 360 px phone); a single name
   longer than the line still ends in … */
.op2-ctl-mt { flex-wrap: wrap; row-gap: 1px; }
.op2-ctl-mt > span, .op2-ctl-mt > b, .op2-ctl-mt > i { max-width: 100%; }
.op2-ctl-sep { flex: none; color: var(--oc3-ink-3); }
.op2-ctl-w { white-space: nowrap; font-size: calc(11.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); font-variant-numeric: tabular-nums; }
.op2-ctl-more { padding-top: 4px; }
@media (min-width: 1024px) {
  .op2-ctl-body { padding-top: 16px; }
  /* open when the page loads (p2_ctl_open): the stat strip beside the name starts at the top of the identity box, not in the
     middle of name + timeline (opened by a tap, player-v2.js pins it where it was instead) */
  .op2-score:has(> .op2-id > .op2-ctl[data-open="1"]) > .op2-sls { align-self: start; }
}
/* motion (Motion → "Clan timeline", .op2-id[data-ctl-mo] — the renderer sets it only with the master on): the fold opens on the
   reveal time with the arrival curve and shuts faster (state time); the chevron turns with it. The rows, bars, days and arrows
   inside are player-v2.js's (with Rows / Bars / Count-up figures). Reduced motion: the global rule stills it. */
#oc3.op2 .op2-id[data-ctl][data-ctl-mo] > .op2-ctl { transition: grid-template-rows calc(260ms * var(--op2-mk, 1)) var(--op2-mo-out), visibility 0s linear calc(260ms * var(--op2-mk, 1)); }
#oc3.op2 .op2-id[data-ctl][data-ctl-mo] > .op2-ctl[data-open="1"] { transition: grid-template-rows calc(420ms * var(--op2-mk, 1)) var(--op2-mo-out), visibility 0s; }
#oc3.op2 .op2-id[data-ctl-mo] .op2-ctl-cv { transition: transform var(--op2-mo-st) var(--op2-mo-out); }
@media print {
  #oc3.op2 .op2-ctl { grid-template-rows: 1fr !important; visibility: visible !important; }
  #oc3.op2 .op2-ctl-l > .is-x { display: grid !important; }
  #oc3.op2 .op2-ctl-b, #oc3.op2 .op2-ctl-more { display: none !important; }
}
/* checker (life): the Days-in-the-clan slot opens the timeline too (player-v2.js adds .is-ctl + role=button) */
#oc3.op2 .op2-sl--tenure.is-ctl { cursor: pointer; }
/* ══ [/merge life builder] ══ */

/* stat slots (fix3): Félix's ordered stats under the identity. Phones: two by two on a full-bleed band, hairlines from the
   band's 1px gaps (so a slot hidden on this device leaves no hole); desktop: a strip beside the name (the ≥1024 block). */
.op2-sls {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; margin: 14px -14px 0;
  background: var(--oc3-line); border-top: 1px solid var(--oc3-line);
}
#oc3.op2 .op2-sl {
  display: grid; grid-template-columns: 30px minmax(0, 1fr); grid-template-rows: auto auto; column-gap: 9px; align-items: center; align-content: center;
  min-width: 0; padding: 10px 10px 11px 14px; background: var(--oc3-card);
}
#oc3.op2 .op2-sl.is-tt { box-shadow: inset 0 0 0 1.5px var(--oc3-ink-3); border-radius: 0; }
.op2-sl--wide { grid-column: 1 / -1; }
.op2-sl-i { grid-row: 1 / 3; display: grid; place-items: center; width: 30px; height: 30px; }
.op2-sl-i > img, .op2-sl-i > picture { width: 30px; height: 30px; object-fit: contain; }
.op2-sl-i > .oc3-emo { font-size: 24px; }
.op2-sl-v { display: flex; align-items: center; gap: 5px; min-width: 0; }
.op2-sl-v > b {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--oc3-clash); font-weight: 700; font-size: 15px; line-height: 1.2; letter-spacing: .02em; color: var(--oc3-ink); font-variant-numeric: tabular-nums;
}
.op2-sl-v > b small { font-size: 11px; color: var(--oc3-ink-3); margin-left: 1px; }
/* checker (life): a league name wider than its slot ("Valkyrie 15", "Legend II" in a ~80 px desktop column) wraps at its space
   instead of ending in "Valkyr…" */
#oc3.op2 .op2-sl--league .op2-sl-v > b, #oc3.op2 .op2-sl--best .op2-sl-v > b { white-space: normal; text-wrap: balance; }
.op2-sl-v .op2-ok { margin-left: 3px; vertical-align: -1px; }
#oc3.op2 .op2-sl.is-max .op2-sl-v > b { color: var(--oc3-green); }
.op2-sl-v .op2-pl--s { flex: none; }
.op2-sl-l {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 8px; min-width: 0;
  font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.3; color: var(--oc3-mute);
}
.op2-sl-l .op2-lg-s { font-size: inherit; gap: 3px; color: var(--oc3-ink-3); }
.op2-sl-l .op2-lg-s img, .op2-sl-l .op2-lg-s picture { width: 14px; height: 14px; }
/* icons builder: a piece wider than its slot ("514 week of Aug 17" in a 360–402 phone half, "1,105 last week" in a desktop
   slot) was clipped ("Aug 1") or ran into the next slot: its words now drop under the figure instead */
.op2-sl-l .op2-lg-s { flex-wrap: wrap; white-space: normal; min-width: 0; row-gap: 0; }
.op2-sl-l .op2-lg-s > b { white-space: nowrap; }
/* a top-3 place in the group reads as its medal (like the League board's rows) */
.op2-lg-s--md .op2-md--xs { margin: 0; vertical-align: 0; flex: none; }
.op2-sl-l .op2-lg-s--md .op2-md--xs, .op2-sl-l .op2-lg-s--md .op2-md--xs .op2-mi { width: 15px; height: 15px; }
.op2-sl-cn { font-weight: 600; color: var(--oc3-ink-3); }
/* the best-rank slot: the roster medal (or "#4") takes the icon's place */
.op2-sl-md .op2-md { width: 26px; height: 26px; font-size: 12px; }
.op2-sl-md .op2-md.has-mi, .op2-sl-md .op2-mi { width: 30px; height: 30px; }
.op2-sl-md .op2-pl:not(.op2-md) { font-size: 15px; }
/* the league row's words, now the League slot's line */
.op2-lg-s { display: inline-flex; align-items: center; gap: 4px; font-size: calc(13px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); white-space: nowrap; }
.op2-lg-s img, .op2-lg-s picture { width: 16px; height: 16px; object-fit: contain; }
.op2-lg-s b { font-family: var(--oc3-data); font-weight: 700; color: var(--oc3-ink); font-variant-numeric: tabular-nums; }

/* ranks inside the clan: the focal band — the roster's medals and podium tint, one cell per stat */
.op2-rkb { margin-top: 14px; }
.op2-rkb .op2-sh { color: var(--oc3-ink); border-bottom: 0; padding-bottom: 0; margin-bottom: 7px; }
.op2-rk { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 14px; }
/* fix1: the roster's stat rows — a hairline over each row, the medal carries the podium (no boxed cells, no gold tint) */
#oc3.op2 .op2-rk-c {
  display: grid; grid-template-columns: 26px minmax(0, 1fr); grid-template-rows: auto auto; column-gap: 7px; align-items: center;
  min-width: 0; padding: 8px 0; background: none; border-radius: 0; border-top: 1px solid var(--oc3-line);
}
.op2-rk-c .op2-pl { grid-row: 1 / 3; justify-self: center; }
.op2-rk-t { overflow: hidden; text-overflow: ellipsis; }
#oc3.op2 .op2-rk-c.is-tt { box-shadow: inset 0 0 0 1.5px var(--oc3-ink-3); }
.op2-rk-v { display: inline-flex; align-items: center; gap: 4px; min-width: 0; white-space: nowrap; }
.op2-rk-v b { font-family: var(--oc3-data); font-weight: 700; font-size: calc(15px * var(--oc3-ts, 1)); line-height: 1.15; color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-rk-v .op2-ok { margin-left: 0; }
.op2-rk-i { width: 16px; height: 16px; object-fit: contain; flex: none; }
.op2-rk-lg { width: 24px; height: 24px; object-fit: contain; margin: -2px 0 -3px; }
.op2-rk-l { font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.25; color: var(--oc3-mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* small text on a tinted surface (podium cells, wells, the leader row) takes the tertiary ink: the caption step is under 4.5:1 there */
:is(.op2-rk-c.is-m1, .op2-rk-c.is-m2, .op2-rk-c.is-m3) .op2-rk-l, .oc3-li.is-lead :is(.op2-of, .oc3-li-sub) { color: var(--oc3-ink-3); }
.op2-rk-none { display: flex; align-items: center; gap: 7px; padding: 10px 12px; border-radius: 6px; background: var(--oc3-summary); font-size: calc(13px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); }
.op2-rk-none img, .op2-rk-none picture { width: 18px; height: 18px; object-fit: contain; flex: none; }

/* war form + attacks used: fact cells (the clan page's fact line, labels kept on phones) */
.op2-war1 { display: grid; gap: 10px; margin-top: 14px; }
.op2-fx { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px 8px; }
.op2-fx > li { display: grid; grid-template-columns: 22px minmax(0, 1fr); grid-template-rows: auto auto; column-gap: 6px; align-items: center; min-width: 0; padding: 2px 0; }
.op2-fx-i { grid-row: 1 / 3; width: 22px; height: 22px; object-fit: contain; }
.op2-fx b { font-family: var(--oc3-clash); font-weight: 700; font-size: 14px; line-height: 1.15; letter-spacing: .02em; color: var(--oc3-ink); white-space: nowrap; font-variant-numeric: tabular-nums; }
.op2-fx b small { font-size: 11px; color: var(--oc3-ink-3); margin-left: 1px; }
.op2-fx > li > span { font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.25; color: var(--oc3-mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* foot: last active, this week's actions, the next war — on the summary well at the card's foot */
.op2-foot { margin: 14px -14px 0; padding: 10px 14px 12px; background: var(--oc3-summary); border-top: 1px solid var(--oc3-line); display: grid; gap: 8px; }
/* right under the slot band: the band's hairlines run into the foot's top edge */
@media (max-width: 1023.98px) { .op2-sls + .op2-foot { margin-top: 0; } }
/* a foot that only holds the jump strip: slimmer */
.op2-foot--j { padding-top: 8px; padding-bottom: 8px; }
/* the card ends on its foot well when one shows on this device, else on its padding */
.op2-score { padding-bottom: 16px; }
@media (max-width: 1023.98px) { .op2-score:has(> .op2-foot:not(.op2-dt)) { padding-bottom: 0; } }
@media (min-width: 1024px) { .op2-score:has(> .op2-foot:not(.op2-ph)) { padding-bottom: 0; } }
.op2-pulse { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; font-size: calc(13px * var(--oc3-ts, 1)); color: var(--oc3-ink-2); }
.op2-la { display: inline-flex; align-items: center; gap: 0 5px; flex-wrap: wrap; }
.op2-la img, .op2-la picture { width: 18px; height: 18px; object-fit: contain; }
.op2-pulse b { font-family: var(--oc3-data); font-weight: 700; color: var(--oc3-ink); }
#oc3 .op2-la-w { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; color: var(--oc3-ink-2); font-size: calc(13px * var(--oc3-ts, 1)); }
.op2-la-w img, .op2-la-w picture { width: 16px; height: 16px; }
.op2-next { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: calc(13px * var(--oc3-ts, 1)); color: var(--oc3-ink-2); }
/* fix1: the line wraps instead of cutting the start time ("map #1 · …" at 360) */
.op2-next-t { min-width: 0; overflow-wrap: anywhere; line-height: 1.35; }
.op2-next b { font-family: var(--oc3-sans); font-weight: 700; color: var(--oc3-ink); }
.op2-chip { flex: none; display: inline-flex; align-items: center; padding: 3px 9px; border-radius: 999px; font-family: var(--oc3-clash); font-weight: 700; font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; }
.op2-chip.is-prep { background: linear-gradient(135deg, var(--oc3-gold-a), var(--oc3-gold-b)); color: var(--oc3-gold-ink); }
.op2-chip.is-live { background: linear-gradient(135deg, #d0392f, #b3302a); color: #fff; }
.op2-chip.is-cwl { background: var(--oc3-raised); color: var(--oc3-ink-2); border: 1px solid var(--oc3-line); }

/* ════ jump strip (fix3): "Jump to" + one icon per board at the foot of the first card; player-v2.js pins it under the
   site menu (.is-fixed) once the card has scrolled away, and marks the board in view ════ */
.op2-jwrap { min-height: 40px; }
.op2-jump { display: flex; align-items: center; gap: 10px; min-width: 0; }
.op2-jump-l { flex: none; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); white-space: nowrap; }
.op2-jump ul { display: flex; flex: 1; gap: 4px; min-width: 0; }
.op2-jump li { flex: 1 1 0; min-width: 0; max-width: 64px; }
#oc3 a.op2-j {
  display: flex; align-items: center; justify-content: center; gap: 6px; height: 40px; padding: 0 4px;
  background: var(--oc3-card); border: 1px solid var(--oc3-line); color: var(--oc3-ink-2);
  font-family: var(--oc3-clash); font-weight: 700; font-size: 10.5px; letter-spacing: .05em; text-transform: uppercase;
}
#oc3 a.op2-j:hover { border-color: var(--oc3-line-2); color: var(--oc3-ink); }
#oc3 a.op2-j:focus-visible { outline: 2px solid var(--oc3-ink-2); outline-offset: 1px; }
.op2-j-i { width: 22px; height: 22px; object-fit: contain; flex: none; }
.op2-j span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
#oc3 a.op2-j.is-on { background: var(--op2-jump-on); border-color: var(--op2-jump-on); color: var(--op2-jump-on-ink); }
/* pinned: a slim bar the width of the page column, under the site menu */
.op2-jwrap.is-fixed .op2-jump {
  position: fixed; z-index: 30; top: var(--op2-stick); left: 0; right: 0; padding: var(--op2-jpy) var(--op2-jx, 16px);
  background: var(--op2-page); box-shadow: 0 1px 0 var(--oc3-line), 0 8px 16px -12px rgba(16, 24, 40, .35);
  animation: op2-jin .18s cubic-bezier(.16, 1, .3, 1) both;
}
@keyframes op2-jin { from { transform: translateY(-8px); opacity: 0; } to { transform: none; opacity: 1; } }
/* a board reached by its #address lands under the menu + the pinned strip (40px + its padding) + one card gap (fix5) */
#oc3.op2 .oc3-sec { scroll-margin-top: calc(var(--op2-stick) + 40px + 2 * var(--op2-jpy) + 12px); }
@media (prefers-reduced-motion: reduce) { .op2-jwrap.is-fixed .op2-jump { animation: none; } }

/* ════ 2 · war ════ */
.op2-war-b { display: grid; gap: 14px; }
.op2-srcm { margin-top: 0; }
.op2-srcm .oc3-m { row-gap: 7px; }
.op2-srcn { margin-left: 4px; font-family: var(--oc3-clash); font-weight: 700; font-size: 10.5px; letter-spacing: .03em; color: var(--oc3-ink-3); }
#oc3 .op2-cmp { position: relative; overflow: visible; }
#oc3 .op2-cmp i { border-radius: 999px 0 0 999px; }
#oc3 .op2-cmp u { position: absolute; top: -4px; bottom: -4px; width: 2px; margin-left: -1px; background: var(--op2-avg); text-decoration: none; }
.op2-m-foot { grid-column: 1 / -1; display: flex; justify-content: space-between; gap: 10px; font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); }
.op2-avg { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.op2-avg i { display: inline-block; width: 2px; height: 11px; background: var(--op2-avg); }
.op2-avg b { font-family: var(--oc3-data); font-weight: 700; color: var(--oc3-ink-2); }
.op2-cap { caption-side: top; text-align: left; padding: 0 0 6px; font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
.op2-tbl thead :is(th, td) { padding: 0 4px 6px; border-bottom: 1px solid var(--oc3-line-2) !important; text-align: right; font-family: var(--oc3-clash); font-weight: 700; font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--oc3-ink-3); white-space: nowrap; }
.op2-tbl thead th img, .op2-tbl thead th picture { width: 16px; height: 16px; object-fit: contain; vertical-align: -3px; }
.op2-tbl thead th span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.op2-tbl tbody th { padding: 8px 4px 8px 2px; text-align: left; font-family: var(--oc3-clash); font-weight: 700; font-size: 12px; letter-spacing: .03em; color: var(--oc3-ink-2); }
.op2-tbl td { padding: 8px 4px; text-align: right; font-family: var(--oc3-data); font-weight: 600; font-size: calc(14px * var(--oc3-ts, 1)); color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-tbl tbody tr + tr { border-top: 1px solid var(--oc3-line); }
.op2-tbl tbody tr:nth-child(even) { background: var(--oc3-zebra); }
.op2-tbl td.op2-nil { text-align: left; padding-left: 14px; font-family: var(--oc3-sans); font-weight: 400; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
.op2-atts-w .op2-sh--rule { margin-top: 0; }
.op2-atts > li { display: grid; grid-template-columns: minmax(0, 1fr) auto; row-gap: 5px; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--oc3-line); }
.op2-atts > li:last-child { border-bottom: 0; }
.op2-att-l { display: inline-flex; align-items: center; gap: 7px; font-size: calc(13.5px * var(--oc3-ts, 1)); color: var(--oc3-ink-2); }
.op2-att-l img, .op2-att-l picture { width: 18px; height: 18px; object-fit: contain; }
.op2-att-v { display: inline-flex; align-items: center; font-family: var(--oc3-data); font-weight: 700; font-size: calc(15px * var(--oc3-ts, 1)); color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-att-v small { font-size: .8em; font-weight: 600; color: var(--oc3-ink-3); }
.op2-att.is-max .op2-att-v, .op2-att.is-max .op2-att-v small { color: var(--oc3-green); }
.op2-atts .oc3-meter { grid-column: 1 / -1; height: 6px; }
.op2-att-d { grid-column: 1 / -1; font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-mute); }

/* ════ 3 · this week ════ */
.op2-week .oc3-tabs { margin-bottom: 0; }
.op2-read-rk { display: inline-flex !important; align-items: center; gap: 4px; flex-wrap: wrap; }
.op2-read-rk b { font-family: var(--oc3-data); font-weight: 700; color: var(--oc3-ink); }
.op2-spark { color: var(--op2-chart); }
.op2-days { display: flex; justify-content: space-between; margin-top: 4px; font-size: calc(11px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); font-variant-numeric: tabular-nums; }
.op2-days .is-today { color: var(--oc3-ink-2); font-weight: 600; }
.op2-spark .oc3-spark-c { margin-top: 6px; }
.op2-spark .oc3-spark-x { height: 46px; }
.op2-week .oc3-state[data-state="idle"] .oc3-dot { background: var(--oc3-tie); animation: none; }
#oc3.op2 .op2-read--solo { grid-template-columns: minmax(0, 1fr); }

/* ════ 4 · favourite army (layout C) ════ */
/* category tabs: neutral ink by default (This week holds the page's gold tab); vis_p2_fav_gold adds .oc3-today = C's gold */
.op2-army .oc3-tabs { grid-template-columns: repeat(var(--tc, 6), minmax(0, 1fr)); }
.op2-fav-read { grid-template-columns: minmax(0, 1fr) !important; margin-bottom: 2px; }
.op2-army .oc3-board .oc3-list { margin-top: 8px; }
.op2-li-u { width: 26px; height: 26px; object-fit: contain; flex: none; margin: -3px 0; }
.oc3-li-v small.op2-of { font-size: calc(12px * var(--oc3-ts, 1)); font-weight: 600; color: var(--oc3-mute); margin-left: 1px; }
#oc3.op2 .op2-army .oc3-li-a { font-family: var(--oc3-sans); }
.op2-fav-none { padding: 12px 2px 4px; }
.op2-army .oc3-note { margin-top: 10px; }

/* ════ 5 · upgrades ════ */
.op2-up-sum { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px 12px; margin-bottom: 12px; padding: 11px 12px 12px; background: var(--oc3-summary); border-radius: 6px; }
.op2-up-sum > li { display: grid; grid-template-columns: 20px auto 1fr; grid-template-rows: auto auto auto; align-items: center; column-gap: 5px; row-gap: 4px; min-width: 0; }
.op2-up-sum img, .op2-up-sum picture { width: 20px; height: 20px; object-fit: contain; }
.op2-up-sum b { font-family: var(--oc3-data); font-weight: 700; font-size: calc(14px * var(--oc3-ts, 1)); color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-up-sum .op2-ok { margin-left: 0; }
.op2-up-sum .oc3-meter { grid-column: 1 / -1; height: 5px; }
.op2-up-sum li > span:last-child { grid-column: 1 / -1; font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op2-upg .oc3-note { margin: 10px 0 0; }
.op2-upg .oc3-grp-s .op2-ok { margin-left: 3px; }
/* tile meters take their length from --p (no inline width: shorter markup for ~130 tiles) */
.op2-upg .oc3-u .oc3-meter i { width: calc(var(--p, 0) * 1%); }
.op2-locked { display: flex; align-items: center; gap: 6px; margin-top: 6px; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
.op2-locked img, .op2-locked picture { width: 16px; height: 16px; object-fit: contain; opacity: .8; }
/* the tile tip is the page tooltip (name + level), not the clan page's name-only tip */
#oc3.op2 .op2-upg .oc3-u.is-tt .oc3-u-i { outline: 2px solid var(--oc3-ink); outline-offset: 1px; }

/* ════ 6 · history ════ */
.op2-ten { display: flex; align-items: center; gap: 8px; font-size: calc(13.5px * var(--oc3-ts, 1)); color: var(--oc3-ink-2); line-height: 1.6; }
.op2-ten small { color: var(--oc3-mute); font-size: calc(12.5px * var(--oc3-ts, 1)); }
.op2-ten b { font-family: var(--oc3-clash); font-weight: 700; font-size: 12px; letter-spacing: .02em; color: var(--oc3-ink); }
.op2-moves { margin-top: 8px; }
.op2-moves li { display: flex; align-items: center; gap: 10px; padding: 5px 0; border-top: 1px solid var(--oc3-line); font-size: calc(13px * var(--oc3-ts, 1)); }
.op2-mv-d { flex: none; min-width: 92px; font-family: var(--oc3-data); font-weight: 600; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); font-variant-numeric: tabular-nums; }
.op2-mv-t { display: inline-flex; align-items: center; gap: 6px; min-width: 0; color: var(--oc3-ink-3); white-space: nowrap; overflow: hidden; }
.op2-mv-t b { font-family: var(--oc3-clash); font-weight: 700; font-size: 12px; letter-spacing: .02em; color: var(--oc3-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op2-mv-t i { font-style: normal; color: var(--oc3-mute); }
.op2-mv-t svg { flex: none; color: var(--oc3-mute); }
.op2-ls { display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; column-gap: 10px; align-items: center; padding: 7px 2px; border-bottom: 1px solid var(--oc3-line); }
.op2-ls:last-child, .op2-ls:has(+ .op2-ls[hidden]) { border-bottom: 0; }
.op2-ls-i { width: 26px; height: 26px; object-fit: contain; }
.op2-ls-n { display: grid; min-width: 0; }
.op2-ls-n b { font-family: var(--oc3-clash); font-weight: 700; font-size: 13px; letter-spacing: .02em; color: var(--oc3-ink); }
.op2-ls-n small { font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op2-ls-v { display: grid; justify-items: end; }
.op2-ls-v > b { display: inline-flex; align-items: center; gap: 3px; font-family: var(--oc3-data); font-weight: 700; font-size: calc(15px * var(--oc3-ts, 1)); color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-ls-v img, .op2-ls-v picture { width: 14px; height: 14px; object-fit: contain; }
.op2-ls-v > small { display: inline-flex; align-items: center; gap: 3px; font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-mute); font-variant-numeric: tabular-nums; }
.op2-ls-v > small img, .op2-ls-v > small picture { width: 12px; height: 12px; }
.op2-ls.is-old .op2-ls-i { opacity: .85; }
.op2-wk { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; margin-bottom: 10px; }
.op2-wk li { display: grid; gap: 3px; min-width: 0; padding: 8px 9px; background: var(--oc3-summary); border-radius: 6px; }
.op2-wk-d { display: inline-flex; align-items: center; gap: 5px; font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); white-space: nowrap; }
.op2-wk-d img, .op2-wk-d picture { width: 20px; height: 20px; object-fit: contain; }
.op2-wk b { display: inline-flex; align-items: center; gap: 4px; font-family: var(--oc3-data); font-weight: 700; font-size: calc(15px * var(--oc3-ts, 1)); color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-wk b img, .op2-wk b picture { width: 14px; height: 14px; }
.op2-wk-p { font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); white-space: nowrap; }
.op2-fx--rec { margin-top: 2px; }
.op2-fx--rec > li > span { white-space: normal; }

/* ════ 7 · achievements ════ */
.op2-ach-top { display: grid; gap: 9px; padding: 11px 12px; background: var(--oc3-summary); border-radius: 6px; }
.op2-ach-m { height: 8px; }
.op2-vil { display: flex; flex-wrap: wrap; gap: 4px 16px; }
.op2-vil li { display: inline-flex; align-items: center; gap: 5px; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); }
.op2-vil b { font-family: var(--oc3-data); font-weight: 700; font-size: calc(14px * var(--oc3-ts, 1)); color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-vil b small { font-size: .82em; font-weight: 600; color: var(--oc3-ink-3); }
#oc3.op2 .op2-vil li.is-max b, #oc3.op2 .op2-vil li.is-max b small { color: var(--oc3-green); }
.op2-vil .op2-ok { margin-left: -1px; }
.op2-uns > li { display: grid; grid-template-columns: minmax(0, 1fr) auto; row-gap: 6px; column-gap: 10px; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--oc3-line); }
.op2-uns > li:last-child, .op2-uns > li:has(+ li[hidden]) { border-bottom: 0; }
.op2-un-n { display: grid; min-width: 0; }
.op2-un-n b { font-family: var(--oc3-clash); font-weight: 700; font-size: 13px; letter-spacing: .02em; color: var(--oc3-ink); }
.op2-un-n small { font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
.op2-un-v { display: grid; justify-items: end; gap: 2px; }
.op2-un-v b { font-family: var(--oc3-data); font-weight: 700; font-size: calc(14px * var(--oc3-ts, 1)); color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-un-v b small { font-size: .82em; font-weight: 600; color: var(--oc3-ink-3); }
.op2-uns .oc3-meter { grid-column: 1 / -1; height: 6px; }
.op2-fx--car { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 12px; }
.op2-ach .op2-sh--rule + .op2-none { margin-top: 0; }

.op2-src { margin-top: 2px; }

/* ── narrow phones ── */
@media (max-width: 379.98px) {
  #oc3.op2 .op2-rk-c { grid-template-columns: 22px minmax(0, 1fr); column-gap: 5px; padding: 8px 0; }
  .op2-rk-v b { font-size: calc(14px * var(--oc3-ts, 1)); }
  .op2-md { width: 20px; height: 20px; font-size: 11px; }
  .op2-fx b { font-size: 13px; }
  .op2-fx > li { grid-template-columns: 20px minmax(0, 1fr); column-gap: 5px; }
  .op2-fx-i { width: 20px; height: 20px; }
  #oc3.op2 .op2-sl { padding-left: 12px; padding-right: 8px; column-gap: 7px; grid-template-columns: 28px minmax(0, 1fr); }
  .op2-sl-i, .op2-sl-i > img, .op2-sl-i > picture { width: 28px; height: 28px; }
  .op2-sl-v > b { font-size: 15px; }
  .op2-jump { gap: 8px; }
  .op2-wk li { padding: 7px 7px; }
  .op2-up-sum { column-gap: 8px; padding-inline: 10px; }
  .op2-up-sum > li { grid-template-columns: 18px auto 1fr; column-gap: 4px; }
  .op2-up-sum img, .op2-up-sum picture { width: 18px; height: 18px; }
  .op2-up-sum b { font-size: calc(13px * var(--oc3-ts, 1)); }
}
@media (max-width: 389.98px) {
  /* narrow phones: the labels chip gives its line back to the first screen */
  .op2-lbls { display: none; }
}
@media (max-width: 479.98px) {
  .op2-hide-s { display: none; }
  /* favourite army tabs: icon-only in one row (the labels stay for screen readers), like the clan page's board tabs */
  .op2-army .oc3-tab { min-height: 44px; padding: 6px 2px; }
  .op2-army .oc3-tab-i { width: 24px; height: 24px; }
  .op2-army .oc3-tab span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .op2-army:not(.oc3-today) .oc3-read-v.is-multi { display: grid; grid-template-columns: repeat(3, auto); justify-content: start; column-gap: 16px; }
  /* fix1: p2_trio_phone (default = the clan page's c3_trio_phone, "beside" live): the icon left of its number, the three spread over the row */
  #oc3.op2 .op2-army[data-tri="beside"] .oc3-read-v.is-multi { justify-content: space-between; column-gap: 8px; }
  #oc3.op2 .op2-army[data-tri="beside"] .oc3-read-v.is-multi .oc3-res { flex-direction: row; align-items: center; gap: 4px; }
}
@media (min-width: 480px) {
  .op2-rk { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* five or six tabs in a row: the icon over its label */
  .op2-week .oc3-tab, .op2-army .oc3-tab { flex-direction: column; gap: 3px; min-height: 54px; padding: 6px 4px; font-size: 10px; }
  .op2-week .oc3-tab span, .op2-army .oc3-tab span { max-width: 100%; }
  .oc3 .op2-fav-read .oc3-read-v.is-multi { flex-direction: row; flex-wrap: wrap; gap: 4px 22px; }
}

/* ── ≥768: labels beside the icons, facts wider ── */
@media (min-width: 768px) {
  #oc3.op2 { gap: 14px; }
  .op2-j span { position: static; width: auto; height: auto; clip: auto; overflow: hidden; text-overflow: ellipsis; }
  .op2-jump li { max-width: 170px; }
  .op2-tbl thead th span { position: static; width: auto; height: auto; clip: auto; margin-left: 4px; }
  .op2-up-sum { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .op2-fx--car { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .op2-sls { margin: 18px -20px 0; }
  #oc3.op2 .op2-sl { padding: 11px 14px 12px 20px; }
  .op2-foot { margin: 18px -20px 0; padding: 12px 20px 14px; }
  .op2-foot--j { padding-top: 9px; padding-bottom: 9px; }
  .op2-id { grid-template-columns: 88px minmax(0, 1fr); gap: 0 18px; }
  .op2-th { width: 88px; height: 88px; }
  /* war: the 3-star meter beside regular vs CWL; the attendance bars (when on) under both */
  .op2-war-b { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 28px; align-items: start; }
  .op2-war-b > :only-child, .op2-war-b > .op2-atts-w { grid-column: 1 / -1; }
}


/* ── ≥1024 (fix3): the stat slots run beside the name, the rest of the card under both; the page is a two-column grid
   where a half-width board pairs with the next one (op2_render() gives .op2-half only to real pairs, so no row is half empty) ── */
@media (min-width: 1024px) {
  #oc3.op2 { --op2-stick: 152px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; align-items: stretch; }
  #oc3.op2 > * { grid-column: 1 / -1; }
  #oc3.op2 > .op2-half { grid-column: auto; }
  .op2-score { display: grid; grid-template-columns: fit-content(460px) minmax(0, 1fr); column-gap: 26px; align-items: center; }
  .op2-score > * { grid-column: 1 / -1; }
  .op2-score > .op2-id { grid-column: 1; }
  /* the strip: one cell per slot, a hairline before each; wraps to a second row past ~4 slots */
  .op2-score > .op2-sls {
    grid-column: 2; align-self: center; margin: 0; background: none; border-top: 0; gap: 10px 0;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  }
  #oc3.op2 .op2-sls > .op2-sl { background: none; padding: 4px 10px 4px 18px; border-left: 1px solid var(--oc3-line); grid-template-columns: 34px minmax(0, 1fr); column-gap: 10px; }
  .op2-sls .op2-sl-i, .op2-sls .op2-sl-i > img, .op2-sls .op2-sl-i > picture { width: 34px; height: 34px; }
  .op2-sls .op2-sl-v > b { font-size: 17px; }
  /* checker (life): the league / best-league name gets ~85 px beside its badge — a step smaller and untracked, so "Valkyrie 15",
     "P.E.K.K.A 23", "Unranked" fit or wrap at the space instead of "Valkyr…" */
  #oc3.op2 .op2-sls .op2-sl--league .op2-sl-v > b, #oc3.op2 .op2-sls .op2-sl--best .op2-sl-v > b { font-size: 14.5px; letter-spacing: 0; }
  .op2-sls .op2-sl-l { font-size: calc(12.5px * var(--oc3-ts, 1)); }
  .op2-sl--wide { grid-column: auto; }
  .op2-rkb { margin-top: 20px; }
  .op2-rk { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); column-gap: 18px; }
  #oc3.op2 .op2-rk-c { padding: 11px 0; grid-template-columns: 30px minmax(0, 1fr); column-gap: 10px; }
  .op2-rk-i { width: 18px; height: 18px; }
  .op2-rk-l { font-size: calc(12.5px * var(--oc3-ts, 1)); }
  .op2-rkb .op2-md { width: 26px; height: 26px; font-size: 13px; }
  .op2-rk-c .op2-pl:not(.op2-md) { font-size: 15px; }
  /* war form beside attacks used; one of them alone (the other hidden or device-hidden) takes the width */
  .op2-war1 { display: flex; gap: 28px; margin-top: 18px; }
  .op2-w1b { flex: 1 1 0; min-width: 0; }
  .op2-foot { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
  .op2-foot > .op2-jwrap { grid-column: 1 / -1; }

  /* a half-width board: its inner two-column layouts stack */
  .op2-half .op2-war-b { grid-template-columns: minmax(0, 1fr); }
  .op2-half .op2-fx--car { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* This week as a half board: the chart takes the height its partner gives (the clan page's pulse pairing) */
  .op2-half.op2-week { display: flex; flex-direction: column; }
  .op2-fav-read .oc3-read-fig .oc3-read-u { max-width: none; }
  .op2-half.op2-week .oc3-board { flex: 1; display: flex; flex-direction: column; }
  .op2-half.op2-week .oc3-read:not([hidden]) { flex: 1; align-items: stretch; grid-template-columns: minmax(150px, 210px) minmax(0, 1fr); }
  .op2-half.op2-week .oc3-read-fig { align-self: end; }
  .op2-half.op2-week .op2-spark { display: flex; flex-direction: column; }
  .op2-half.op2-week .op2-spark svg { flex: 1; height: auto; min-height: 90px; }
  .op2-half.op2-week .oc3-spark-x { height: auto; bottom: 52px; }
}

@media (prefers-reduced-motion: reduce) {
  #oc3.op2 .oc3-meter i, #oc3.op2 .oc3-li-bar i, #oc3.op2 .oc3-dot, #oc3.op2 .oc3-li.is-lead .oc3-li-bar i::after { animation: none !important; }
}

/* ── fix1 (2026-09-25): Favourite army reads like the roster Scoreboard — medals on the top 3, green bars, no gold row ── */
.op2-army--sb:not(.op2-army--gold) .oc3-li.is-lead .oc3-li-a { background: none; }
.op2-army--sb .oc3-li-bar i { background: linear-gradient(90deg, var(--oc3-hero-bar-a), var(--oc3-hero-bar-b)); }
.op2-army--sb .oc3-li-n { display: inline-flex; align-items: center; justify-content: center; }
.op2-army--sb .oc3-li-n .op2-pl--s, .op2-army--sb .oc3-li-n .op2-pl--s .op2-mi { width: 22px; height: 22px; font-size: 11px; }
/* League history: weeks and seasons share one row; a week's place medal sits on the small line */
.op2-ls-v > small .op2-md--xs { vertical-align: -3px; }

/* ── fix4 (2026-09-26) ── */
/* R3 "↑ Top" at the end of the jump strip: a hairline sets it apart from the boards; by default it only shows once the strip
   is pinned (at the top of the page there is nowhere to go back to) */
.op2-jump li.op2-j-tli { padding-left: 5px; border-left: 1px solid var(--oc3-line); }
.op2-jwrap:not(.is-fixed) .op2-j-tli.is-pin { display: none; }
.op2-j-up { color: var(--oc3-ink-2); }
#oc3 a.op2-j-top:hover .op2-j-up { color: var(--oc3-ink); }
/* R7 History: a part's rows, then its "Show older" button; two lists of one kind in a row keep the rows' hairline between them */
.op2-hb > .op2-lss + .op2-lss { border-top: 1px solid var(--oc3-line); }
.op2-hb > .oc3-more + .op2-lss { margin-top: 6px; border-top: 1px solid var(--oc3-line); }
.op2-hb--c > .op2-ten + .oc3-more { padding-top: 4px; }
.op2-ten-c small { white-space: nowrap; }
/* R1 league rows: the stats picked for the small line, "·" between them */
.op2-ls-s { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
/* id weight: clan-v3.css clears every pseudo-element inside #oc3 */
#oc3 .op2-ls-s + .op2-ls-s::before { content: "·"; margin: 0 5px 0 2px; color: var(--oc3-ink-3); }
.op2-ls-v > b .op2-md { width: 20px; height: 20px; font-size: 11px; }
.op2-ls.is-best .op2-ls-n small { color: var(--oc3-ink-3); }
.op2-ls.is-best .op2-ls-v > small { white-space: nowrap; }
/* narrow phones: two or more stats on a league row's small line stack (the week's date keeps its line); four or more
   records run two by two (their labels would wrap on three lines in thirds) */
@media (max-width: 389.98px) {
  .op2-ls-v > small:has(> .op2-ls-s + .op2-ls-s) { flex-direction: column; align-items: flex-end; gap: 1px; }
  #oc3 .op2-ls-v > small .op2-ls-s + .op2-ls-s::before { content: none; }
}
@media (max-width: 479.98px) {
  .op2-fx--rec:has(> li:nth-child(4)) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* fix4b: a record / career cell keeps its figure on top of its label (a neighbour's label on two lines no longer opens a gap
   between them); career names wrap like the records' labels instead of ending in "…"; a league / CWL league name as a record */
.op2-fx > li { align-content: start; }
.op2-fx--car > li > span { white-space: normal; }
.op2-fx > li.is-txt b { white-space: normal; }

/* ── fix5 (2026-09-26) ── */
/* F1 (Félix: "the progress bar colours have no logic"): ONE rule for every bar on the page — the war 3-star rate, the
   attendance, Favourite army, the Upgrades figures and tiles, Achievements: a bar that measures progress, a share or an
   amount is green (--op2-bar → --op2-bar-b, by default the clan page's sorted-column bars), its track is the only grey.
   No gold bar anywhere: the medals and the podium tint already mark #1 (vis_p2_fav_gold keeps its gold tabs and the
   leader's shimmer only). The war meter's clan-average tick stays ink. Id weight: out-ranks the clan page's slate / grey /
   near-max tint / gold-leader fills. */
#oc3.op2 :is(.oc3-meter, .oc3-li-bar) { background: var(--op2-track); }
#oc3.op2 :is(.oc3-meter, .oc3-li-bar) > i { background: linear-gradient(90deg, var(--op2-bar), var(--op2-bar-b)); }
#oc3.op2 .oc3-meter.is-max > i { border-radius: 999px; }
/* F2 (checker): a long note ("193 attacks in OUTSKIRT since joining") keeps its line; the clan average moves under it, right */
#oc3.op2 .op2-m-foot { flex-wrap: wrap; row-gap: 2px; }
#oc3.op2 .op2-m-foot .op2-avg { margin-left: auto; }
/* F3 (checker): each record has its own icon key now, so an emoji or no icon (a single space) must hold the cell: an emoji
   icon is an icon, not a label (the label rule shrank it to 12px); a cell without an icon keeps its figure and label in the
   text column, lined up with the others */
#oc3.op2 .op2-fx > li > .op2-fx-i.oc3-emo { font-size: calc(var(--oc3-es, 22px) * .8); line-height: 1; color: inherit; white-space: nowrap; overflow: hidden; }
#oc3.op2 .op2-fx > li > b:first-child, #oc3.op2 .op2-fx > li > b:first-child + span { grid-column: 2; }
/* narrow phones: three records in thirds left ~70px per label ("best builder base season" on four lines) — the icon stays
   beside the figure and the label runs under both */
@media (max-width: 389.98px) {
  #oc3.op2 .op2-fx--rec > li > .op2-fx-i { grid-row: 1; }
  #oc3.op2 .op2-fx--rec > li > span:not(.op2-fx-i), #oc3.op2 .op2-fx--rec > li > b:first-child + span { grid-column: 1 / -1; }
}
/* F2: in "in this clan since joining" mode the lone source name opens a tooltip (why ClashSpot and ClashPerk sit out); a dotted
   rule says the small word can be tapped, like nothing else on the row */
.op2-srcn.is-tip { text-decoration: underline dotted; text-underline-offset: 3px; }

/* ── fix6 · Battle log board (builder "Battle log board", 2026-09-26): mockup A's rows — op2_sec_log() / op2_log_row().
   Swords or shield, the opponent's Town Hall and name (not a link), the small line, the stars over the destruction + a Ranked
   battle's trophies or a multiplayer battle's gold. Each cell has its column, so an icon blanked in the admin (or the Town Hall
   switched off) never shifts the others. [log life builder] the row is .op2-bl-g inside the list item (a <summary> when the
   battle opens, a <div> when it does not). [log2 builder] (2026-09-27) + the two summary panels, the switches, the pinned day
   headers, trophies / loot per row, the loot breakdown — the rule set: battlelog-rules.md ── */
.op2-bls { position: relative; }
/* each shown item draws its top rule, except the first one shown ([data-lead], kept by op2_sec_log() and player-v2.js): a filter
   or a sort never leaves a stray rule, and nothing clips the rows gliding to their new places */
.op2-bls > li { border-top: 1px solid var(--oc3-line); }
.op2-bls > li.op2-bld, .op2-bls > li[data-lead] { border-top: 0; }
.op2-bl-g { display: grid; grid-template-columns: 20px 28px minmax(0, 1fr) auto; column-gap: 9px; align-items: center; padding: 8px 2px; }
.op2-bl.is-x .op2-bl-g { grid-template-columns: 20px 28px minmax(0, 1fr) auto 12px; }
.op2-bls--noth .op2-bl-g { grid-template-columns: 20px minmax(0, 1fr) auto; }
.op2-bls--noth .op2-bl.is-x .op2-bl-g { grid-template-columns: 20px minmax(0, 1fr) auto 12px; }
.op2-bl-s { grid-column: 1; width: 20px; height: 20px; object-fit: contain; }
.op2-bl-th { grid-column: 2; width: 28px; height: 28px; object-fit: contain; }
.op2-bl-n { grid-column: 3; display: grid; min-width: 0; overflow: hidden; }
.op2-bl-r { grid-column: 4; display: grid; justify-items: end; gap: 2px; }
.op2-bls--noth .op2-bl-n { grid-column: 2; }
.op2-bls--noth .op2-bl-r { grid-column: 3; }
.op2-bl-n b { font-family: var(--oc3-clash); font-weight: 700; font-size: 13px; letter-spacing: .02em; color: var(--oc3-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op2-bl-n b.is-anon { color: var(--oc3-ink-3); }
/* the small line wraps between its parts, never inside one ("Thu 17:19" stays whole). Every part opens with its "·" and the
   line starts 12px left of the name: the "·" of whichever part begins a line falls in the clipped margin, so no line ever
   starts with a dot (id weight: clan-v3.css clears every pseudo-element inside #oc3) */
.op2-bl-n small { display: flex; flex-wrap: wrap; margin-left: -12px; font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.4; color: var(--oc3-mute); }
.op2-bl-w { white-space: nowrap; }
#oc3 .op2-bl-w::before { content: "·"; display: inline-block; width: 12px; text-align: center; color: var(--oc3-ink-3); }
.op2-bl-r .op2-st, .op2-bl-r .op2-stars picture { width: 15px; height: 15px; }
.op2-bl-r > small { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; font-family: var(--oc3-data); font-weight: 600; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-ink-2); font-variant-numeric: tabular-nums; }
.op2-bl-p, .op2-bl-lt, .op2-bl-tr { display: inline-flex; align-items: center; gap: 3px; }
.op2-bl-p img, .op2-bl-p picture { width: 12px; height: 12px; object-fit: contain; }
.op2-bl-lt, .op2-bl-tr { color: var(--oc3-ink-2); }
.op2-bl-lt img, .op2-bl-lt picture, .op2-bl-tr img, .op2-bl-tr picture { width: 13px; height: 13px; object-fit: contain; }
/* a loss reads as one: gold lost on a multiplayer defence, trophies a Legend I defence cost */
.op2-bl-lt.is-neg, .op2-bl-tr.is-neg { color: var(--op2-bl-neg); }
#oc3.op2 { --op2-bl-neg: #c2362b; }
html[data-theme="dark"] #oc3.op2 { --op2-bl-neg: #ff8a80; }
/* ≈ before a computed trophy figure (the league log has not listed that battle) */
#oc3.op2 .op2-bl-apx { margin-right: 1px; font-style: normal; font-weight: 500; color: var(--oc3-ink-3); }
.op2-bl.is-un .op2-bl-s { opacity: .6; }
.op2-bl-r > small.op2-bl-unt { font-family: var(--oc3-clash); font-weight: 700; font-size: 9.5px; letter-spacing: .07em; text-transform: uppercase; color: var(--oc3-ink-3); white-space: nowrap; }
/* shown first per device (p2_log_n phones & tablets, p2_log_n_desk desktop): the rows (and day headers) between the two counts
   wait for "Show all" on the device with the smaller count (.is-dk = desktop only, .is-ph = phones only) */
@media (max-width: 1023.98px) {
  .op2-bls > .is-dk { display: none; }
  .op2-bls:has(~ .oc3-more [aria-expanded="true"]) > .is-dk:not([hidden]) { display: block; }
}
@media (min-width: 1024px) {
  .op2-bls > .is-ph { display: none; }
  .op2-bls:has(~ .oc3-more [aria-expanded="true"]) > .is-ph:not([hidden]) { display: block; }
}
@media (max-width: 379.98px) {
  .op2-bl-g { column-gap: 7px; grid-template-columns: 18px 24px minmax(0, 1fr) auto; }
  .op2-bl.is-x .op2-bl-g { grid-template-columns: 18px 24px minmax(0, 1fr) auto 10px; }
  .op2-bls--noth .op2-bl-g { grid-template-columns: 18px minmax(0, 1fr) auto; }
  .op2-bls--noth .op2-bl.is-x .op2-bl-g { grid-template-columns: 18px minmax(0, 1fr) auto 10px; }
  .op2-bl-th { width: 24px; height: 24px; }
  .op2-bl-s { width: 18px; height: 18px; }
}
/* ── end fix6 · Battle log board ── */

/* ── [log life builder] → [log2 builder] ────────────────────────────────────────────────────────────────────────────── */
#oc3.op2 .op2-log .op2-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* the controls work only with the page script: without it (the section never marked [data-js]) they are not drawn */
.op2-log:not([data-js]) :is(.op2-blc, .op2-bl-fnone) { display: none !important; }

/* summary: two panels, Attacks and Defences, between two hairlines — side by side from 480px of board width (the League
   strip's idiom: a hairline between them), stacked under that (a hairline between them). No card inside the card: the
   panels are regions of the board, told apart by their heading and a rule. */
.op2-blsum { container-type: inline-size; margin: 0 0 10px; border-block: 1px solid var(--oc3-line); }
.op2-blsum-g { display: grid; grid-template-columns: minmax(0, 1fr); }
.op2-bsp { min-width: 0; padding: 10px 2px 11px; }
.op2-bsp + .op2-bsp { border-top: 1px solid var(--oc3-line); }
.op2-bsp[hidden] { display: none; }
@container (min-width: 480px) {
  .op2-blsum.is-two:not(.is-one) .op2-blsum-g { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .op2-blsum.is-two:not(.is-one) .op2-bsp + .op2-bsp { border-top: 0; border-left: 1px solid var(--oc3-line); padding-left: 14px; }
  .op2-blsum.is-two:not(.is-one) .op2-bsp:first-child { padding-right: 12px; }
}
.op2-bsp-h { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 7px; margin: 0 0 8px; font-family: var(--oc3-clash); font-weight: 700; font-size: 11px; line-height: 1.2; letter-spacing: .07em; text-transform: uppercase; color: var(--oc3-ink-2); }
.op2-bsp-hi { width: 18px; height: 18px; object-fit: contain; flex: none; }
#oc3.op2 .op2-bsp-h > b { font-family: var(--oc3-data); font-size: 13px; letter-spacing: 0; color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-bsp-un { margin-left: auto; font-family: var(--oc3-sans); font-weight: 500; font-size: calc(11px * var(--oc3-ts, 1)); letter-spacing: 0; text-transform: none; color: var(--oc3-mute); }
.op2-bsp-un[hidden] { display: none; }
/* the figures in equal columns (three in a phone-wide panel, two in a half-board one): wins – losses, stars, destruction, then
   Ranked trophies with the loot beside them (the loot takes a whole row when there is no trophy cell) */
.op2-bsp-f { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 10px 12px; margin: 0; }
.op2-bsp[data-z] .op2-bsp-f, .op2-bsp:not([data-z]) .op2-bsp-z { display: none; }
.op2-bsp-z { margin: 0; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
.op2-bsp-c { display: grid; align-content: start; gap: 2px; min-width: 0; }
.op2-bsp-c[hidden] { display: none; }
.op2-bsp-lt { grid-column: 1 / -1; }
.op2-bsp-f:has(> .op2-bsp-tr:not([hidden])) > .op2-bsp-lt { grid-column: span 2; }
.op2-bsp-v { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 4px; min-width: 0; }
.op2-bsp-i { width: 16px; height: 16px; object-fit: contain; flex: none; }
.op2-bsp-r { display: inline-flex; align-items: center; gap: 3px; margin-right: 8px; white-space: nowrap; }
.op2-bsp-r:last-child { margin-right: 0; }
.op2-bsp-r[hidden] { display: none; }
.op2-bsp-r .op2-bsp-i { width: 15px; height: 15px; }
#oc3.op2 .op2-bsp b[data-sv] { font-family: var(--oc3-clash); font-weight: 700; font-size: 15px; line-height: 1.15; letter-spacing: .02em; color: var(--oc3-ink); white-space: nowrap; font-variant-numeric: tabular-nums; }
.op2-bsp-wl b + .op2-bsp-i, .op2-bsp-wl b + picture { margin-left: 6px; }
.op2-bsp-l { font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.25; color: var(--oc3-mute); }
.op2-bsp-sub { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 6px; font-size: calc(11px * var(--oc3-ts, 1)); line-height: 1.3; color: var(--oc3-mute); }
.op2-bsp-sub[hidden] { display: none; }
#oc3.op2 .op2-bsp-sub b[data-sv] { font-family: var(--oc3-data); font-size: calc(11.5px * var(--oc3-ts, 1)); font-weight: 700; letter-spacing: 0; color: var(--oc3-ink-2); }
.op2-bsp-sub .op2-bsp-r { margin-right: 4px; gap: 2px; }
.op2-bsp-sub .op2-bsp-i { width: 12px; height: 12px; }
#oc3.op2 .op2-bsp .op2-bl-apx { font-size: 14px; }
/* the Defences loot: figures lost on multiplayer defences (mp), "No loot lost (Ranked)" when only Ranked defences are shown
   (rk), a dash when neither is (none) */
.op2-bsp-lt:not([data-lk="mp"]) :is(.op2-bsp-lv, .op2-bsp-lsub), .op2-bsp-lt:not([data-lk="rk"]) .op2-bsp-nl, .op2-bsp-lt:not([data-lk="none"]) .op2-bsp-nn,
.op2-bsp-lt[data-lk="rk"] .op2-bsp-l { display: none; }
.op2-bsp-lv { display: contents; }
.op2-bsp-nl { font-family: var(--oc3-clash); font-weight: 700; font-size: 13px; letter-spacing: .02em; color: var(--oc3-ink-2); }
.op2-bsp-nn { font-family: var(--oc3-clash); font-weight: 700; font-size: 15px; color: var(--oc3-ink-3); }
@container (max-width: 359.98px) {
  .op2-bsp-f { column-gap: 12px; }
  #oc3.op2 .op2-bsp b[data-sv] { font-size: 14px; }
  .op2-bsp-l { font-size: 11px; }
}

/* controls: the two switches (radio groups, one choice each: All · Attacks · Defences, All · Ranked · Multiplayer) on the first
   line, the chips and the sort switch on the next; frames like the site's segmented control, square (the site's chrome) */
.op2-blc { display: grid; gap: 6px; margin: 0 0 10px; }
.op2-blc-r { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px; }
/* (a switch never truncates its words: it takes its own line when two do not fit side by side) */
.op2-blc { container-type: inline-size; }
.op2-blseg { display: flex; flex: 1 1 auto; border: 1px solid var(--oc3-line-2); background: var(--oc3-line-2); gap: 1px; }
.op2-blseg-b { position: relative; flex: 1 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: 5px; min-height: 36px; padding: 4px 8px; margin: 0; border: 0; border-radius: 0;
  background: var(--oc3-panel); color: var(--oc3-ink-2); font-family: var(--oc3-clash); font-weight: 700; font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; line-height: 1; white-space: nowrap; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.op2-blseg-b:hover { color: var(--oc3-ink); }
.op2-blseg-b[aria-checked="true"] { background: var(--oc3-ink); color: var(--oc3-panel); }
.op2-blseg-i { width: 16px; height: 16px; object-fit: contain; flex: none; }
.op2-blseg-t { white-space: nowrap; }
.op2-blseg-n { font-family: var(--oc3-data); font-weight: 700; font-size: 11px; letter-spacing: 0; text-transform: none; font-variant-numeric: tabular-nums; opacity: .72; }
.op2-blf-g { display: inline-flex; border: 1px solid var(--oc3-line-2); background: var(--oc3-line-2); gap: 1px; }
.op2-blf-c { display: inline-flex; align-items: center; justify-content: center; gap: 5px; min-width: 36px; min-height: 34px; padding: 4px 9px; margin: 0; border: 0; border-radius: 0;
  background: var(--oc3-panel); color: var(--oc3-ink-2); font-family: var(--oc3-clash); font-weight: 700; font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; line-height: 1; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.op2-blf-c:hover { color: var(--oc3-ink); }
.op2-blf-c[aria-pressed="true"] { background: var(--oc3-ink); color: var(--oc3-panel); }
.op2-blf-c:focus-visible, .op2-blo-b:focus-visible, .op2-blseg-b:focus-visible { outline: 2px solid var(--oc3-focus); outline-offset: -2px; z-index: 1; }
.op2-blf-c:focus-visible { position: relative; }
.op2-blf-i { width: 16px; height: 16px; object-fit: contain; flex: none; }
.op2-blf-c--s { gap: 2px; min-width: 34px; padding: 4px 6px; }
.op2-blf-c--s .op2-blf-i { width: 14px; height: 14px; }
.op2-blf-c--s b { font-family: var(--oc3-clash); font-weight: 700; font-size: 12px; }
@media (max-width: 479.98px) {
  #oc3.op2 .op2-blf-t.is-w { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .op2-blf-c { padding: 4px 9px; }
}
@container (max-width: 339.98px) {
  .op2-blseg-b { padding: 4px 6px; gap: 4px; }
  .op2-blseg-i { width: 14px; height: 14px; }
}
@container (max-width: 289.98px) { .op2-blseg-n { display: none; } }
.op2-blo { display: inline-flex; margin-left: auto; border: 1px solid var(--oc3-line-2); background: var(--oc3-line-2); gap: 1px; }
.op2-blo-b { position: relative; display: grid; place-items: center; width: 38px; min-height: 34px; padding: 0; margin: 0; border: 0; border-radius: 0; background: var(--oc3-panel); cursor: pointer; -webkit-tap-highlight-color: transparent; }
.op2-blo-b[aria-checked="true"] { background: var(--oc3-ink); }
.op2-blo-i { width: 17px; height: 17px; object-fit: contain; }
/* with the sliding mark (player-v2.js Slider, motion "tabs"): the mark carries the picked fill, each button a resting fill under it */
#oc3.op2 :is(.op2-blo, .op2-blseg).op2-sld { position: relative; }
#oc3.op2 .op2-blo.op2-sld .op2-blo-b, #oc3.op2 .op2-blseg.op2-sld .op2-blseg-b { background: transparent; }
#oc3.op2 .op2-blo.op2-sld .op2-blo-b::before, #oc3.op2 .op2-blseg.op2-sld .op2-blseg-b::before { content: ""; position: absolute; inset: 0; z-index: -2; background: var(--oc3-panel); pointer-events: none; }
/* the emptied list: which filters emptied it, and Clear */
.op2-bl-fnone { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 12px 2px 4px; font-size: calc(13px * var(--oc3-ts, 1)); line-height: 1.4; color: var(--oc3-mute); }
.op2-bl-fnone[hidden] { display: none; }
.op2-log .oc3-more[hidden], .op2-log .oc3-more button[hidden] { display: none; }

/* day headers: more room above than below; the first rule under them is the row's own. Pinned (vis_p2_log_days_pin): each day's
   header stays under the site menu (and the pinned jump strip) while its battles scroll by */
.op2-bls > .op2-bld { padding: 14px 2px 5px; font-family: var(--oc3-clash); font-weight: 700; font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase; color: var(--oc3-ink-3); }
.op2-bls > .op2-bld:first-child { padding-top: 4px; }
.op2-log.is-pin .op2-bls > .op2-bld { position: sticky; top: var(--op2-stick); z-index: 2; background: var(--oc3-card); }
#oc3.op2:has(.op2-jwrap.is-fixed) .op2-log.is-pin .op2-bls > .op2-bld { top: calc(var(--op2-stick) + 40px + 2 * var(--op2-jpy)); }
.op2-log[data-sort]:not([data-sort="time"]) .op2-bls > .op2-bld { display: none !important; }
.op2-log.has-days[data-sort="time"] .op2-bl-dd { display: none; }

/* a battle that opens: the row is its <summary> (no marker), a chevron at its end; opened, the battle sits on a raised panel
   (the panel reaches 8px past the row so its contents never touch its edge — it is there, transparent, when closed) */
.op2-bl-d { margin: 0 -8px; padding: 0 8px; }
.op2-bl-d[open] { background: var(--oc3-raised); }
summary.op2-bl-g { list-style: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
summary.op2-bl-g::-webkit-details-marker { display: none; }
#oc3 summary.op2-bl-g::marker { content: ""; }
summary.op2-bl-g:focus-visible { outline: 2px solid var(--oc3-focus); outline-offset: 0; }
@media (hover: hover) and (pointer: fine) { .op2-bl-d:not([open]):hover { background: var(--oc3-raised); } }
.op2-bl-cv { grid-column: -2; justify-self: end; color: var(--oc3-ink-3); }
.op2-bl-d[open]:not([data-closing]) .op2-bl-cv { transform: rotate(180deg); }
#oc3.op2[data-mo~="on"] .op2-log[data-lmo~="fold"] .op2-bl-cv { transition: transform var(--op2-mo-st) var(--op2-mo-out); }
/* the fold: one row track, 0fr → 1fr (player-v2.js, motion "fold"); its content clips while it moves */
.op2-bl-x { display: grid; grid-template-rows: 1fr; }
.op2-bl-xi { min-height: 0; overflow: hidden; }
.op2-bl-xi > :first-child { margin-top: 2px; }
.op2-bl-xi > :last-child { margin-bottom: 12px; }
.op2-bl-xi > * + * { margin-top: 12px; }
.op2-bl-xk { display: block; font-family: var(--oc3-clash); font-weight: 700; font-size: 10px; letter-spacing: .07em; text-transform: uppercase; color: var(--oc3-ink-3); }
/* the opponent's Town Hall beside the result */
.op2-bl-xs { display: grid; grid-template-columns: 60px minmax(0, 1fr); column-gap: 12px; align-items: start; }
.op2-bl-xs.is-noth { grid-template-columns: minmax(0, 1fr); }
.op2-bl-xth { display: grid; justify-items: center; gap: 2px; }
.op2-bl-xth-i { width: 52px; height: 52px; object-fit: contain; }
.op2-bl-xth small { font-family: var(--oc3-data); font-weight: 700; font-size: 11px; color: var(--oc3-ink-2); }
.op2-bl-xr { display: grid; gap: 9px; min-width: 0; }
.op2-bl-xd { display: grid; grid-template-columns: 14px minmax(0, 1fr) auto; align-items: center; column-gap: 7px; }
.op2-bl-xd-i { width: 14px; height: 14px; object-fit: contain; }
.op2-bl-xd .oc3-meter { height: 7px; }
.op2-bl-xd b, .op2-bl-xl b { font-family: var(--oc3-data); font-weight: 700; font-size: calc(13px * var(--oc3-ts, 1)); color: var(--oc3-ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* a Ranked battle's trophies: official, or ≈ computed with the rule that gave them */
.op2-bl-xt { display: grid; grid-template-columns: 14px minmax(0, 1fr); column-gap: 7px; align-items: start; }
.op2-bl-xt-i { width: 14px; height: 14px; margin-top: 2px; object-fit: contain; }
.op2-bl-xt p { margin: 0; font-family: var(--oc3-data); font-weight: 700; font-size: calc(13px * var(--oc3-ts, 1)); line-height: 1.35; color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-bl-xt small { display: block; font-family: var(--oc3-sans); font-weight: 500; font-size: calc(11.5px * var(--oc3-ts, 1)); line-height: 1.4; color: var(--oc3-mute); }
/* the loot: one line per resource — the figure, then its split (normal + bonus) and what the base held */
.op2-bl-xl { display: grid; gap: 5px; }
.op2-bl-xl ul { display: grid; gap: 4px; }
.op2-bl-xl li { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 8px; }
.op2-bl-xl img, .op2-bl-xl picture { width: 16px; height: 16px; object-fit: contain; }
.op2-bl-xl small { font-size: calc(11.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); white-space: nowrap; font-variant-numeric: tabular-nums; }
.op2-bl-xz { font-size: calc(12.5px * var(--oc3-ts, 1)); line-height: 1.4; color: var(--oc3-ink-2); }
.op2-bl-xmeta { margin: 0; font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.4; color: var(--oc3-mute); }
/* [army E] (2026-09-29, Félix picked draft E "Compact strip": "Let's do layout E. Pretty good") — battlelog-rules.md §V,
   op2_log_army(): the opened battle's army in every layout (primary, Timeline, Analyst table) and, with p2_log_ar_row, the
   closed row's one-line preview (primary, Timeline). ONE markup: the title (screen readers only), ONE wrapping row .op2-ar-r (its
   group lists are `display: contents`), the line under it (.op2-ar-sum, vis_p2_log_ar_sum). Small tiles on the lifted fill, the
   count on a pill bottom-left, a level ONLY below max: a tag top-right of the tile / the portrait (data-l), a dot on an equipment /
   a pet; a maxed unit (data-lx) draws nothing — a maxed army stays calm (its tooltip and the line still say it). A hero = its
   portrait then its 2 × 2 cluster (2 equipment over the pet). The clan castle = a small shield (its chevron cut out) before the
   donated units. Colours = the "Battle log army" tokens (Player Page → Colours; op2_color_tokens()) and the page's --oc3-*; no raw
   colour in a rule. Radii 2 / 3 / pill / circle. Every rule under #oc3 (every pseudo-element too: clan-v3.css resets #oc3
   *::before / *::after). (Retired: the army sheet — draft A, .op2-ara-* — and drafts D / F, .op2-a2-*.) */
#oc3.op2 { --op2-ar-pill: #ffd23f; --op2-ar-pill-ink: #3a3000; --op2-ar-lv: #2f3542; --op2-ar-lv-ink: #ffffff; --op2-lv-sup: #7c3aed; }
html[data-theme="dark"] #oc3.op2 { --op2-ar-pill: #f0c040; --op2-ar-lv: #e6e6e6; --op2-ar-lv-ink: #0d1117; --op2-lv-sup: #a78bfa; }
#oc3 .op2-ar { --u: 30px; --g: 3px; --m: calc((var(--u) - 2px) / 2); min-width: 0; }
#oc3 .op2-ar ul { margin: 0; padding: 0; list-style: none; }
#oc3 .op2-ar > .op2-bl-xk { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
/* the one row: every group's units flow in it (heroes, troops and siege machines, spells, the clan castle) */
#oc3 .op2-ar-r { display: flex; flex-wrap: wrap; align-items: center; gap: 6px var(--g); min-width: 0; }
#oc3 .op2-ar-r > ul, #oc3 .op2-ar-cc, #oc3 .op2-ar-cc > ul { display: contents; }
#oc3 .op2-ar-r li { position: relative; flex: none; }
#oc3 .op2-ar :is(li, i) > :is(img, .op2-bl-unm) { display: block; width: 100%; height: 100%; box-sizing: border-box; object-fit: contain; border-radius: 3px; }
#oc3 .op2-ar .op2-bl-unm { display: grid; place-items: center; overflow: hidden; padding: 1px; font-style: normal; font-family: var(--oc3-clash); font-size: 9.5px; line-height: 1.05; text-align: center; color: var(--oc3-ink-2); }
#oc3 .op2-ar-u > li { width: var(--u); height: var(--u); border-radius: 3px; background: var(--oc3-lifted); }
/* a hero: its portrait, then its cluster (2 equipment on top, the pet across the bottom) */
#oc3 .op2-ar-h > li { display: flex; gap: 2px; margin-right: 3px; }
#oc3 .op2-ar-h > li > :is(img, .op2-bl-unm) { flex: none; width: var(--u); height: var(--u); background: var(--oc3-lifted); }
#oc3 .op2-ar-h > li > span { display: grid; grid-template-columns: repeat(2, var(--m)); grid-auto-rows: var(--m); gap: 2px; }
#oc3 .op2-ar-h > li > span > i { position: relative; display: block; min-width: 0; font-style: normal; }
#oc3 .op2-ar-h > li > span > i.is-pet { grid-column: 1 / -1; grid-row: 2; }
#oc3 .op2-ar-h > li > span > i > :is(img, .op2-bl-unm) { border-radius: 2px; }
/* a super troop: the game's purple ring (its level = its base troop's) */
#oc3 .op2-ar-u > li.is-sp > :is(img, .op2-bl-unm) { outline: 1.5px solid var(--op2-lv-sup); outline-offset: -1.5px; }
/* the count: a pill bottom-left */
#oc3 .op2-ar-u > li > b { position: absolute; left: 1px; bottom: 1px; z-index: 1; height: 13px; padding: 0 3px; border-radius: 999px; background: var(--op2-ar-pill); color: var(--op2-ar-pill-ink);
  font-family: var(--oc3-data); font-style: normal; font-weight: 800; font-size: 10px; line-height: 13px; font-variant-numeric: tabular-nums; white-space: nowrap; pointer-events: none; }
/* a level ONLY below max: a tag top-right of the tile / the portrait (the hero's <li> starts with it); an equipment's / a pet's: a dot */
#oc3 .op2-ar :is(.op2-ar-u > li, .op2-ar-h > li)[data-l]::after { content: attr(data-l); content: attr(data-l) / ""; position: absolute; top: 1px; right: 1px; z-index: 1; min-width: 12px; height: 12px; padding: 0 2px; box-sizing: border-box; border-radius: 2px;
  background: var(--op2-ar-lv); color: var(--op2-ar-lv-ink); font-family: var(--oc3-data); font-style: normal; font-weight: 800; font-size: 10px; line-height: 12px; text-align: center; font-variant-numeric: tabular-nums; pointer-events: none; }
#oc3 .op2-ar .op2-ar-h > li[data-l]::after { right: calc(100% - var(--u) + 1px); }
#oc3 .op2-ar .op2-ar-h > li > span > i[data-l]::after { content: ""; position: absolute; top: -1px; right: -1px; z-index: 1; width: 6px; height: 6px; border-radius: 50%; background: var(--op2-ar-lv); pointer-events: none; }
/* the clan castle: a small shield (its chevron cut out) before the donated units (its words: the group's label, the hover text) */
#oc3 .op2-ar-ccb { position: relative; flex: none; width: 12px; height: var(--u); margin: 0 1px 0 4px; background: var(--oc3-ink-3);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 12'%3E%3Cpath d='M0 0h6l6 6 6-6h6L12 12z'/%3E%3C/svg%3E") 50% 44% / 7px 4px no-repeat, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 28'%3E%3Cpath d='M12 0l12 4v9c0 7.5-5.4 12.6-12 15C5.4 25.6 0 20.5 0 13V4z'/%3E%3C/svg%3E") center / 12px 14px no-repeat;
  -webkit-mask-composite: xor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 12'%3E%3Cpath d='M0 0h6l6 6 6-6h6L12 12z'/%3E%3C/svg%3E") 50% 44% / 7px 4px no-repeat exclude, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 28'%3E%3Cpath d='M12 0l12 4v9c0 7.5-5.4 12.6-12 15C5.4 25.6 0 20.5 0 13V4z'/%3E%3C/svg%3E") center / 12px 14px no-repeat; }
/* a unit with its level tooltip (player-v2.js makes each picture a button once its battle opens) */
#oc3 .op2-ar [role="button"] { cursor: pointer; -webkit-tap-highlight-color: transparent; }
#oc3.op2 .op2-ar [role="button"]:focus-visible, #oc3.op2 .op2-ar .is-tt { outline: 2px solid var(--oc3-focus); outline-offset: 1px; }
/* the line under the row: "{x} of {n} at max level" (green when every one is), or a defence's loading / "not available" words —
   always one line high (a defence's is empty until its levels are read: nothing moves) */
#oc3 .op2-ar-sum { margin: 7px 0 0; min-height: 1.4em; font-family: var(--oc3-sans); font-weight: 400; font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.4; color: var(--oc3-mute); }
#oc3 .op2-ar-sum b { font-family: var(--oc3-data); font-weight: 700; color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
#oc3 .op2-ar-sum.is-max { color: var(--oc3-green); }
/* a defence: the attacker's levels load when the battle opens (player-v2.js, data-lv on the army: load → in / ok, or fail) — a quiet
   mark where a level can come (the tag's place; a mini's dot; never the clan castle, an event troop), then the tags below max in
   place (data-lv="in": they pop in, motion on only); no layout shift (the marks sit on the pictures); a failed read = no mark + the
   words in the line under the row (or, that line off, one short note .op2-bl-lvn under the army) */
#oc3 .op2-ar[data-lv="load"] :is(.op2-ar-r > .op2-ar-u > li:not(.is-ev), .op2-ar-h > li)::after { content: ""; position: absolute; top: 1px; right: 1px; z-index: 1; width: 12px; height: 12px; border-radius: 2px; background: var(--oc3-line-2); opacity: .6; pointer-events: none; }
#oc3 .op2-ar[data-lv="load"] .op2-ar-h > li::after { right: calc(100% - var(--u) + 1px); }
#oc3 .op2-ar[data-lv="load"] .op2-ar-h > li > span > i::after { content: ""; position: absolute; top: -1px; right: -1px; z-index: 1; width: 6px; height: 6px; border-radius: 50%; background: var(--oc3-line-2); opacity: .6; pointer-events: none; }
@media (prefers-reduced-motion: no-preference) {
  #oc3.op2[data-mo~="on"] .op2-ar[data-lv="load"] :is(.op2-ar-r > .op2-ar-u > li:not(.is-ev), .op2-ar-h > li, .op2-ar-h > li > span > i)::after { animation: op2-lvp 900ms ease-in-out infinite alternate; }
  #oc3 .op2-ar[data-lv="in"] :is(.op2-ar-u > li, .op2-ar-h > li, .op2-ar-h > li > span > i)[data-l]::after { animation: op2-lvin calc(280ms * var(--op2-mk, 1)) var(--op2-mo-out, ease-out) both; animation-delay: var(--lvd, 0ms); }
}
@keyframes op2-lvp { from { opacity: .2; } to { opacity: .5; } }
@keyframes op2-lvin { from { opacity: 0; transform: scale(.5); } }
#oc3 .op2-bl-lvn { margin: 8px 0 0; font-size: calc(11.5px * var(--oc3-ts, 1)); line-height: 1.4; color: var(--oc3-mute); }
/* [army options] (2026-09-29, Félix: "Add options to customize how it works … have 1 tooltip shown the 3") — battlelog-rules.md §V4.
   The level tags (p2_log_ar_lv → the board's data-ar): lv-a = a tag on EVERY unit — a maxed one (data-lx) in a quieter tag (the
   panel's fill, the muted ink, a hairline); equipment and pets keep their dot below max (too small for a number) —; lv-n = none (no
   tag, no dot, no loading mark: the tooltips and the hero card still give every level). No token = below max only (above). */
#oc3 .op2-log[data-ar~="lv-a"] .op2-ar :is(.op2-ar-u > li, .op2-ar-h > li)[data-lx]::after { content: attr(data-lx); content: attr(data-lx) / ""; position: absolute; top: 1px; right: 1px; z-index: 1; min-width: 12px; height: 12px; padding: 0 2px; box-sizing: border-box; border-radius: 2px;
  background: var(--oc3-panel); color: var(--oc3-mute); box-shadow: inset 0 0 0 1px var(--oc3-line-2); font-family: var(--oc3-data); font-style: normal; font-weight: 800; font-size: 10px; line-height: 12px; text-align: center; font-variant-numeric: tabular-nums; pointer-events: none; }
#oc3 .op2-log[data-ar~="lv-a"] .op2-ar .op2-ar-h > li[data-lx]::after { right: calc(100% - var(--u) + 1px); }
@media (prefers-reduced-motion: no-preference) {
  #oc3 .op2-log[data-ar~="lv-a"] .op2-ar[data-lv="in"] :is(.op2-ar-u > li, .op2-ar-h > li)[data-lx]::after { animation: op2-lvin calc(280ms * var(--op2-mk, 1)) var(--op2-mo-out, ease-out) both; animation-delay: var(--lvd, 0ms); }
}
#oc3 .op2-log[data-ar~="lv-n"] .op2-ar .op2-ar-r :is(li, i)::after,
#oc3 .op2-log[data-ar~="lv-n"] .op2-ar[data-lv] .op2-ar-r :is(li, i)::after { content: none; animation: none; }
/* the hero card (p2_log_ar_htip, on for this device): player-v2.js makes each hero — its portrait AND its equipment / pet cluster —
   ONE button (role=button, aria-expanded; its ::before stretches the tap target to 40 px tall on phones, nothing moves) whose card
   is the page's one shared tooltip (.oc3-tt.op2-hc, role=tooltip, aria-describedby): the hero (portrait, name, "Level l / m"), its
   equipment and its pet (picture, name, level / max; a maxed one green with a check mark), the "now" note; a defence: quiet marks
   while the attacker's levels load, then the levels, or the "not available" words. A panel (tokens only, light + dark; radius 10) */
#oc3 .op2-ar .op2-ar-h > li[role="button"] { border-radius: 3px; }
#oc3 .op2-ar .op2-ar-h > li[role="button"]::before { content: ""; position: absolute; left: 0; right: 0; top: min(0px, calc((var(--u) - 40px) / 2)); bottom: min(0px, calc((var(--u) - 40px) / 2)); }
/* (phones, the hero card on there — data-ar hc: an opened battle whose army leads keeps 5 px above it, so the fold's clip never cuts a
   hero's 40 px tap target; the closed row's line is untouched) */
@media (max-width: 767.98px) { #oc3 .op2-log[data-ar~="hc"] .op2-bl-d[open] .op2-bl-xi > .op2-bl-xa:first-child { margin-top: 5px; } }
#oc3 .oc3-tt.op2-hc { width: min(264px, calc(100vw - 16px)); max-width: none; padding: 10px 12px 9px; border: 1px solid var(--oc3-line-2); border-radius: 10px; background: var(--oc3-panel); color: var(--oc3-ink); }
#oc3 .oc3-tt.op2-hc .oc3-tt-ar { border: solid var(--oc3-line-2); border-width: 0 1px 1px 0; }
#oc3 .oc3-tt.op2-hc[data-at="bottom"] .oc3-tt-ar { border-width: 1px 0 0 1px; }
#oc3 .op2-hc-h { display: grid; grid-template-columns: 36px minmax(0, 1fr); align-items: center; gap: 10px; }
#oc3 .op2-hc :is(.op2-hc-h, .op2-hc-l > li) > :is(img, .op2-hc-np) { display: block; width: 100%; height: auto; aspect-ratio: 1; box-sizing: border-box; object-fit: contain; border-radius: 3px; background: var(--oc3-lifted); }
#oc3 .op2-hc-h b { display: block; font-family: var(--oc3-sans); font-weight: 700; font-size: calc(13px * var(--oc3-ts, 1)); line-height: 1.3; overflow-wrap: anywhere; }
#oc3 .op2-hc-v { display: block; min-height: 1.35em; margin-top: 1px; font-family: var(--oc3-data); font-weight: 700; font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.35; color: var(--oc3-ink-2); font-variant-numeric: tabular-nums; }
#oc3 .op2-hc-v.is-max, #oc3 .op2-hc-l > li.is-max > em { color: var(--oc3-green); }
#oc3 .op2-hc-k { margin: 10px 0 4px; font-family: var(--oc3-clash); font-weight: 700; font-size: 10.5px; line-height: 1.3; letter-spacing: .05em; text-transform: uppercase; color: var(--oc3-mute); }
#oc3 .op2-hc-l { display: grid; gap: 4px; margin: 0; padding: 0; list-style: none; }
#oc3 .op2-hc-l > li { display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; align-items: center; gap: 8px; min-height: 24px; font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.3; }
#oc3 .op2-hc-l > li > span { min-width: 0; overflow-wrap: anywhere; }
#oc3 .op2-hc-l > li > em { font-family: var(--oc3-data); font-style: normal; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--oc3-ink-2); }
#oc3 .op2-hc-l > li.is-max > em::after { content: ""; display: inline-block; width: 10px; height: 10px; margin-left: 4px; vertical-align: -1px; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.5l5 5L20 6.5'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.5l5 5L20 6.5'/%3E%3C/svg%3E") center / contain no-repeat; }
#oc3 .op2-hc .op2-hc-ld { display: inline-block; width: 38px; height: 10px; border-radius: 2px; background: var(--oc3-line-2); opacity: .6; vertical-align: middle; }
#oc3 .op2-hc-x { margin: 10px 0 0; font-size: calc(11.5px * var(--oc3-ts, 1)); line-height: 1.4; color: var(--oc3-mute); }
@media (prefers-reduced-motion: no-preference) {
  #oc3.op2[data-mo~="on"] .op2-hc .op2-hc-ld { animation: op2-lvp 900ms ease-in-out infinite alternate; }
}
@media (min-width: 768px) {
  #oc3 .op2-ar { --u: 40px; }
  #oc3 .op2-ar-u > li > b { height: 14px; font-size: 10.5px; line-height: 14px; }
}
/* the closed battle row (p2_log_ar_row → details.has-pv, primary and Timeline; [army options] below): its army as ONE line under the row — the same
   markup, the battle's content shown while closed (::details-content) with all but the army's row hidden: no cluster, no level, no
   line under it (the opened battle has them); the troops and siege machines lead (they tell armies apart), then the spells, the
   heroes (portraits), the clan castle; the units past the line hidden by player-v2.js ([data-pv]) and counted in "+N" (data-pvn);
   JavaScript off: the units that do not fit wrap below the line (clipped) and it fades out at its end. Only where the browser has
   ::details-content (@supports; no :has() needed):
   elsewhere the closed row stays as it was — never a broken line, never a second strip. Opened, the army leads its battle
   (op2_log_x($e, true)): the line grows into the full strip in place. */
@supports selector(::details-content) {
  #oc3 .op2-bl-d.has-pv:not([open])::details-content { content-visibility: visible; }
  #oc3 .op2-bl-d.has-pv:not([open]) .op2-bl-xi > :not(.op2-bl-xa),
  #oc3 .op2-bl-d.has-pv:not([open]) .op2-ar > .op2-ar-sum,
  #oc3 .op2-log:not([data-ar~="pv-g"]) .op2-bl-d.has-pv:not([open]) .op2-ar-h > li > span,
  #oc3 .op2-bl-d.has-pv:not([open]) .op2-ar [data-pv],
  #oc3 .op2-bl-d.has-pv:not([open]) .op2-bl-lvn { display: none; }
  #oc3 .op2-bl-d.has-pv:not([open]) .op2-bl-xi > .op2-bl-xa { margin: 0 0 10px; cursor: pointer; }
  #oc3 .op2-bl-d.has-pv:not([open]) .op2-ar-r { flex-wrap: nowrap; overflow: hidden; }
  #oc3 .op2-bl-d.has-pv:not([open]) .op2-ar-h > li { order: 1; margin-right: 0; }
  #oc3 .op2-bl-d.has-pv:not([open]) :is(.op2-ar-ccb, .op2-ar-cc li) { order: 2; }
  #oc3 .op2-log .op2-bl-d.has-pv:not([open]) .op2-ar .op2-ar-r :is(li, i)::after { content: none; animation: none; }
  #oc3 .op2-bl-d.has-pv:not([open]) .op2-ar-r[data-pvn]::after { content: attr(data-pvn); order: 3; flex: none; height: 20px; padding: 0 7px; border-radius: 999px; background: var(--oc3-lifted); color: var(--oc3-ink-2);
    font-family: var(--oc3-data); font-weight: 700; font-size: 11px; line-height: 20px; font-variant-numeric: tabular-nums; }
  /* (JavaScript off: the units that do not fit wrap onto lines below the one shown — whole units, nothing laid out past the edge —
     and the line fades out at its end) */
  #oc3 .op2-log:not([data-js]) .op2-bl-d.has-pv:not([open]) .op2-ar-r { flex-wrap: wrap; max-height: var(--u); -webkit-mask-image: linear-gradient(90deg, var(--oc3-ink) calc(100% - 28px), transparent); mask-image: linear-gradient(90deg, var(--oc3-ink) calc(100% - 28px), transparent); }
  /* [army options] the board's data-ar: WHERE (p2_log_ar_row — pv-ph = phones & tablets only, pv-dt = desktop only: on the other side
     the closed row is the browser's own again, its content hidden; the opened battle is the same everywhere), WHAT (p2_log_ar_row_what
     — pv-h = the heroes only, pv-u = the troops, siege machines and spells only), the heroes' equipment and pet (pv-g, above; without
     it the portraits only) */
  @media (min-width: 1024px) { #oc3 .op2-log[data-ar~="pv-ph"] .op2-bl-d.has-pv:not([open])::details-content { content-visibility: hidden; } }
  @media (max-width: 1023.98px) { #oc3 .op2-log[data-ar~="pv-dt"] .op2-bl-d.has-pv:not([open])::details-content { content-visibility: hidden; } }
  #oc3 .op2-log[data-ar~="pv-h"] .op2-bl-d.has-pv:not([open]) :is(.op2-ar-r > .op2-ar-u, .op2-ar-cc),
  #oc3 .op2-log[data-ar~="pv-u"] .op2-bl-d.has-pv:not([open]) :is(.op2-ar-h, .op2-ar-cc) { display: none; }
}
.op2-bl-xc { margin: 0; }
.op2-bl-copy { gap: 6px; }
.op2-bl-cpi { width: 14px; height: 14px; object-fit: contain; flex: none; }
.op2-bl-cpi.is-drawn { display: inline-block; background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2'%3E%3Crect x='8' y='8' width='13' height='13' rx='2'/%3E%3Cpath d='M4 16V5a1 1 0 0 1 1-1h11'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2'%3E%3Crect x='8' y='8' width='13' height='13' rx='2'/%3E%3Cpath d='M4 16V5a1 1 0 0 1 1-1h11'/%3E%3C/svg%3E") center / contain no-repeat; }
@media (max-width: 379.98px) {
  .op2-bl-xs { grid-template-columns: 48px minmax(0, 1fr); column-gap: 10px; }
  .op2-bl-xth-i { width: 44px; height: 44px; }
}
/* motion "fb": chips and switches press in; the chip fill changes in a feedback beat */
#oc3.op2[data-mo~="fb"] .op2-blf-c { transition: background-color var(--op2-mo-fb) linear, color var(--op2-mo-fb) linear; }
#oc3.op2[data-mo~="fb"] :is(.op2-blf-c, .op2-blo-b, .op2-blseg-b) > * { transition: transform calc(110ms * var(--op2-mk, 1)) var(--op2-mo-out); }
#oc3.op2[data-mo~="fb"] :is(.op2-blf-c, .op2-blo-b, .op2-blseg-b):active > * { transform: scale(.9); }
/* a battle leaving the list while the others glide (player-v2.js lays a copy over its old place for its fade) */
#oc3.op2 .op2-bl-ghost { position: absolute; left: 0; right: 0; margin: 0; pointer-events: none; z-index: 1; background: var(--oc3-card); }
/* paper: the list as it stands, without the controls; day headers flow */
@media print { #oc3.op2 .op2-blc, #oc3.op2 .op2-bl-ghost { display: none !important; } .op2-log.is-pin .op2-bls > .op2-bld { position: static; } }
/* ── [/log life builder] ── */
/* ── [log prover] (2026-09-27) JavaScript off: "Show all" needs the page script — without it (the section never marked [data-js]) the
   button is not drawn and every row of the board shows, so the list, the heading and both panels read the same rows
   (battlelog-rules.md §X8). With the script nothing changes here. ── */
.op2-log:not([data-js]) .oc3-more { display: none !important; }
.op2-log:not([data-js]) .op2-bls > li[data-more-of][hidden], .op2-log:not([data-js]) .op2-bls > li.is-dk, .op2-log:not([data-js]) .op2-bls > li.is-ph { display: block !important; }
/* print: the page script opens the list before printing (every passing row); the button itself is not printed */
@media print { .op2-log .oc3-more { display: none !important; } }
/* the day before a row's time is hidden for today's rows (the script re-decides by the visitor's clock) */
#oc3.op2 .op2-log .op2-bl-dd[hidden] { display: none; }
/* ── [/log prover] ── */

/* ── [log draft: table] (2026-09-27) · Battle log, the "Analyst table" draft layout (p2_log_layout = table): op2_sec_log_table()
   and the page script's [log draft: table] module. The primary's rules above still dress what it shares with this layout (the
   switches and chips, the day headers, the opened battle, "Show all", the emptied list); this block adds the KPI tiles + trend
   per side and the table, which is a table from 520px of board width (a sticky column header, one grid of named columns — each
   cell finds its column whatever is switched off) and a stack of cards under that (phones). Colours: tokens only. ── */
.op2-log--t .op2-blsum { display: none; }

/* KPI tiles: one region per side on the panel layer (a tint, no border, no shadow: a region of the board, not a card in the card),
   side by side from 480px of board width, stacked under that */
.op2-bltk { container: op2bltk / inline-size; margin: 0 0 12px; }
.op2-bltk-g { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }
@container op2bltk (min-width: 480px) { .op2-bltk.is-two:not(.is-one) .op2-bltk-g { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.op2-bltk-p { min-width: 0; padding: 10px 12px 11px; background: var(--oc3-raised); }
.op2-bltk-p[hidden] { display: none; }
.op2-bltk-h { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 7px; margin: 0 0 9px; font-family: var(--oc3-clash); font-weight: 700; font-size: 11px; line-height: 1.2; letter-spacing: .07em; text-transform: uppercase; color: var(--oc3-ink-2); }
.op2-bltk-hi { width: 18px; height: 18px; object-fit: contain; flex: none; }
.op2-bltk-un { margin-left: auto; font-family: var(--oc3-sans); font-weight: 500; font-size: calc(11px * var(--oc3-ts, 1)); letter-spacing: 0; text-transform: none; color: var(--oc3-mute); }
.op2-bltk-un[hidden] { display: none; }
#oc3.op2 .op2-bltk-t { display: grid; grid-template-columns: repeat(auto-fill, minmax(82px, 1fr)); gap: 11px 12px; margin: 0; padding: 0; list-style: none; }
.op2-bltk-c { display: grid; align-content: start; gap: 1px; min-width: 0; }
.op2-bltk-c[hidden] { display: none; }
.op2-bltk-c[data-kc="lt"] { grid-column: span 2; }
.op2-bltk-c[data-tt-l] { cursor: help; }
.op2-bltk-c:focus-visible, .op2-bltk-nl:focus-visible { outline: 2px solid var(--oc3-focus); outline-offset: 2px; }
.op2-bltk-v { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 4px; min-width: 0; }
.op2-bltk-i { width: 16px; height: 16px; object-fit: contain; flex: none; }
#oc3.op2 .op2-bltk-v b { font-family: var(--oc3-clash); font-weight: 700; font-size: 17px; line-height: 1.15; letter-spacing: .02em; color: var(--oc3-ink); white-space: nowrap; font-variant-numeric: tabular-nums; }
.op2-bltk-l { font-size: calc(11.5px * var(--oc3-ts, 1)); line-height: 1.25; color: var(--oc3-mute); }
.op2-bltk-s { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 5px; font-size: calc(11px * var(--oc3-ts, 1)); line-height: 1.3; color: var(--oc3-mute); }
.op2-bltk-s[hidden] { display: none; }
#oc3.op2 .op2-bltk-s b { font-family: var(--oc3-data); font-size: calc(11.5px * var(--oc3-ts, 1)); font-weight: 700; color: var(--oc3-ink-2); font-variant-numeric: tabular-nums; }
.op2-bltk-si { width: 13px; height: 13px; object-fit: contain; flex: none; }
.op2-bltk-wl b + .op2-bltk-si, .op2-bltk-wl b + picture { margin-left: 5px; }
#oc3.op2 .op2-bltk .op2-bl-apx { font-size: 15px; }
/* loot: three figures (15px: they share one tile) */
.op2-bltk-r { display: inline-flex; align-items: center; gap: 3px; margin-right: 9px; white-space: nowrap; }
.op2-bltk-r:last-child { margin-right: 0; }
.op2-bltk-r .op2-bltk-i { width: 15px; height: 15px; }
#oc3.op2 .op2-bltk-lv b { font-size: 15px; }
/* the Defences loot: figures lost on multiplayer defences (mp), "No loot lost (Ranked)" when only Ranked defences are shown (rk),
   a dash when neither is (none) — the primary's three states */
.op2-bltk-c[data-lk]:not([data-lk="mp"]) :is(.op2-bltk-lv, .op2-bltk-ls), .op2-bltk-c[data-lk]:not([data-lk="rk"]) .op2-bltk-nl,
.op2-bltk-c[data-lk]:not([data-lk="none"]) .op2-bltk-nn, .op2-bltk-c[data-lk="rk"] .op2-bltk-l { display: none; }
#oc3.op2 .op2-bltk-nl b { font-size: 13px; color: var(--oc3-ink-2); white-space: normal; }
#oc3.op2 .op2-bltk-nn b { color: var(--oc3-ink-3); }
#oc3.op2 .op2-bltk-p[data-z] :is(.op2-bltk-t, .op2-bltt), .op2-bltk-p:not([data-z]) .op2-bltk-z { display: none; }
.op2-bltk-z { margin: 0; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
@container op2bltk (max-width: 339.98px) {
  #oc3.op2 .op2-bltk-t { grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); column-gap: 10px; }
  #oc3.op2 .op2-bltk-v b { font-size: 15.5px; }
  #oc3.op2 .op2-bltk-lv b { font-size: 14px; }
  .op2-bltk-r { margin-right: 7px; }
}

/* the trend: two strips (each battle's stars, then its destruction — never two scales on one), oldest → newest, the first and
   the last day under them; a pointer or the arrow keys read one battle (the readout takes the days' line) */
.op2-bltt { position: relative; margin-top: 11px; padding-top: 9px; border-top: 1px solid var(--oc3-line); outline: none; }
.op2-bltt[data-tz] { display: none; }
.op2-bltt:focus-visible { box-shadow: 0 0 0 2px var(--oc3-focus); }
.op2-bltt-h { margin: 0 0 5px; font-family: var(--oc3-clash); font-weight: 700; font-size: 9.5px; line-height: 1.2; letter-spacing: .07em; text-transform: uppercase; color: var(--oc3-ink-3); }
.op2-bltt-s { display: grid; grid-template-columns: 14px minmax(0, 1fr); column-gap: 7px; align-items: end; }
.op2-bltt-s + .op2-bltt-s { margin-top: 6px; }
.op2-bltt-i { width: 14px; height: 14px; object-fit: contain; align-self: center; }
.op2-bltt-p { position: relative; height: 22px; touch-action: pan-y; }
.op2-bltt-s[data-ts="pct"] .op2-bltt-p { height: 28px; }
.op2-bltt-g { display: block; width: 100%; height: 100%; overflow: visible; }
.op2-bltt-g rect.is-s { fill: var(--oc3-chart); }
.op2-bltt-g rect.is-0 { fill: var(--oc3-bar); }
.op2-bltt-g rect.is-pt { fill: var(--oc3-ink); }
.op2-bltt-a { fill: var(--op2-bar); opacity: .16; }
.op2-bltt-l { fill: none; stroke: var(--op2-bar); stroke-width: 2px; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
/* the average: a dashed guide in the strip's own colour (never mistaken for a 0-star stub) */
.op2-bltt-avg { fill: none; stroke: var(--oc3-ink-3); stroke-width: 1.25px; stroke-dasharray: 4 3; vector-effect: non-scaling-stroke; }
.op2-bltt-s[data-ts="st"] .op2-bltt-avg { stroke: var(--oc3-chart); }
.op2-bltt-s[data-ts="pct"] .op2-bltt-avg { stroke: var(--op2-bar); opacity: .75; }
.op2-bltt-x, .op2-bltt-r { margin: 4px 0 0 21px; font-size: calc(10.5px * var(--oc3-ts, 1)); line-height: 1.3; color: var(--oc3-mute); font-variant-numeric: tabular-nums; }
.op2-bltt-x { display: flex; justify-content: space-between; gap: 8px; }
.op2-bltt-r { display: none; font-family: var(--oc3-data); font-weight: 600; color: var(--oc3-ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op2-bltt[data-pt] .op2-bltt-x { display: none; }
.op2-bltt[data-pt] .op2-bltt-r { display: block; }
/* the battle read: a hairline through both strips and a dot on the line (a ring of the panel's colour around it) */
.op2-bltt-mk { position: absolute; top: -2px; bottom: -2px; width: 0; border-left: 1px solid var(--oc3-ink-3); pointer-events: none; }
.op2-bltt-dot { position: absolute; width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%; background: var(--op2-bar); box-shadow: 0 0 0 2px var(--oc3-raised); pointer-events: none; }

/* ── the list: stacked cards (default — phones, a board under 520px) ── */
.op2-blt { --op2-blt-hh: 31px; container: op2blt / inline-size; position: relative; }
.op2-blt-hd { display: none; }
#oc3.op2 .op2-log--t .op2-blt-g { grid-template-columns: 20px 28px minmax(0, 1fr) auto 12px; grid-template-areas: "sd th nm st cv" "sd th mt pc cv" ". . dv dv dv"; column-gap: 9px; row-gap: 2px; padding: 9px 2px; }
#oc3.op2 .op2-log--t .op2-blt.no-th .op2-blt-g { grid-template-columns: 20px minmax(0, 1fr) auto 12px; grid-template-areas: "sd nm st cv" "sd mt pc cv" ". dv dv dv"; }
#oc3.op2 .op2-log--t .op2-blt.no-sd .op2-blt-g { grid-template-columns: 28px minmax(0, 1fr) auto 12px; grid-template-areas: "th nm st cv" "th mt pc cv" ". dv dv dv"; }
#oc3.op2 .op2-log--t .op2-blt.no-sd.no-th .op2-blt-g { grid-template-columns: minmax(0, 1fr) auto 12px; grid-template-areas: "nm st cv" "mt pc cv" "dv dv dv"; }
.op2-blt-g > .c-side { grid-area: sd; width: 20px; height: 20px; object-fit: contain; }
.op2-blt-g > .c-opp { display: contents; }
.op2-blt-th { grid-area: th; width: 28px; height: 28px; object-fit: contain; }
.op2-blt-g .c-opp > b { grid-area: nm; min-width: 0; font-family: var(--oc3-clash); font-weight: 700; font-size: 13px; letter-spacing: .02em; color: var(--oc3-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op2-blt-g .c-opp > b.is-anon { color: var(--oc3-ink-3); }
/* the type · time line: wraps between its parts, never inside one; the "·" of a part that begins a line falls in the clipped margin */
.op2-blt-m { grid-area: mt; display: flex; flex-wrap: wrap; align-items: center; min-width: 0; margin-left: -12px; clip-path: inset(-3px -3px -3px 12px); font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.4; color: var(--oc3-mute); }
.op2-blt-m > .op2-blt-c { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
#oc3 .op2-blt-m > .op2-blt-c::before { content: "·"; display: inline-block; width: 12px; text-align: center; color: var(--oc3-ink-3); }
.op2-blt-mi { width: 14px; height: 14px; object-fit: contain; flex: none; }
.op2-blt-g .op2-bl-dd { margin-right: 0; }   /* [drafts check] its text ends with a space (= the primary row's day; the script relabels it) */
.op2-blt-g > .c-st { grid-area: st; justify-self: end; display: inline-flex; gap: 1px; }
.op2-blt-g > .c-st .op2-st, .op2-blt-g > .c-st picture { width: 14px; height: 14px; }
.op2-blt-g > .c-pct { grid-area: pc; justify-self: end; }
.op2-blt-g > .c-un { grid-area: st-start / st-start / pc-end / pc-end; justify-self: end; align-self: center; font-family: var(--oc3-clash); font-weight: 700; font-size: 9.5px; letter-spacing: .07em; text-transform: uppercase; color: var(--oc3-ink-3); white-space: nowrap; }
.op2-blt-g > .op2-bl-cv { grid-area: cv; }
.op2-blt-r.is-un .c-side { opacity: .6; }
/* the figures: tabular, the page's data face; a loss in the loss colour */
.op2-blt-g :is(.c-pct, .c-tr, .c-g, .c-e, .c-d) { font-family: var(--oc3-data); font-weight: 600; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.op2-blt-g .is-neg { color: var(--op2-bl-neg); }
.op2-blt-g :is(.is-0, .is-nil) { color: var(--oc3-ink-3); font-weight: 500; }
/* the data line of a card: labelled cells (their icons), the ones that say nothing left out */
.op2-blt-v { grid-area: dv; display: none; flex-wrap: wrap; align-items: center; gap: 3px 12px; margin-top: 4px; min-width: 0; }
.op2-blt.has-cd .op2-blt-v { display: flex; }
.op2-blt-v > .op2-blt-c { display: inline-flex; align-items: center; gap: 3px; }
.op2-blt-v > .is-nil { display: none; }
.op2-blt-di { width: 13px; height: 13px; object-fit: contain; flex: none; }
.op2-blt-g .c-nl { font-size: calc(11.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); white-space: nowrap; }
@container op2blt (max-width: 359.98px) {
  #oc3.op2 .op2-log--t .op2-blt-g { column-gap: 7px; grid-template-columns: 18px 24px minmax(0, 1fr) auto 10px; }
  #oc3.op2 .op2-log--t .op2-blt.no-th .op2-blt-g { grid-template-columns: 18px minmax(0, 1fr) auto 10px; }
  #oc3.op2 .op2-log--t .op2-blt.no-sd .op2-blt-g { grid-template-columns: 24px minmax(0, 1fr) auto 10px; }
  .op2-blt-th { width: 24px; height: 24px; }
  .op2-blt-g > .c-side { width: 18px; height: 18px; }
  .op2-blt-v { column-gap: 10px; }
}

/* ── the table (a board 520px and wider): the column header, then every row on the same named columns ── */
@container op2blt (min-width: 520px) {
  .op2-blt-hd { display: grid; grid-template-columns: var(--op2-blt-cd); column-gap: 6px; align-items: end; min-height: var(--op2-blt-hh); padding: 0 2px; border-bottom: 1px solid var(--oc3-line-2); box-sizing: border-box; }
  /* (three .op2-blt: this beats the card templates of .no-sd / .no-th) */
  #oc3.op2 .op2-log--t .op2-blt.op2-blt.op2-blt .op2-blt-g { grid-template-columns: var(--op2-blt-cd); grid-template-areas: none; column-gap: 6px; row-gap: 0; min-height: 42px; padding: 6px 2px; }
  /* (id weight: every cell on the one row, whatever area the cards gave it) */
  #oc3.op2 .op2-blt-g > *, #oc3.op2 .op2-blt-g .op2-blt-m > *, #oc3.op2 .op2-blt-g .op2-blt-v > * { grid-row: 1; }
  .op2-blt-g > .c-side { grid-column: side; width: 16px; height: 16px; }
  .op2-blt-g > .c-opp { grid-column: opp; display: flex; align-items: center; gap: 7px; min-width: 0; }
  .op2-blt-th { width: 22px; height: 22px; flex: none; }
  .op2-blt-g .c-opp > b { font-size: 12.5px; }
  .op2-blt-g :is(.c-pct, .c-tr, .c-g, .c-e, .c-d), .op2-blt-m > .c-time { font-size: calc(12px * var(--oc3-ts, 1)); }
  .op2-blt-g > .c-st .op2-st, .op2-blt-g > .c-st picture { width: 13px; height: 13px; }
  .op2-blt-g .op2-blt-m, .op2-blt-g .op2-blt-v, .op2-blt.has-cd .op2-blt-g .op2-blt-v { display: contents; }
  .op2-blt-m > .c-type { grid-column: type; min-width: 0; overflow: hidden; }
  .op2-blt-m > .c-time { grid-column: time; display: grid; justify-items: start; line-height: 1.2; font-family: var(--oc3-data); font-weight: 600; font-size: calc(12.5px * var(--oc3-ts, 1)); color: var(--oc3-ink-2); font-variant-numeric: tabular-nums; }
  #oc3 .op2-blt-m > .op2-blt-c::before { content: none; }
  .op2-blt-g .op2-blt-m { clip-path: none; }
  .op2-blt-g .op2-bl-dd { margin: 0; font-weight: 500; font-size: calc(10.5px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
  .op2-blt-tw { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .op2-blt-tw.is-only { position: static; width: auto; height: auto; clip: auto; overflow: hidden; text-overflow: ellipsis; font-size: calc(11px * var(--oc3-ts, 1)); color: var(--oc3-mute); }
  .op2-blt-g > .c-st { grid-column: st; }
  .op2-blt-g > .c-pct { grid-column: pct; }
  .op2-blt-v > .c-tr { grid-column: tr; justify-self: end; }
  .op2-blt-v > .c-g { grid-column: g; justify-self: end; }
  .op2-blt-v > .c-e { grid-column: e; justify-self: end; }
  .op2-blt-v > .c-d { grid-column: d; justify-self: end; }
  .op2-blt-v > .is-nil { display: inline; }
  /* (over one or two loot columns the words wrap, right-aligned, never over the trophies) */
  .op2-blt-v > .c-nl { grid-column: var(--op2-blt-lf) / cv; justify-self: end; min-width: 0; white-space: normal; text-align: right; line-height: 1.15; font-size: calc(11px * var(--oc3-ts, 1)); }
  .op2-blt-g > .c-un { grid-column: var(--op2-blt-rf) / cv; justify-self: start; }
  .op2-blt-g > .op2-bl-cv { grid-column: cv; }
  /* in the table the column header names a cell: its icon is read, not drawn */
  .op2-blt-v .op2-blt-di, .op2-blt-v picture.op2-blt-di { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  /* the header: a button per column (the icon, else the word), the sorted one in ink with its arrow */
  .op2-blt.is-stick .op2-blt-hd { position: sticky; top: var(--op2-stick); z-index: 3; background: var(--oc3-card); }
  #oc3.op2:has(.op2-jwrap.is-fixed) .op2-blt.is-stick .op2-blt-hd { top: calc(var(--op2-stick) + 40px + 2 * var(--op2-jpy)); }
  #oc3.op2 .op2-log.is-pin .op2-blt.is-stick .op2-bls > .op2-bld { top: calc(var(--op2-stick) + var(--op2-blt-hh)); }
  #oc3.op2:has(.op2-jwrap.is-fixed) .op2-log.is-pin .op2-blt.is-stick .op2-bls > .op2-bld { top: calc(var(--op2-stick) + 40px + 2 * var(--op2-jpy) + var(--op2-blt-hh)); }
  .op2-blt .op2-bls > .op2-bld:first-child { padding-top: 8px; }
  .op2-blt-hb:is(.c-side, .c-type) .op2-blt-hw { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
}
/* the sort switch (time · stars · destruction) gives way to the column header where the table is drawn (the controls' own
   container = the board's width) */
@container (min-width: 520px) { .op2-log--t .op2-blc:has(~ .op2-blt) .op2-blo { display: none; } }
.op2-blt-hb { position: relative; display: flex; align-items: center; gap: 3px; min-width: 0; min-height: 30px; padding: 0; margin: 0; border: 0; border-radius: 0; background: none; color: var(--oc3-ink-3);
  font-family: var(--oc3-clash); font-weight: 700; font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase; line-height: 1; white-space: nowrap; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.op2-blt-hb.is-num { flex-direction: row-reverse; justify-content: flex-start; }
.op2-blt-hb:hover, .op2-blt-hb.is-on { color: var(--oc3-ink); }
.op2-blt-hb:focus-visible { outline: 2px solid var(--oc3-focus); outline-offset: -2px; }
.op2-blt-hw { overflow: hidden; text-overflow: ellipsis; }
.op2-blt-hi { width: 15px; height: 15px; object-fit: contain; flex: none; opacity: .85; }
.op2-blt-hb.is-on .op2-blt-hi, .op2-blt-hb:hover .op2-blt-hi { opacity: 1; }
.op2-blt-ar { flex: none; opacity: 0; }
.op2-blt-hb.is-on .op2-blt-ar { opacity: 1; }
.op2-blt-hb[data-up] .op2-blt-ar { transform: rotate(180deg); }
.op2-log:not([data-js]) .op2-blt-hb, .op2-blt-hb.is-static { cursor: default; pointer-events: none; }
.op2-log:not([data-js]) .op2-blt-ar { display: none; }
/* a wide board: the type column carries its word, the drawer lays its parts in two columns (the result and the loot, the army) */
@container op2blt (min-width: 720px) {
  .op2-blt-hd, #oc3.op2 .op2-log--t .op2-blt.op2-blt.op2-blt .op2-blt-g { grid-template-columns: var(--op2-blt-cw); column-gap: 10px; }
  .op2-blt-th { width: 24px; height: 24px; }
  .op2-blt-g > .c-side { width: 20px; height: 20px; }
  .op2-blt-g .c-opp > b { font-size: 13px; }
  .op2-blt-g :is(.c-pct, .c-tr, .c-g, .c-e, .c-d), .op2-blt-m > .c-time { font-size: calc(12.5px * var(--oc3-ts, 1)); }
  .op2-blt-g > .c-st .op2-st, .op2-blt-g > .c-st picture { width: 14px; height: 14px; }
  .op2-blt.has-tw .op2-blt-m > .c-type { display: inline-flex; align-items: center; gap: 5px; }
  .op2-blt.has-tw .op2-blt-hb.c-type .op2-blt-hw { position: static; width: auto; height: auto; clip: auto; }
  .op2-blt.has-tw .op2-blt-tw { position: static; width: auto; height: auto; clip: auto; overflow: hidden; text-overflow: ellipsis; font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-ink-2); }
  .op2-blt .op2-bl-xi { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr); column-gap: 24px; row-gap: 12px; align-items: start; padding-bottom: 12px; }
  .op2-blt .op2-bl-xi > * + *, .op2-blt .op2-bl-xi > :first-child, .op2-blt .op2-bl-xi > :last-child { margin: 0; }
  .op2-blt .op2-bl-xi > :is(.op2-bl-xs, .op2-bl-xl) { grid-column: 1; }
  .op2-blt .op2-bl-xi > :is(.op2-bl-xa, .op2-bl-xc) { grid-column: 2; }
  .op2-blt .op2-bl-xi > .op2-bl-xa { grid-row: 1 / span 2; }
}
/* motion "fb": the sort arrow turns, a header press settles (reduced motion: none — the page's own rule) */
#oc3.op2[data-mo~="fb"] .op2-log--t .op2-blt-ar { transition: transform var(--op2-mo-st) var(--op2-mo-out), opacity var(--op2-mo-fb) linear; }
#oc3.op2[data-mo~="fb"] .op2-log--t .op2-blt-hb > * { transition: transform calc(110ms * var(--op2-mk, 1)) var(--op2-mo-out); }
#oc3.op2[data-mo~="fb"] .op2-log--t .op2-blt-hb:active > * { transform: translateY(1px); }
/* paper: the header flows, the trend whole */
@media print { #oc3.op2 .op2-blt.is-stick .op2-blt-hd { position: static; } #oc3.op2 .op2-bltt-r, #oc3.op2 .op2-bltt-mk, #oc3.op2 .op2-bltt-dot { display: none !important; } }
/* ── [/log draft: table] ── */

/* ── [log draft: feed] → [log timeline] (2026-09-28) Battle log · Timeline — p2_log_layout = feed (op2_sec_log_feed() / player-v2.js
   "[log draft: feed]"): the head-to-head scoreboard (this part) over the primary's rows on a rail ("[log timeline] rows" below).
   Everything here is scoped to .op2-lfd / .op2-tl (this layout only). ── */
#oc3.op2 { --op2-lfd-a: #b8740b; --op2-lfd-d: #3764a6; }
html[data-theme="dark"] #oc3.op2 { --op2-lfd-a: #f0c040; --op2-lfd-d: #82aef0; }
/* (the primary's two panels never show here — the scoreboard stands for them) */
.op2-lfd .op2-blsum { display: none !important; }

/* the scoreboard: a figure per row — Attacks' figure at the left edge, its bar growing left out of the middle, the figure's icon
   and words in the middle, the Defences' bar growing right, their figure at the right edge. Between two hairlines, like the
   primary's panels (no card in the card) */
.op2-lfs { container: lfs / inline-size; margin: 0 0 10px; padding: 9px 0 8px; border-block: 1px solid var(--oc3-line); }
.op2-lfs-t { --lfs-v: 58px; --lfs-k: 66px; display: grid; gap: 5px; }
.op2-lfs-rg, .op2-lfs-lg { display: grid; gap: 5px; }
.op2-lfs-hd, .op2-lfs-m { display: grid; grid-template-columns: var(--lfs-v) minmax(0, 1fr) var(--lfs-k) minmax(0, 1fr) var(--lfs-v); grid-template-areas: "va ba k bd vd"; align-items: center; column-gap: 8px; }
.op2-lfs-m[hidden], .op2-lfs-lg[hidden], .op2-lfs-n[hidden] { display: none; }
.op2-lfs-hd { grid-template-areas: "ha ha k hd hd"; margin-bottom: 3px; }
.op2-lfs-h { display: flex; align-items: center; gap: 6px; min-width: 0; font-family: var(--oc3-clash); font-weight: 700; font-size: 11px; line-height: 1.2; letter-spacing: .07em; text-transform: uppercase; color: var(--oc3-ink-2); white-space: nowrap; }
.op2-lfs-h.is-a { grid-area: ha; }
.op2-lfs-h.is-d { grid-area: hd; justify-content: flex-end; }
.op2-lfs-hi { width: 20px; height: 20px; object-fit: contain; flex: none; }
#oc3.op2 .op2-lfs-h b { font-family: var(--oc3-data); font-size: 15px; letter-spacing: 0; color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-lfs-k { grid-area: k; display: grid; justify-items: center; min-width: 0; }
.op2-lfs-kk { display: grid; justify-items: center; gap: 1px; padding: 1px 2px; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.op2-lfs-kk:focus-visible { outline: 2px solid var(--oc3-focus); outline-offset: 1px; }
.op2-lfs-ki { width: 16px; height: 16px; object-fit: contain; }
.op2-lfs-k small { font-family: var(--oc3-clash); font-weight: 700; font-size: 9px; line-height: 1.15; letter-spacing: .06em; text-transform: uppercase; color: var(--oc3-ink-3); white-space: nowrap; }
.op2-lfs-v { display: flex; align-items: center; gap: 1px; min-width: 0; white-space: nowrap; }
.op2-lfs-v.is-a { grid-area: va; justify-content: flex-start; }
.op2-lfs-v.is-d { grid-area: vd; justify-content: flex-end; }
#oc3.op2 .op2-lfs-v b { font-family: var(--oc3-data); font-weight: 700; font-size: calc(13.5px * var(--oc3-ts, 1)); line-height: 1.2; color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
#oc3.op2 .op2-lfs-v .op2-bl-apx { font-size: 13px; }
#oc3.op2 .op2-lfs-v.is-neg b { color: var(--op2-bl-neg); }
/* a side with no battle in view: its figures read "–", quieter */
#oc3.op2 .op2-lfs.is-za :is(.op2-lfs-v.is-a b, .op2-lfs-h.is-a b), #oc3.op2 .op2-lfs.is-zd :is(.op2-lfs-v.is-d b, .op2-lfs-h.is-d b) { color: var(--oc3-ink-3); }
.op2-lfs.is-za .op2-lfs-h.is-a .op2-lfs-hi, .op2-lfs.is-zd .op2-lfs-h.is-d .op2-lfs-hi { opacity: .5; }
/* the bars: a well each, the fill scaled out of the middle (a transform: it slides on the compositor) */
.op2-lfs-b { position: relative; height: 8px; overflow: hidden; background: var(--oc3-well); }
.op2-lfs-b.is-a { grid-area: ba; }
.op2-lfs-b.is-d { grid-area: bd; }
.op2-lfs-b > i { position: absolute; inset: 0; transform: scaleX(var(--w, 0)); }
.op2-lfs-b.is-a > i { transform-origin: 100% 50%; background: var(--op2-lfd-a); }
.op2-lfs-b.is-d > i { transform-origin: 0 50%; background: var(--op2-lfd-d); }
.op2-lfs.no-bars .op2-lfs-b { visibility: hidden; }
/* the loot's heading row: "taken · LOOT · lost" */
.op2-lfs-lh { margin-top: 3px; }
.op2-lfs-lh .op2-lfs-v { font-family: var(--oc3-clash); font-weight: 700; font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--oc3-ink-3); }
.op2-lfs-lh .op2-lfs-k small { color: var(--oc3-ink-2); }
/* the small lines: attacks' at the left, defences' at the right */
.op2-lfs-ns { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 3px 14px; margin-top: 7px; }
.op2-lfs-n { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 6px; margin: 0; font-size: calc(11px * var(--oc3-ts, 1)); line-height: 1.35; color: var(--oc3-mute); }
.op2-lfs-n.is-d { margin-left: auto; justify-content: flex-end; text-align: right; }
.op2-lfs-n .op2-bsp-r { margin-right: 2px; gap: 2px; }
.op2-lfs-n .op2-bsp-i { width: 12px; height: 12px; }
#oc3.op2 .op2-lfs-n b[data-sv] { font-family: var(--oc3-data); font-size: calc(11.5px * var(--oc3-ts, 1)); font-weight: 700; color: var(--oc3-ink-2); font-variant-numeric: tabular-nums; }
.op2-lfs-n[data-lk="none"], .op2-lfs-n:not([data-lk="mp"]) .op2-lfs-nl, .op2-lfs-n:not([data-lk="rk"]) .op2-lfs-nr { display: none; }
.op2-lfs-nr { font-family: var(--oc3-clash); font-weight: 700; font-size: 11px; letter-spacing: .02em; color: var(--oc3-ink-2); cursor: pointer; }
/* a one-side board: its side only — the figure's name, the bar, the figure */
.op2-lfs.is-one :is(.op2-lfs-hd, .op2-lfs-m) { grid-template-columns: var(--lfs-k) minmax(0, 1fr) var(--lfs-v); }
.op2-lfs.is-one .op2-lfs-hd { grid-template-areas: "ha ha ha"; }
.op2-lfs[data-one="a"] .op2-lfs-m { grid-template-areas: "k ba va"; }
.op2-lfs[data-one="d"] .op2-lfs-m { grid-template-areas: "k bd vd"; }
.op2-lfs[data-one="d"] .op2-lfs-h.is-d { grid-area: ha; justify-content: flex-end; flex-direction: row-reverse; }
.op2-lfs[data-one="a"] :is(.op2-lfs-h, .op2-lfs-v, .op2-lfs-b).is-d, .op2-lfs[data-one="d"] :is(.op2-lfs-h, .op2-lfs-v, .op2-lfs-b).is-a, .op2-lfs[data-one="a"] .op2-lfs-n.is-d, .op2-lfs[data-one="d"] .op2-lfs-n.is-a { display: none; }
.op2-lfs.is-one .op2-lfs-v { justify-content: flex-end; }
.op2-lfs.is-one .op2-lfs-b > i { transform-origin: 0 50%; }
/* (one side: a trophy or loot bar would only be measured against itself — left out; won, stars and destruction keep their scale) */
.op2-lfs.is-one :is(.op2-lfs-m[data-m="tr"], .op2-lfs-lg) .op2-lfs-b { visibility: hidden; }
@container lfs (max-width: 359.98px) {
  .op2-lfs-t { --lfs-v: 50px; --lfs-k: 58px; }
  .op2-lfs-hd, .op2-lfs-m { column-gap: 6px; }
  #oc3.op2 .op2-lfs-v b { font-size: 12.5px; }
  .op2-lfs-h { gap: 5px; letter-spacing: .05em; }
}

/* ── [log timeline] (2026-09-28, Félix: "the timeline should look more like the league's section timeline (also visible on mobile)")
   The primary's rows on a rail, in the League Journey's language (.op2-jr-*): one column on every screen; a 30px rail on the left,
   each battle a node on it (its swords / shield in a ring of its colour — Colours → Battle log timeline; a Ranked / Legend battle
   its own ring + the Ranked mark, .has-rk), the rail's stretch beside a battle coloured by its result (.has-seg: won = the
   Journey's step-up colour, lost = its kept colour, an unopposed defence dashed), a day header a station on the rail. The row is
   the <summary> (the whole battle opens under its line, indented past the rail). The first / last item shown ends the rail
   (data-lead: op2_sec_log() + player-v2.js; data-tail: player-v2.js; without the script the list's last item). ── */
#oc3.op2 { --op2-tl-a: #c2410c; --op2-tl-d: #3764a6; --op2-tl-r: #8a6d00; }
html[data-theme="dark"] #oc3.op2 { --op2-tl-a: #fb923c; --op2-tl-d: #82aef0; --op2-tl-r: #f0c040; }
.op2-tl .op2-bls { --tl-rail: 30px; --tl-node: 26px; --tl-ny: 12px; }
.op2-tl .op2-bls > li { border-top: 0; }
.op2-tl .op2-bls > li.op2-bl, .op2-tl:not(.is-pin) .op2-bls > .op2-bld { position: relative; }
/* the row rule, from past the rail to the edge (the Journey's) — none over the first item shown or right under a day header */
.op2-tl .op2-bls > li.op2-bl { background: linear-gradient(var(--oc3-line), var(--oc3-line)) calc(var(--tl-rail) + 10px) 0 / 100% 1px no-repeat; }
.op2-tl .op2-bls > li.op2-bl[data-lead], .op2-tl .op2-bls > .op2-bld + li.op2-bl { background: none; }
/* the rail: each item draws its own stretch (above its node, below it), so a filter or a sort never leaves a gap or a stray end */
#oc3.op2 .op2-tl .op2-bls > li::before, #oc3.op2 .op2-tl .op2-bls > li::after {
  content: ""; position: absolute; left: calc(var(--tl-rail) / 2 - 1px); width: 2px; border-radius: 999px; background: var(--c, var(--op2-jr-stay)); pointer-events: none;
}
#oc3.op2 .op2-tl .op2-bls > li.op2-bl::before { top: 0; height: calc(var(--tl-ny) + 3px); }
#oc3.op2 .op2-tl .op2-bls > li.op2-bl::after { top: calc(var(--tl-ny) + var(--tl-node) - 3px); bottom: 0; }
.op2-tl.has-seg .op2-bls > li.op2-bl[data-w="1"] { --c: var(--op2-jr-up); }
#oc3.op2 .op2-tl.has-seg .op2-bls > li.op2-bl.is-un::before, #oc3.op2 .op2-tl.has-seg .op2-bls > li.op2-bl.is-un::after { background: repeating-linear-gradient(to bottom, var(--op2-jr-stay) 0 3px, transparent 3px 7px); }
#oc3.op2 .op2-tl .op2-bls > li[data-lead]::before, #oc3.op2 .op2-tl .op2-bls > li.op2-bl[data-tail]::after,
#oc3.op2 .op2-tl:not([data-js]) .op2-bls > li.op2-bl:last-child::after { display: none; }
/* a day header: a station on the rail (a small ring), its words past the rail; pinned (vis_p2_log_days_pin) it keeps the rail */
.op2-tl .op2-bls > .op2-bld, .op2-tl .op2-bls > .op2-bld:first-child { padding: 12px 2px 6px calc(var(--tl-rail) + 10px); text-align: left; background: none; }
.op2-tl.is-pin .op2-bls > .op2-bld { background: var(--oc3-card); }
.op2-tl .op2-bls > .op2-bld > span { display: inline-block; padding: 3px 9px; line-height: 12px; border: 1px solid var(--oc3-line-2); border-radius: 999px; background: var(--oc3-card); color: var(--oc3-ink-2); }
#oc3.op2 .op2-tl .op2-bls > .op2-bld::before { top: 0; bottom: 0; }
#oc3.op2 .op2-tl .op2-bls > .op2-bld[data-lead]::before { display: block; top: 20px; }
#oc3.op2 .op2-tl .op2-bls > .op2-bld::after { top: 15px; left: calc(var(--tl-rail) / 2 - 5px); width: 10px; height: 10px; box-sizing: border-box; border: 2px solid var(--op2-jr-stay); border-radius: 50%; background: var(--oc3-card); }
/* the row: past the rail, the opponent's Town Hall, his name over the small line, the result, the chevron */
.op2-tl .op2-bl-d, .op2-tl .op2-bl-d[open] { margin: 0; padding: 0; background: none; }
.op2-tl .op2-bl-g { box-sizing: border-box; min-height: 50px; padding: 8px 2px 8px calc(var(--tl-rail) + 10px); column-gap: 10px; grid-template-columns: 28px minmax(0, 1fr) auto; }
.op2-tl .op2-bl.is-x .op2-bl-g { grid-template-columns: 28px minmax(0, 1fr) auto 14px; }
.op2-tl .op2-bls--noth .op2-bl-g { grid-template-columns: minmax(0, 1fr) auto; }
.op2-tl .op2-bls--noth .op2-bl.is-x .op2-bl-g { grid-template-columns: minmax(0, 1fr) auto 14px; }
.op2-tl .op2-bl-th { grid-column: 1; }
.op2-tl .op2-bl-n { grid-column: 2; }
.op2-tl .op2-bl-r { grid-column: 3; }
.op2-tl .op2-bls--noth .op2-bl-n { grid-column: 1; }
.op2-tl .op2-bls--noth .op2-bl-r { grid-column: 2; }
@media (hover: hover) and (pointer: fine) {
  .op2-tl .op2-bl-d:not([open]):hover { background: none; }
  .op2-tl summary.op2-bl-g:hover { background: var(--oc3-raised); }
  .op2-tl summary.op2-bl-g:hover .op2-bl-cv { color: var(--oc3-ink); }
}
/* the node: the side's swords / shield in a ring of its colour (an icon AND a colour: never colour alone) */
.op2-tl .op2-bl { --k: var(--op2-tl-a); }
.op2-tl .op2-bl.is-def { --k: var(--op2-tl-d); }
.op2-tl.has-rk .op2-bl[data-m="r"] { --k: var(--op2-tl-r); }
.op2-tl .op2-bl.is-un { --k: var(--oc3-line-2); }
#oc3.op2 .op2-tl .op2-bl-g > .op2-bl-s {
  position: absolute; top: var(--tl-ny); left: calc((var(--tl-rail) - var(--tl-node)) / 2); z-index: 1; box-sizing: border-box; width: var(--tl-node); height: var(--tl-node);
  margin: 0; padding: 4px; border: 2px solid var(--k); border-radius: 50%; background: var(--oc3-card); object-fit: contain;
}
#oc3.op2 .op2-tl .op2-bl.is-un .op2-bl-g > .op2-bl-s { border-style: dashed; }
.op2-tl .op2-bl-g > picture.op2-bl-s > img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* a Ranked / Legend battle: the Ranked mark on its node's corner (vis_p2_logtl_rk; ic_p2_logtl_rk, a board variable) */
#oc3.op2 .op2-tl.has-rk .op2-bl[data-m="r"]:not(.is-un) .op2-bl-g::after {
  content: ""; position: absolute; z-index: 2; top: calc(var(--tl-ny) + var(--tl-node) - 11px); left: calc((var(--tl-rail) + var(--tl-node)) / 2 - 9px); width: 13px; height: 13px;
  background: var(--op2-tl-rki, none) center / contain no-repeat; pointer-events: none;
}
/* the opened battle unfolds under its line, past the rail (the rail runs on beside it) */
.op2-tl .op2-bl-x { margin-left: calc(var(--tl-rail) + 10px); }
.op2-tl .op2-bl-xi { padding: 0 2px; }
/* a battle leaving while the others glide: no band over the rail */
#oc3.op2 .op2-lfd .op2-bl-ghost { background: none; }
@media (max-width: 379.98px) {
  .op2-tl .op2-bls { --tl-rail: 26px; --tl-node: 24px; }
  .op2-tl .op2-bl-g { column-gap: 7px; grid-template-columns: 24px minmax(0, 1fr) auto; }
  .op2-tl .op2-bl.is-x .op2-bl-g { grid-template-columns: 24px minmax(0, 1fr) auto 10px; }
  #oc3.op2 .op2-tl .op2-bl-g > .op2-bl-s { padding: 3px; }
}
/* ── [/log timeline] rows ── */
/* motion: with "flip" (Battle log families) the scoreboard's bars slide to their new length with the rows (the morph beat); at the
   board's first sight ("bars") they grow out of the middle — held at 0 until then, like every bar of the page (the arming class
   only: JS off = drawn) */
#oc3.op2[data-mo~="on"] .op2-lfd[data-lmo~="flip"] .op2-lfs-b > i { transition: transform calc(450ms * var(--op2-mk, 1)) var(--op2-mo-settle); }
#oc3.op2.op2-mo-arm[data-mo~="bars"]:not([data-op2-live]) > .op2-lfd .op2-lfs-b > i,
#oc3.op2.op2-mo-arm[data-mo~="bars"] > .op2-lfd[data-op2-rv] .op2-lfs-b > i { transform: scaleX(0); }
#oc3.op2.op2-mo-arm[data-mo~="count"]:not([data-mo~="rev"]):not([data-op2-live]) > .op2-lfd :is(.op2-lfs-v b, .op2-lfs-h b),
#oc3.op2.op2-mo-arm[data-mo~="count"]:not([data-mo~="rev"]) > .op2-lfd[data-op2-rv] :is(.op2-lfs-v b, .op2-lfs-h b) { opacity: 0; }
@media (prefers-reduced-motion: reduce) { #oc3.op2.op2-mo-arm .op2-lfd .op2-lfs-b > i { transform: scaleX(var(--w, 0)) !important; } }
@media print { #oc3.op2 .op2-lfd .op2-lfs-b > i { transform: scaleX(var(--w, 0)) !important; } #oc3.op2 .op2-lfd .op2-bl-ghost { display: none !important; } }
/* ── [/log draft: feed] ── */

/* ── fix6 · League board (builder "League board", 2026-09-26): mockup A's League section — op2_sec_lg() ── */
/* heading: the current league's badge + its name on the right (Clash: a league name is identity, not a figure) */
.op2-lgb .op2-h .oc3-h-r { min-width: 0; }
.op2-lgb .op2-h .oc3-h-r > span { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.op2-lgb-ti { width: 22px; height: 22px; object-fit: contain; flex: none; }
#oc3.op2 .op2-lgb .oc3-h-r b.op2-lgb-tn { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--oc3-clash); font-size: 13px; letter-spacing: .02em; color: var(--oc3-ink); }
/* the strip: one row of equal cells between two hairlines (mockup A), a hairline between cells; four cells run two by two on phones */
.op2-fx--lg { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); column-gap: 0; padding: 9px 0; border-block: 1px solid var(--oc3-line); }
.op2-fx--lg > li { padding: 0 8px 0 10px; }
.op2-fx--lg > li:first-child { padding-left: 2px; }
.op2-fx--lg > li + li { border-left: 1px solid var(--oc3-line); }
.op2-fx--lg.is-after { margin-top: 12px; }
/* checker (life): the strip as the board's last part (an unranked player: no Journey, no seasons) keeps no dangling bottom rule */
.op2-fx--lg:last-child, .op2-fx--lg:has(+ noscript:last-child) { border-bottom: 0; padding-bottom: 2px; }
#oc3.op2 .op2-fx--lg b { font-size: 15px; }
/* the label runs under the icon and the figure (mockup A), so "best tier · 5 wks" keeps its line in a phone third */
#oc3.op2 .op2-fx--lg > li > .op2-fx-i { grid-row: 1; }
#oc3.op2 .op2-fx--lg > li > span:not(.op2-fx-i), #oc3.op2 .op2-fx--lg > li > b:first-child, #oc3.op2 .op2-fx--lg > li > b:first-child + span { grid-column: 1 / -1; }
.op2-fx--lg + .op2-sh--rule { margin-top: 14px; }
/* [ranked prover] 2026-09-28 (rules §K3): a strip label is never cut — a longer saved label ("Legend Trophies" in a 402 px third)
   takes a second line instead of the shared ellipsis */
#oc3.op2 .op2-fx--lg > li > span:not(.op2-fx-i) { white-space: normal; overflow: visible; text-overflow: clip; }
@media (max-width: 479.98px) {
  .op2-fx--lg:has(> li:nth-child(4)) { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 9px; }
  .op2-fx--lg:has(> li:nth-child(4)) > li:nth-child(odd) { border-left: 0; padding-left: 2px; }
}
/* [strip cells] 2026-09-28: a phone third (390–419 px) keeps a whole "Legend II" clear of the next cell's hairline (15 px ran into it) */
@media (max-width: 419.98px) {
  #oc3.op2 .op2-fx--lg b { font-size: 14px; }
}
@media (max-width: 379.98px) {
  #oc3.op2 .op2-fx--lg b { font-size: 13px; }
  .op2-fx--lg > li { padding: 0 5px 0 7px; }
  #oc3.op2 .op2-fx--lg > li > span { font-size: 10.5px; }   /* "best tier · 5 wks" keeps its line in a 360 third */
}
/* [strip cells] a top-3 best place: its medal is the figure, as large as the other cells' icons */
#oc3.op2 .op2-fx--lg > li > b > .op2-md { width: 22px; height: 22px; font-size: 11px; vertical-align: middle; margin: 0; }
#oc3.op2 .op2-fx--lg > li > b > .op2-md .op2-mi { width: 22px; height: 22px; }
/* [strip cells] 2026-09-28: five or six cells run three by two wherever one row of six would squeeze a "#11,195" (phones,
   tablets under 768 px, a half-width desktop board) — the same hairlines between the cells of a row, the two rows apart like
   the phone's two by two; from 768 px one row of up to six */
@media (max-width: 767.98px) {
  .op2-fx--lg:has(> li:nth-child(5)) { grid-auto-flow: row; grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: 9px; }
  .op2-fx--lg:has(> li:nth-child(5)) > li:nth-child(n) { border-left: 1px solid var(--oc3-line); padding-left: 8px; }
  .op2-fx--lg:has(> li:nth-child(5)) > li:nth-child(3n+1) { border-left: 0; padding-left: 2px; }
}
@media (max-width: 379.98px) {
  .op2-fx--lg:has(> li:nth-child(5)) > li:nth-child(n):not(:nth-child(3n+1)) { padding-left: 6px; }
}
@media (min-width: 1024px) {
  .op2-half .op2-fx--lg:has(> li:nth-child(5)) { grid-auto-flow: row; grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: 9px; }
  .op2-half .op2-fx--lg:has(> li:nth-child(5)) > li:nth-child(n) { border-left: 1px solid var(--oc3-line); padding-left: 10px; }
  .op2-half .op2-fx--lg:has(> li:nth-child(5)) > li:nth-child(3n+1) { border-left: 0; padding-left: 2px; }
}
/* rows (weekly results, Legend seasons): the figures run in columns like mockup A — the big one, then the next ones — lined
   up from row to row (the rows share their list's columns through subgrid). Under 390px (a 360 phone, a 7-digit global rank)
   the columns would squeeze the date onto two lines: the next figures go back under the big one, like History's rows */
@supports (grid-template-columns: subgrid) { @media (min-width: 390px) {
  .op2-lg-l { display: grid; grid-template-columns: 26px minmax(0, 1fr) auto auto; column-gap: 10px; }
  .op2-lg-l > .op2-ls { grid-column: 1 / -1; grid-template-columns: subgrid; }
  .op2-lg-l > .op2-ls[hidden] { display: none; }
  .op2-lg-l .op2-ls-v { display: contents; }
  .op2-lg-l .op2-ls-v > b, .op2-lg-l .op2-ls-v > small { justify-self: end; }
} }
.op2-lg-l .op2-ls-v > small { font-family: var(--oc3-data); font-weight: 600; font-size: calc(13px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); }
/* ── end fix6 · League board ── */

/* ── [league life builder] (2026-09-26 "life") · the League board as a tier journey — op2_lg_now() / op2_lg_journey() /
   op2_lg_seasons() / op2_lg_records(); its motion: player-v2.js "[league life builder]" + the fold / held / off switches at the
   end of this block. The ladder's colours are page tokens (Colours → League journey: col_p2_jr_up / _stay / _down). ── */
#oc3.op2 { --op2-jr-up: var(--oc3-green); --op2-jr-stay: #c3c9d2; --op2-jr-down: var(--oc3-red); }
html[data-theme="dark"] #oc3.op2 { --op2-jr-stay: #4a525e; }
#oc3.op2 .op2-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* the top: the current league (identity: its badge and name), the last finished week's figures, this week's attacks */
.op2-lgn { display: grid; grid-template-columns: 48px minmax(0, 1fr); column-gap: 12px; align-items: center; padding: 0 0 12px; }
.op2-lgn-bd { width: 48px; height: 48px; object-fit: contain; }
.op2-lgn-t { display: grid; row-gap: 4px; min-width: 0; }
#oc3.op2 .op2-lgn-nm { font-family: var(--oc3-clash); font-weight: 700; font-size: calc(17px * var(--oc3-ts, 1)); line-height: 1.15; letter-spacing: .02em; color: var(--oc3-ink); overflow-wrap: anywhere; }
.op2-lgn-l { display: flex; flex-wrap: wrap; gap: 3px 14px; margin: 0; font-size: calc(12.5px * var(--oc3-ts, 1)); line-height: 1.3; color: var(--oc3-mute); }
.op2-lgn-p { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; cursor: pointer; }
#oc3.op2 .op2-lgn-p > b { font-family: var(--oc3-data); font-weight: 700; font-size: calc(14.5px * var(--oc3-ts, 1)); color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-lgn-pi { width: 16px; height: 16px; object-fit: contain; flex: none; }
.op2-lgn-p .op2-md--xs { vertical-align: 0; margin: 0; }
.op2-lgn-none { white-space: normal; color: var(--oc3-ink-3); }
.op2-lgn + .op2-fx--lg.is-after { margin-top: 0; }
/* the tabs: the page's tab row (its sliding mark: player-v2.js); on phones the icon sits over its name */
.op2-lg-tabs.is-after { margin-top: 12px; }
.op2-lg-p { padding-top: 6px; }
.op2-lg-psh { display: none; }   /* a panel's own sub-heading: only without JavaScript and on paper (the tab names it otherwise) */
@media (max-width: 479.98px) {
  .op2-lg-tabs .oc3-tab { flex-direction: column; gap: 3px; min-height: 52px; padding: 6px 4px; font-size: 10px; }
  .op2-lg-tabs .oc3-tab span { white-space: normal; text-align: center; line-height: 1.15; overflow: visible; }
  .op2-lg-tabs .oc3-tab-i { width: 20px; height: 20px; }
}
/* the Journey: a rail on the left (30px) — each week's tier badge a rung, the segment between two rungs coloured by how the
   lower week ended, its ribbon on the step; the week itself is a button (it opens), its figures lined up from row to row */
.op2-jr { --jr-rail: 30px; --jr-node: 26px; --jr-ny: 11px; margin: 0; padding: 0; list-style: none; }
.op2-jr-w { position: relative; margin: 0; list-style: none; }
.op2-jr-w + .op2-jr-w::after { content: ""; position: absolute; top: 0; left: calc(var(--jr-rail) + 10px); right: 0; border-top: 1px solid var(--oc3-line); pointer-events: none; }
.op2-jr-r { position: absolute; top: 0; bottom: 0; left: 0; width: var(--jr-rail); z-index: 1; pointer-events: none; }
#oc3.op2 .op2-jr-bd { position: absolute; top: var(--jr-ny); left: calc((var(--jr-rail) - var(--jr-node)) / 2); width: var(--jr-node); height: var(--jr-node); object-fit: contain; z-index: 1; }
.op2-jr-seg { --c: var(--op2-jr-stay); position: absolute; left: calc(var(--jr-rail) / 2 - 1px); width: 2px; border-radius: 999px; background: var(--c); transform-origin: 50% 100%; }
.op2-jr-seg.is-up { top: 0; height: calc(var(--jr-ny) + 3px); }
.op2-jr-seg.is-dn { top: calc(var(--jr-ny) + var(--jr-node) - 3px); bottom: 0; }
.op2-jr-seg[data-mv="up"] { --c: var(--op2-jr-up); }
.op2-jr-seg[data-mv="down"] { --c: var(--op2-jr-down); }
.op2-jr-seg[data-gap] { background: repeating-linear-gradient(to bottom, var(--c) 0 3px, transparent 3px 7px); }
/* the ribbon stands on the step between two weeks (the boundary of the lower row) */
#oc3.op2 .op2-jr-mv { position: absolute; top: 0; left: calc(var(--jr-rail) / 2 - 6px); width: 12px; height: 18px; margin-top: -9px; object-fit: contain; z-index: 2; filter: drop-shadow(0 1px 1px rgba(16, 24, 40, .22)); }
/* the last week shown has no segment under it (the rows after it hidden, or kept for the other device's count) */
.op2-jr-w:last-child .op2-jr-seg.is-dn, .op2-jr-w:has(+ .op2-jr-w[hidden]) .op2-jr-seg.is-dn { display: none; }
@media (max-width: 1023.98px) {
  .op2-jr:not(:has(~ .oc3-more [aria-expanded="true"])) > .op2-jr-w.is-dk { display: none; }
  .op2-jr:not(:has(~ .oc3-more [aria-expanded="true"])) > .op2-jr-w:has(+ .op2-jr-w.is-dk) .op2-jr-seg.is-dn { display: none; }
}
@media (min-width: 1024px) {
  .op2-jr:not(:has(~ .oc3-more [aria-expanded="true"])) > .op2-jr-w.is-ph { display: none; }
  .op2-jr:not(:has(~ .oc3-more [aria-expanded="true"])) > .op2-jr-w:has(+ .op2-jr-w.is-ph) .op2-jr-seg.is-dn { display: none; }
}
.op2-jr-b {
  display: grid; grid-template-columns: minmax(0, 1fr) auto 14px; grid-template-areas: "t v c" "s w c"; column-gap: 10px; row-gap: 2px; align-items: center;
  box-sizing: border-box; width: 100%; min-height: 50px; margin: 0; padding: 8px 2px 8px calc(var(--jr-rail) + 10px);
  border: 0; border-radius: 0; background: none; box-shadow: none; color: inherit; font: inherit; text-align: left; text-transform: none; letter-spacing: normal; cursor: pointer;
}
span.op2-jr-b { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "t v" "s w"; cursor: default; }
#oc3.op2 .op2-jr-b:focus-visible { outline: 2px solid var(--oc3-focus); outline-offset: -2px; }
.op2-jr-c { display: grid; grid-template-areas: "t" "s"; row-gap: 2px; align-content: center; min-height: 50px; box-sizing: border-box; padding: 8px 2px 8px calc(var(--jr-rail) + 10px); }
#oc3.op2 .op2-jr-t { grid-area: t; min-width: 0; font-family: var(--oc3-clash); font-weight: 700; font-size: 13px; line-height: 1.2; letter-spacing: .02em; color: var(--oc3-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#oc3.op2 .op2-jr-s { grid-area: s; min-width: 0; font-family: var(--oc3-sans) !important; font-weight: 400; letter-spacing: normal; text-transform: none; font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.25; color: var(--oc3-mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op2-jr-w.is-now .op2-jr-t { color: var(--oc3-ink); }
/* checker (life): a week's title wider than its column ("Week of Sep 14" beside its figures on a 360 px phone) wraps at a
   space instead of losing its date to "Week of Sep…" */
#oc3.op2 .op2-jr-t { white-space: normal; text-wrap: balance; }
.op2-jr-w.is-now[data-tt-l] { cursor: pointer; }
.op2-jr-v { grid-area: v; display: inline-flex; align-items: center; justify-content: flex-end; gap: 10px; }
.op2-jr-f { display: inline-flex; align-items: center; justify-content: flex-end; gap: 3px; box-sizing: content-box; white-space: nowrap; font-family: var(--oc3-data); font-variant-numeric: tabular-nums; }
.op2-jr-fa { min-width: calc(var(--jr-a, 3ch) + 17px); font-weight: 700; font-size: calc(15px * var(--oc3-ts, 1)); color: var(--oc3-ink); }
.op2-jr-fb { min-width: calc(var(--jr-b, 3ch) + 17px); font-weight: 600; font-size: calc(13px * var(--oc3-ts, 1)); color: var(--oc3-ink-3); }
.op2-jr-fi { width: 14px; height: 14px; object-fit: contain; flex: none; }
.op2-jr-f .op2-md--xs { margin: 0; vertical-align: 0; }
.op2-jr-wl { grid-area: w; display: inline-flex; justify-content: flex-end; gap: 10px; font-family: var(--oc3-data); font-weight: 600; font-size: calc(12px * var(--oc3-ts, 1)); color: var(--oc3-mute); font-variant-numeric: tabular-nums; }
.op2-jr-wlp { position: relative; display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
.op2-jr-wlp .op2-jr-fi { width: 13px; height: 13px; }
.op2-jr-cv { grid-area: c; color: var(--oc3-ink-3); }
.op2-jr-b[aria-expanded="true"] .op2-jr-cv { transform: rotate(180deg); }
@media (hover: hover) and (pointer: fine) {
  button.op2-jr-b:hover { background: var(--oc3-raised); }
  button.op2-jr-b:hover .op2-jr-cv { color: var(--oc3-ink); }
}
/* an opened week: it unfolds under its line (grid rows 0fr → 1fr), its figures two by two (three on a full-width desktop board) */
.op2-jr-x { display: grid; grid-template-rows: 0fr; visibility: hidden; margin-left: calc(var(--jr-rail) + 10px); }
.op2-jr-b[aria-expanded="true"] + .op2-jr-x { grid-template-rows: 1fr; visibility: visible; }
.op2-jr-xi { min-height: 0; overflow: hidden; }
.op2-jr-xs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px 12px; margin: 0; padding: 2px 2px 12px; list-style: none; }
.op2-jr-xc { display: flex; align-items: center; gap: 6px; min-width: 0; margin: 0; list-style: none; font-size: calc(12.5px * var(--oc3-ts, 1)); line-height: 1.3; color: var(--oc3-mute); }
#oc3.op2 .op2-jr-xc b { font-family: var(--oc3-data); font-weight: 700; color: var(--oc3-ink); font-variant-numeric: tabular-nums; }
.op2-jr-xc.is-wide { grid-column: 1 / -1; }
#oc3.op2 .op2-jr-xic { width: 18px; height: 18px; object-fit: contain; flex: none; }
#oc3.op2 .op2-jr-xmv { width: 12px; }
.op2-jr-xc.is-mv b { font-family: var(--oc3-sans); font-weight: 600; }
.op2-jr-xc.is-used > span:not(.oc3-meter) { flex: none; }
.op2-jr-xc.is-used .op2-jr-bar { flex: 1 1 60px; min-width: 60px; height: 6px; margin-left: 4px; }
.op2-jr-note { margin: -4px 2px 12px; font-size: calc(11.5px * var(--oc3-ts, 1)); line-height: 1.35; color: var(--oc3-ink-3); }
.op2-jr-empty { padding: 2px 2px 4px calc(var(--jr-rail, 30px) + 10px); }
@media (min-width: 1024px) { .op2-lgb:not(.op2-half) .op2-jr-xs { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 379.98px) {
  .op2-jr-v, .op2-jr-wl { gap: 7px; }
  .op2-jr-b, span.op2-jr-b { column-gap: 7px; }
  .op2-jr-fa { font-size: 14px; }
}
/* fill (2026-09-27): a computed figure's marker (vis_p2_lg_fill_mk) and the unknown mark — the board's own figures, one step
   quieter; the running week's figures sit in the same columns as the weeks under it (their chevron column + gap kept free) */
#oc3.op2 .op2-apx { margin-right: 1px; font-weight: 500; color: var(--oc3-ink-3); }
#oc3.op2 .op2-unk { font-weight: 600; color: var(--oc3-ink-3); }
.op2-jr-f.is-unk .op2-jr-fi, .op2-lg-s .op2-unk + .op2-jr-fi { opacity: .5; }
.op2-jr-c.has-v { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "t v" "s v"; column-gap: 10px; padding-right: 26px; }
.op2-jr-part { color: var(--oc3-ink-3); }
/* [feed rule] (2026-09-27): a figure only our feed gives, of a week it saw in part — the unknown mark, its icon a step quieter;
   a tap / hover gives the reason (the opened week's figure: the board's tooltip; the won–lost on the line: its title) */
.op2-jr-xc.is-na .op2-jr-xic, .op2-jr-wlp.is-na .op2-jr-fi { opacity: .5; }
.op2-jr-xc.is-na { cursor: help; }
#oc3.op2 .op2-jr-note .op2-apx { margin-right: 3px; }   /* checker: #oc3.op2 .op2-apx (1px) outranked the unscoped rule */
@media (max-width: 379.98px) { .op2-jr-c.has-v { column-gap: 7px; padding-right: 23px; } }
/* [cs backfill] (2026-09-27): the mark after a figure from ClashSpot's saved Ranked history (vis_p2_lg_fill_cs_mk) — small and
   raised like a footnote's, as quiet as the computed marker; the opened week's note starts with it */
#oc3.op2 .op2-csm { margin-left: 2px; font-family: var(--oc3-sans); font-size: .58em; font-weight: 700; letter-spacing: .04em; line-height: 1; color: var(--oc3-ink-3); vertical-align: .6em; }
#oc3.op2 .op2-jr-note .op2-csm { margin: 0 4px 0 0; font-size: .8em; vertical-align: .25em; }
/* in the Journey's figure columns the mark has a fixed room (1.7 of its em ≈ 1 em of the figure) and every other figure keeps
   the same room empty, so the digits of every week line up, the marks in their own narrow column after them */
#oc3.op2 .op2-jr-f .op2-csm { flex: none; align-self: flex-start; box-sizing: border-box; min-width: 1.7em; margin: 1px 0 0 1px; text-align: left; }
#oc3.op2 .op2-jr.has-csm .op2-jr-f:not(.is-cs)::after { content: ""; flex: none; width: calc(.986em + 1px); }
.op2-jr.has-csm .op2-jr-fa { min-width: calc(var(--jr-a, 3ch) + 21px + .986em); }
.op2-jr.has-csm .op2-jr-fb { min-width: calc(var(--jr-b, 3ch) + 24px + .986em); }   /* + 3 px: a "#" is a little wider than 1ch */
/* the Legend seasons by era: a heading per era (its badge, name, dates · count; a tap = what that system was), the seasons
   under it, the first column holding a best finish's medal */
.op2-lse + .op2-lse { margin-top: 12px; }
.op2-lse-h { display: flex; align-items: center; margin: 0; padding: 4px 0 7px; border-bottom: 1px solid var(--oc3-line); font: inherit; }
.op2-lse-hb { display: inline-grid; grid-template-columns: 26px minmax(0, 1fr); column-gap: 10px; align-items: center; min-width: 0; cursor: pointer; }
#oc3.op2 .op2-lse-bd { width: 26px; height: 26px; object-fit: contain; }
.op2-lse-hn { display: grid; min-width: 0; }
#oc3.op2 .op2-lse-hn b { font-family: var(--oc3-clash); font-weight: 700; font-size: 12.5px; line-height: 1.2; letter-spacing: .05em; text-transform: uppercase; color: var(--oc3-ink); }
#oc3.op2 .op2-lse-hn small { font-family: var(--oc3-sans) !important; font-weight: 400; letter-spacing: normal; text-transform: none; font-size: calc(12px * var(--oc3-ts, 1)); line-height: 1.3; color: var(--oc3-mute); }
.op2-lse-mc { display: inline-flex; align-items: center; justify-content: center; }
#oc3.op2 .op2-lse-md { width: 22px; height: 22px; font-size: 11px; }
#oc3.op2 .op2-lse-md.has-mi, #oc3.op2 .op2-lse-md .op2-mi { width: 24px; height: 24px; }
.op2-ls-n b .op2-lse-md { margin-right: 6px; vertical-align: -5px; }
/* the Records: the page's record tiles */
.op2-lgr { margin-top: 2px; }

/* League motion (Player Page → Motion: vis_p2_mo_lg_climb / vis_p2_mo_lg_fold, as the section's data-lg-mo) */
/* fold: a week unfolds on the arrival curve and folds back faster; the chevron turns with it */
#oc3.op2 .op2-lgb[data-lg-mo~="fold"] .op2-jr-x { transition: grid-template-rows calc(260ms * var(--op2-mk, 1)) var(--op2-mo-settle), visibility 0s linear calc(260ms * var(--op2-mk, 1)); }
#oc3.op2 .op2-lgb[data-lg-mo~="fold"] .op2-jr-b[aria-expanded="true"] + .op2-jr-x { transition: grid-template-rows calc(420ms * var(--op2-mk, 1)) var(--op2-mo-out), visibility 0s; }
#oc3.op2 .op2-lgb[data-lg-mo~="fold"] .op2-jr-cv { transition: transform var(--op2-mo-st) var(--op2-mo-out); }
/* climb: held at its start while the board waits for its first sight (the arming class only: JS off = drawn) */
#oc3.op2.op2-mo-arm:not([data-op2-live]) > .op2-lgb[data-lg-mo~="climb"] .op2-jr-seg,
#oc3.op2.op2-mo-arm > .op2-lgb[data-lg-mo~="climb"][data-op2-rv] .op2-jr-seg { transform: scaleY(0); }
/* without JavaScript, and on paper: every panel shows under its sub-heading (no tab row), every week open */
@media (scripting: none) {
  #oc3.op2 .op2-lg-tabs { display: none; }
  #oc3.op2 .op2-lg-p[hidden] { display: block !important; }
  #oc3.op2 .op2-lg-psh { display: block; }
  #oc3.op2 .op2-lg-p + .op2-lg-p .op2-sh { margin-top: 16px; }
  #oc3.op2 .op2-jr-x { grid-template-rows: 1fr; visibility: visible; }
  #oc3.op2 .op2-jr-cv { display: none; }
}
@media print {
  #oc3.op2 .op2-lg-tabs { display: none; }
  #oc3.op2 .op2-lg-p[hidden] { display: block !important; }
  #oc3.op2 .op2-lg-psh { display: block; }
  #oc3.op2 .op2-lg-p + .op2-lg-p .op2-sh { margin-top: 16px; }
  #oc3.op2 .op2-jr-seg { transform: none !important; }
}
@media (prefers-reduced-motion: reduce) { #oc3.op2 .op2-jr-seg { transform: none !important; } }
/* ── [ranked prover] (2026-09-28, rules §K4 / §K5, Δ12) JavaScript off: "Show all" needs the page script — without it (the board
   never marked [data-js]) its buttons are not drawn and every week / season of the set shows (the rows kept for the other device's
   count too, when a button would have opened them; with "Show all" switched off each device keeps its own count). Paper: no
   button (the rows printed = the rows the screen lists), every listed week open (a tap can't open it on paper). ── */
.op2-lgb:not([data-js]) .oc3-more { display: none !important; }
.op2-lgb:not([data-js]) .op2-jr > .op2-jr-w[data-more-of][hidden],
.op2-lgb:not([data-js]) .op2-jr:has(~ .oc3-more) > .op2-jr-w.is-dk,
.op2-lgb:not([data-js]) .op2-jr:has(~ .oc3-more) > .op2-jr-w.is-ph { display: list-item !important; }
.op2-lgb:not([data-js]) .op2-jr:has(~ .oc3-more) > .op2-jr-w .op2-jr-seg.is-dn { display: block !important; }
.op2-lgb:not([data-js]) .op2-jr > .op2-jr-w:last-child .op2-jr-seg.is-dn { display: none !important; }
.op2-lgb:not([data-js]) .op2-lse[data-more-of][hidden] { display: block !important; }
.op2-lgb:not([data-js]) .op2-lss > .op2-ls[data-more-of][hidden] { display: grid !important; }
@media print {
  #oc3.op2 .op2-lgb .oc3-more { display: none !important; }
  #oc3.op2 .op2-lgb .op2-jr-x { grid-template-rows: 1fr !important; visibility: visible !important; }
  #oc3.op2 .op2-lgb .op2-jr-cv { display: none !important; }
}
/* ── end [league life builder] ── */

/* ══ motion (2026-09-26 animate pass — Player Page → Motion; player-v2.js "motion") ═══════════════════════════════════════════
   Félix: "For the player's page, you don't have restrictions" — the DESIGN.md Data-Moves and Glow-In-Place rules do not apply
   here (the clan page keeps them). One motion language: things are DEALT onto the page like cards — they arrive from a short
   distance on the confident arrival curve (--op2-mo-out) and settle; bars and sliding rows use the DESIGN.md settle curve.
   Timings (× --op2-mk = Player Page → Motion → Motion time; player-v2.js scales its own the same way):
     feedback 140ms (tooltip pop, press)   state 260ms (tabs, panels, the jump mark)   reveal 420ms (a board rising in)
     land 560ms (the Town Hall)            count 800ms (figures)                        grow 900ms (bars, DESIGN.md)
     step 45ms, capped at 300ms (a list's stagger)
   #oc3's data-mo lists the families that are on: 'on' (the master), entr, rev, count, bars, rows, tabs, fb, hover, shine, dot.
   The entrances are Web Animations started by player-v2.js with a backwards fill; this file only supplies the HELD states they
   start from, and those exist only under .op2-mo-arm — a class the inline script at the top of #oc3 adds before the cards are
   parsed (reduced motion, a back / forward visit: never). player-v2.js takes over with [data-op2-live] (the inline script
   gives the page back after 3 s if it never does). Without JS nothing here hides anything. Loops rest off screen
   ([data-op2-off]) and in a hidden tab ([data-op2-hid]). Reduced motion and print: everything whole and still.
   (check pass 2: the states player-v2.js changes on the root, the boards and the upgrade groups are ATTRIBUTES, not classes:
   the theme's :not([class*=gridContainer]) rules restyle every picture, cell and paragraph under an element whose class
   changes — up to 2 100 elements a frame on this page, mid-scroll) */
#oc3.op2 {
  --op2-mo-out: cubic-bezier(.16, 1, .3, 1);
  --op2-mo-settle: cubic-bezier(.25, .7, .3, 1);
  --op2-mo-fb: calc(140ms * var(--op2-mk, 1));
  --op2-mo-st: calc(260ms * var(--op2-mk, 1));
}

/* ── held states (entrance start points) ── */
/* before player-v2.js runs: the first card's contents (its surface stays: the card is dealt INTO its frame) */
#oc3.op2.op2-mo-arm[data-mo~="entr"]:not([data-op2-live]) > .op2-score > * { opacity: 0; }
/* a board: before player-v2.js runs, then while it waits for its first sight ([data-op2-rv]) */
#oc3.op2.op2-mo-arm[data-mo~="rev"]:not([data-op2-live]) > .oc3-sec,
#oc3.op2.op2-mo-arm[data-mo~="rev"] > .oc3-sec[data-op2-rv] { opacity: 0; }
/* board reveals off: the board shows, what moves inside it waits (empty bars, figures and rows not yet dealt) */
#oc3.op2.op2-mo-arm[data-mo~="bars"]:not([data-op2-live]) > .oc3-sec :is(.oc3-meter, .oc3-li-bar) > i,
#oc3.op2.op2-mo-arm[data-mo~="bars"] > .oc3-sec[data-op2-rv] :is(.oc3-meter, .oc3-li-bar) > i { transform: scaleX(0); }
#oc3.op2.op2-mo-arm[data-mo~="count"]:not([data-mo~="rev"]):not([data-op2-live]) > .oc3-sec :is(.op2-fx b, .oc3-m-v, .op2-avg b, .op2-tbl td, .op2-att-v, .oc3-li-v, .oc3-res, .oc3-read-v, .op2-h-fig, .op2-up-sum b, .op2-ls-v > b, .op2-bl-p, .op2-vil b, .op2-un-v b, .op2-wk b),
#oc3.op2.op2-mo-arm[data-mo~="count"]:not([data-mo~="rev"]) > .oc3-sec[data-op2-rv] :is(.op2-fx b, .oc3-m-v, .op2-avg b, .op2-tbl td, .op2-att-v, .oc3-li-v, .oc3-res, .oc3-read-v, .op2-h-fig, .op2-up-sum b, .op2-ls-v > b, .op2-bl-p, .op2-vil b, .op2-un-v b, .op2-wk b),
#oc3.op2.op2-mo-arm[data-mo~="rows"]:not([data-mo~="rev"]):not([data-op2-live]) > .oc3-sec :is(.oc3-list > .oc3-li, .op2-bls > .op2-bl, .op2-lss > .op2-ls, .op2-atts > li, .op2-uns > li, .op2-tbl tbody tr, .op2-fx > li, .op2-up-sum > li, .op2-moves > li, .oc3-units > .oc3-u),
#oc3.op2.op2-mo-arm[data-mo~="rows"]:not([data-mo~="rev"]) > .oc3-sec[data-op2-rv] :is(.oc3-list > .oc3-li, .op2-bls > .op2-bl, .op2-lss > .op2-ls, .op2-atts > li, .op2-uns > li, .op2-tbl tbody tr, .op2-fx > li, .op2-up-sum > li, .op2-moves > li, .oc3-units > .oc3-u) { opacity: 0; }
/* armed, the bars are grown by player-v2.js (from their first sight, with a stagger), not all at once at load by the shared
   stylesheet; same-session revisit (.op2-mo-rest): at rest */
#oc3.op2:is(.op2-mo-arm, .op2-mo-rest) :is(.oc3-meter, .oc3-li-bar) > i { animation-name: none; }

/* (a board whose entrance is running gets will-change: transform for ~2 s — an inline style set by player-v2.js: one layer of
   its own, so the rows / bars / stars taking and giving back their layers repaint the board, not the whole page) */

/* a counting figure (player-v2.js wraps the number): its final width is reserved, digits in tabular figures, so nothing
   beside it moves while it counts (the wrapper is removed when the count ends) */
#oc3.op2 .op2-cu { display: inline-block; white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; will-change: transform; }
/* (anim check pass: will-change gives each counting figure its own small layer while it counts — its digits no longer repaint
   the whole page layer every frame; the frame cost at 4× slowdown halved) */

/* ── tabs & the jump strip: one sliding mark (a shared element) instead of each tab painting its own fill ──
   player-v2.js adds .op2-sld to the tab row (or the jump strip) and one .op2-sld-i: it sits over the resting fills (each
   tab's ::before) and under the borders and labels, and glides to the tab picked (transform only). */
#oc3.op2 .op2-sld { isolation: isolate; }
#oc3.op2 .oc3-tabs.op2-sld, #oc3.op2 .op2-jwrap:not(.is-fixed) .op2-jump.op2-sld { position: relative; }   /* (pinned, the strip stays fixed) */
#oc3.op2 .op2-sld-i {
  position: absolute; left: 0; top: 0; z-index: -1; width: 100px; height: 100px; transform-origin: 0 0; pointer-events: none;
  background: var(--oc3-ink); opacity: 0;
  transition: transform var(--op2-mo-st) var(--op2-mo-out), opacity var(--op2-mo-fb) linear;
}
#oc3.op2 .oc3-today .op2-sld-i { background: var(--oc3-gold); }
#oc3.op2 .op2-jump.op2-sld .op2-sld-i { background: var(--op2-jump-on); }
#oc3.op2 .op2-sld :is(.oc3-tab, a.op2-j) { position: relative; background: transparent; }   /* (labels switch at once: the mark carries the motion; a colour tween repainted the strip every frame of every scroll-spy change) */
#oc3.op2 .op2-sld .oc3-tab::before, #oc3.op2 .op2-sld a.op2-j::before { content: ""; position: absolute; inset: -1px; z-index: -2; background: var(--oc3-raised); pointer-events: none; }
#oc3.op2 .op2-jump.op2-sld a.op2-j::before { background: var(--oc3-card); }
#oc3.op2 .op2-sld .oc3-tab[aria-selected="true"], #oc3.op2 .op2-jump.op2-sld a.op2-j.is-on { background: transparent; }
/* tab motion off: the mark still marks, it just jumps */
#oc3.op2[data-mo]:not([data-mo~="tabs"]) .op2-sld-i { transition: none; }

/* ── feedback ── */
/* a tooltip pops from its stat (from the arrow's point), and leaves faster than it came */
#oc3.op2[data-mo~="fb"] .oc3-tt { transform-origin: var(--ax, 50%) calc(100% + 5px); animation: op2-tt-in var(--op2-mo-fb) var(--op2-mo-out) both; }
#oc3.op2[data-mo~="fb"] .oc3-tt[data-at="bottom"] { transform-origin: var(--ax, 50%) -5px; }
#oc3.op2[data-mo~="fb"] .oc3-tt.op2-tt-out { animation: op2-tt-out calc(90ms * var(--op2-mk, 1)) ease-in both; }
@keyframes op2-tt-in { from { opacity: 0; transform: scale(.92); } }
@keyframes op2-tt-out { to { opacity: 0; transform: scale(.96); } }
/* press: buttons give under the finger; tabs and jump icons press their contents (their own box carries the sliding mark) */
#oc3.op2[data-mo~="fb"] :is(.oc3-btn, .oc3-srcsw, .oc3-tag) { transition: transform calc(110ms * var(--op2-mk, 1)) var(--op2-mo-out); }
#oc3.op2[data-mo~="fb"] :is(.oc3-btn, .oc3-srcsw, .oc3-tag):active { transform: scale(.97); }
#oc3.op2[data-mo~="fb"] :is(.oc3-tab, a.op2-j) > * { transition: transform calc(110ms * var(--op2-mk, 1)) var(--op2-mo-out); }
#oc3.op2[data-mo~="fb"] :is(.oc3-tab, a.op2-j):active > * { transform: scale(.92); }
/* the tag chip: the copy icon turns into a ✓ for 1.2 s (stacked, the chip never changes width; the word is for screen readers) */
#oc3.op2 .oc3-tag { position: relative; }
#oc3.op2 .oc3-tag-ok { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
#oc3.op2 .op2-tag-ck { position: absolute; right: 10px; top: 50%; margin-top: -6px; color: var(--oc3-green); opacity: 0; transform: scale(.4); }
#oc3.op2 .op2-tag-ck path { stroke-dasharray: 24; stroke-dashoffset: 24; }
#oc3.op2 .oc3-tag.is-ok { border-color: var(--oc3-green); }
#oc3.op2 .oc3-tag.is-ok .oc3-tag-i { opacity: 0; transform: scale(.4) rotate(-45deg); }
#oc3.op2 .oc3-tag.is-ok .op2-tag-ck { opacity: 1; transform: none; }
#oc3.op2 .oc3-tag.is-ok .op2-tag-ck path { stroke-dashoffset: 0; }
#oc3.op2[data-mo~="fb"] .oc3-tag :is(.oc3-tag-i, .op2-tag-ck) { transition: opacity var(--op2-mo-fb) linear, transform var(--op2-mo-st) var(--op2-mo-out); }
#oc3.op2[data-mo~="fb"] .oc3-tag .op2-tag-ck path { transition: stroke-dashoffset calc(280ms * var(--op2-mk, 1)) var(--op2-mo-out) calc(60ms * var(--op2-mk, 1)); }
/* a board reached from the jump strip: a short gold sweep under its title, so the eye finds where it landed */
#oc3.op2 .oc3-h-t.op2-sweep { position: relative; }
#oc3.op2 .oc3-h-t.op2-sweep::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -5px; height: 3px; border-radius: 2px;
  background: linear-gradient(90deg, var(--oc3-gold-a), var(--oc3-gold-b)); transform-origin: left center;
  animation: op2-hsweep calc(1.2s * var(--op2-mk, 1)) var(--op2-mo-out) both;
}
@keyframes op2-hsweep { 0% { transform: scaleX(0); opacity: 1; } 35% { transform: none; opacity: 1; } 100% { transform: none; opacity: 0; } }

/* ── hover (a mouse only): tiles and unit icons lift, stat slots brighten ── */
@media (hover: hover) and (pointer: fine) {
  #oc3.op2[data-mo~="hover"] .op2-upg .oc3-u,
  #oc3.op2[data-mo~="hover"] .op2-army .op2-li-u { transition: transform calc(160ms * var(--op2-mk, 1)) var(--op2-mo-out); }
  #oc3.op2[data-mo~="hover"] .op2-upg .oc3-u .oc3-u-i { transition: filter calc(160ms * var(--op2-mk, 1)) var(--op2-mo-out); }
  #oc3.op2[data-mo~="hover"] .op2-upg .oc3-u:hover { transform: translateY(-2px); }
  #oc3.op2[data-mo~="hover"] .op2-upg .oc3-u:hover .oc3-u-i { filter: drop-shadow(0 4px 5px rgba(16, 24, 40, .28)); }
  #oc3.op2[data-mo~="hover"] .op2-army .oc3-li-a:hover .op2-li-u { transform: translateY(-2px) scale(1.06); }
  #oc3.op2[data-mo~="hover"] .op2-sls > .op2-sl { transition: background-color calc(160ms * var(--op2-mk, 1)) linear; }
  #oc3.op2[data-mo~="hover"] .op2-sls > .op2-sl:hover { background-color: var(--oc3-raised); }
}

/* ── shine (one pass, never a loop) ── */
/* a badge / medal catches the light once: a band crossing the picture's own shape (player-v2.js lays .op2-shn over the picture
   and masks it with the picture itself, so the band never shows outside the art; the band moves by transform, off the main
   thread) */
#oc3.op2 .op2-shn {
  position: absolute; z-index: 1; overflow: hidden; pointer-events: none;
  -webkit-mask: var(--op2-shn) center / contain no-repeat; mask: var(--op2-shn) center / contain no-repeat;
}
#oc3.op2 .op2-shn::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 70%;
  background: linear-gradient(105deg, transparent 15%, rgba(255, 255, 255, .92) 50%, transparent 85%);
  transform: translateX(-110%);
  animation: op2-shine calc(900ms * var(--op2-mk, 1)) cubic-bezier(.45, 0, .25, 1) both;
}
@keyframes op2-shine { from { transform: translateX(-110%); } to { transform: translateX(160%); } }
/* an upgrade group that is all maxed: one gold light band crosses its tiles (one band per group, moved by transform: it runs
   off the main thread; the group clips it only while it passes — [data-op2-sw] = the group's turn, 0–3) */
#oc3.op2 .op2-upg .oc3-grp[data-op2-sw] .oc3-units { position: relative; overflow: hidden; }
#oc3.op2 .op2-upg .oc3-grp[data-op2-sw] .oc3-units::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 60%; pointer-events: none; z-index: 1;
  background: linear-gradient(105deg, transparent 20%, color-mix(in srgb, var(--oc3-gold) 38%, transparent) 50%, transparent 80%);
  transform: translateX(-100%);
  animation: op2-band calc(900ms * var(--op2-mk, 1)) cubic-bezier(.45, 0, .25, 1) both;
}
#oc3.op2 .op2-upg .oc3-grp[data-op2-sw="1"] .oc3-units::after { animation-delay: calc(160ms * var(--op2-mk, 1)); }
#oc3.op2 .op2-upg .oc3-grp[data-op2-sw="2"] .oc3-units::after { animation-delay: calc(320ms * var(--op2-mk, 1)); }
#oc3.op2 .op2-upg .oc3-grp[data-op2-sw="3"] .oc3-units::after { animation-delay: calc(480ms * var(--op2-mk, 1)); }
@keyframes op2-band { from { transform: translateX(-100%); } to { transform: translateX(180%); } }

/* ── the last-active dot: a badge on the clock's corner (never moves the line) ── */
#oc3.op2 .op2-la-ic { position: relative; display: inline-flex; flex: none; }
#oc3.op2 .op2-la-dot {
  display: none; position: absolute; right: -2px; bottom: -1px; width: 7px; height: 7px; border-radius: 50%;
  background: var(--oc3-green); box-shadow: 0 0 0 1.5px var(--oc3-card);
}
#oc3.op2 .op2-foot .op2-la-dot { box-shadow: 0 0 0 1.5px var(--oc3-summary); }
#oc3.op2 .op2-la-dot:is([data-st="on"], [data-st="fresh"]) { display: block; }
/* no clock icon (blanked in the admin): the dot stands in its place */
#oc3.op2 .op2-la-ic:not(:has(img, picture, .oc3-emo)) .op2-la-dot { position: static; margin-right: 2px; }
#oc3.op2[data-mo~="dot"] .op2-la-dot[data-st="fresh"] { animation: op2-dot-soft 2.4s ease-out infinite; }
#oc3.op2[data-mo~="dot"] .op2-la-dot[data-st="on"] { animation: op2-dot-on 1.6s ease-out infinite; }
@keyframes op2-dot-soft {
  0% { box-shadow: 0 0 0 1.5px var(--oc3-summary), 0 0 0 1.5px var(--oc3-pulse-ring); }
  70%, 100% { box-shadow: 0 0 0 1.5px var(--oc3-summary), 0 0 0 6px transparent; }
}
@keyframes op2-dot-on {
  0% { box-shadow: 0 0 0 1.5px var(--oc3-summary), 0 0 0 1.5px var(--oc3-green); }
  80%, 100% { box-shadow: 0 0 0 1.5px var(--oc3-summary), 0 0 0 7px transparent; }
}

/* ── loops rest off screen and in a hidden tab ── */
#oc3.op2 [data-op2-off] :is(.oc3-dot, .op2-la-dot), #oc3.op2 [data-op2-off] .oc3-li-bar > i::after,
#oc3.op2[data-op2-hid] :is(.oc3-dot, .op2-la-dot), #oc3.op2[data-op2-hid] .oc3-li-bar > i::after { animation-play-state: paused !important; }

/* ── families switched off (only when the renderer says so: data-mo present) ── */
#oc3.op2[data-mo]:not([data-mo~="bars"]) :is(.oc3-meter, .oc3-li-bar) > i { animation: none !important; }
#oc3.op2[data-mo]:not([data-mo~="shine"]) .oc3-li-bar > i::after { animation: none !important; }
#oc3.op2[data-mo]:not([data-mo~="dot"]) :is(.oc3-dot, .op2-la-dot) { animation: none !important; }
#oc3.op2[data-mo]:not([data-mo~="fb"]) .oc3-tt { animation: none !important; }
#oc3.op2[data-mo]:not([data-mo~="on"]) .op2-jwrap.is-fixed .op2-jump { animation: none; }

/* ── reduced motion: nothing moves, nothing waits ── */
@media (prefers-reduced-motion: reduce) {
  #oc3.op2 *, #oc3.op2 *::before, #oc3.op2 *::after { animation: none !important; transition: none !important; }
  #oc3.op2.op2-mo-arm > *, #oc3.op2.op2-mo-arm > .op2-score > *, #oc3.op2.op2-mo-arm [data-op2-rv],
  #oc3.op2.op2-mo-arm [data-op2-rv] :is(.oc3-meter, .oc3-li-bar) > i { opacity: 1 !important; transform: none !important; }
  #oc3.op2.op2-mo-arm [data-op2-rv] * { opacity: 1 !important; }
  #oc3.op2 .op2-shn { display: none; }
}
/* ── paper: every card whole, every bar full, every figure final ── */
@media print {
  #oc3.op2 *, #oc3.op2 *::before, #oc3.op2 *::after { animation: none !important; transition: none !important; }
  #oc3.op2 > *, #oc3.op2 > .op2-score > *, #oc3.op2 [data-op2-rv], #oc3.op2 [data-op2-rv] * { opacity: 1 !important; }
  #oc3.op2 :is(.oc3-meter, .oc3-li-bar) > i { transform: none !important; }
  #oc3.op2 .op2-shn { display: none; }
}
