RRosternomics

Yankees NYY

GM: Clyde King

Overview

CONTEND → steady
expensive & winning · year 1 in this regime · payroll 1.35× league · TAB +12.5
+12.5TAB — talent above budget3rd/26
+11.8WAB — realized wins (TAB + luck)5th/26
11.0depth — 2+ WAR regulars1st/26
-3.0dead WAR — sub-replacement drag7th/26
19%dead money %4th/26
0.602win %4th/26
50.1roster fWAR2nd/26
-2surplus $M (value vs cost)16th/26
$13Mpayroll $M2nd/26

Roster

CFRickey Henderson 141GHenry Cotto 20GKen Griffey Sr. 5G
LFKen Griffey Sr. 106GBill Sample 51GDan Pasqua 31G
RFDave Winfield 152GDan Pasqua 6GVictor Mata 2G
SSBobby Meacham 155GAndre Robertson 14GDale Berra 6G
2BWillie Randolph 143GRex Hudler 16GJuan Bonilla 7G
3BMike Pagliarulo 134GDale Berra 41GAndre Robertson 33G
1BDon Mattingly 159GRon Hassey 2GKen Griffey Sr. 1G
STARTERSRon Guidry 4.9WARBob Shirley 2.4WAREd Whitson 2.0WARDennis Rasmussen 1.2WARPhil Niekro 1.0WAR
CButch Wynegar 98GRon Hassey 69GJuan Espino 9G
DHDon Baylor 126GDan Pasqua 14GScott Bradley 9G
BULLPEN Dave Righetti 29svBrian Fisher 0hRich Bordi 0hNeil Allen 0hRod Scurry 0hMike Armstrong 0hDon Cooper 0hJohn Montefusco 0h
CButch Wynegar 98 · Ron Hassey 69 · Juan Espino 9
1BDon Mattingly 159 · Ron Hassey 2 · Ken Griffey Sr. 1
2BWillie Randolph 143 · Rex Hudler 16 · Juan Bonilla 7
3BMike Pagliarulo 134 · Dale Berra 41 · Andre Robertson 33
SSBobby Meacham 155 · Andre Robertson 14 · Dale Berra 6
LFKen Griffey Sr. 106 · Bill Sample 51 · Dan Pasqua 31
CFRickey Henderson 141 · Henry Cotto 20 · Ken Griffey Sr. 5
RFDave Winfield 152 · Dan Pasqua 6 · Victor Mata 2
DHDon Baylor 126 · Dan Pasqua 14 · Scott Bradley 9
SPRon Guidry 4.9 · Bob Shirley 2.4 · Ed Whitson 2.0 · Dennis Rasmussen 1.2 · Phil Niekro 1.0
BP Dave Righetti 29 · Brian Fisher 0 · Rich Bordi 0 · Neil Allen 0 · Rod Scurry 0 · Mike Armstrong 0 · Don Cooper 0 · John Montefusco 0

Each position lists its starter then backups by games (so platoons & bench show). Starters (mound) & bullpen (left, foul territory) are ranked by WAR; marks the closer (most save chances). MLB Stats API.

1985 roster — value & surplus

PlayerAgeServiceGfWARSalary $MSurplus $M
Rickey Henderson 26 FA-elig 1439.7 1.5 +1.1
Don Mattingly 24 arb 1596.1 0.5 +1.1
Ron Guidry 34 FA-elig 344.9 0.9 +0.4
Willie Randolph 30 FA-elig 1434.3 0.6 +0.5
Brian Fisher 23 553.1
Dave Winfield 33 FA-elig 1553.0 1.8 -1.0
Dave Righetti 26 FA-elig 742.7 0.7 +0.0
Bob Shirley 31 FA-elig 482.4 0.6 -0.0
Butch Wynegar 29 FA-elig 1022.4 0.6 +0.1
Ed Whitson 30 FA-elig 302.0 0.8 -0.3
Ron Hassey 32 FA-elig 922.0 0.4 +0.1
Rich Bordi 26 501.9
Mike Pagliarulo 25 1381.8
Ken Griffey Sr. 35 FA-elig 1271.6 1.1 -0.6
Dennis Rasmussen 26 221.2
Phil Niekro 46 FA-elig 331.0 0.6 -0.3
Don Baylor 36 FA-elig 1420.8 0.8 -0.6
Dan Pasqua 23 600.6
Andre Robertson 27 500.4
Omar Moreno↔ KCR 32 340.4
Bill Sample 30 FA-elig 590.3 0.4 -0.4
Neil Allen↔ STL 27 FA-elig 170.2 0.3 -0.3
Bobby Meacham 24 pre-arb 1560.1 0.1 -0.1
Juan Espino 29 90.1
Henry Cotto 24 340.0
Dale Murray↔ TEX 35 30.0
Dale Berra 28 FA-elig 480.0 0.5 -0.5
Keith Smith 23 40.0
Rod Scurry↔ PIT 29 arb 5-0.0 0.1 -0.1
Juan Bonilla 29 8-0.1
Don Cooper 29 7-0.1
Mike Armstrong 31 9-0.1
Victor Mata 24 6-0.2
Joe Niekro↔ HOU 40 FA-elig 3-0.2 0.1 -0.1
Marty Bystrom 26 arb 8-0.3 0.2 -0.3
John Montefusco 35 FA-elig 3-0.3 0.6 -0.7
Scott Bradley 25 19-0.4
Rex Hudler 24 20-0.4
Joe Cowley 26 arb 30-0.8 0.1 -0.3

Key additions (new vs 1984)

PlayerfWAR
Rickey Henderson9.7
Don Mattingly6.1
Ron Guidry4.9
Willie Randolph4.3
Brian Fisher3.1
Dave Winfield3.0

Key subtractions (gone from 1984)

Player1984 fWAR

Current & Historical Payroll

1985 payroll
$13.3M

What the front office was committed to as of 1985, 1985–1991. Pre-2015 has no contract-terms data — forward italic $ are realized actuals (hindsight, not commitments known then). Control labels (ARB/FA) are point-in-time.

current $ guaranteed $ actual $ (hindsight) arbitration (proj) pre-arb (proj) free agent

Guaranteed / signed (18)

PlayerAgeSvc1985198619871988198919901991
Dave Winfield3312.000$1.8M$1.9M$1.9M$2.0MFREE AGENT$1.7M
Rickey Henderson266.000$1.5M$1.6M$1.7M$1.8M$1.2MFREE AGENT
Ken Griffey Sr.3512.000$1.1M$604kFREE AGENT
Ron Guidry3410.000$900k$975k$850k$825kFREE AGENT
Don Baylor3615.000$810kFREE AGENT
Ed Whitson308.000$800k$439kFREE AGENT
Dave Righetti266.000$680k$838k$800k$1.3M$1.4M$1.6MFREE AGENT
Bob Shirley318.000$638k$750k$200kFREE AGENT
John Montefusco3511.000$638k$717kFREE AGENT
Phil Niekro4621.000$600kFREE AGENT
Willie Randolph3010.000$600k$1.1M$900k$875kFREE AGENT
Butch Wynegar299.000$550k$733kFREE AGENT
Dale Berra288.000$478k$558kFREE AGENT
Bill Sample307.000$435kFREE AGENT
Ron Hassey327.000$425k$227kFREE AGENT
Neil Allen276.000$319kFREE AGENT$815k$250k
Joe Niekro4018.000$71k$750k$545kFREE AGENT
Omar Moreno3210.000FREE AGENT

Arbitration-eligible (7)

PlayerAgeSvc1985198619871988198919901991
Don Mattingly243.000$455kARB 2ARB 3FREE AGENT
Marty Bystrom265.000$250kFREE AGENT
Joe Cowley263.000$120kARB 2ARB 3FREE AGENT
Rod Scurry295.000$50kFREE AGENT
Juan Bonilla294.000ARB 3FREE AGENT
Rich Bordi265.000FREE AGENT
Juan Espino293.000ARB 2ARB 3FREE AGENT

Pre-arbitration (14)

PlayerAgeSvc1985198619871988198919901991
Bobby Meacham242.000$100kARB 1ARB 2ARB 3FREE AGENT
Mike Armstrong31
Scott Bradley251.000Pre-ArbARB 1ARB 2ARB 3FREE AGENT
Don Cooper29
Henry Cotto241.000Pre-ArbARB 1ARB 2ARB 3FREE AGENT
Brian Fisher230.000Pre-ArbPre-ArbARB 1ARB 2ARB 3FREE AGENT
Rex Hudler241.000Pre-ArbARB 1ARB 2ARB 3FREE AGENT
Victor Mata24
Dale Murray35
Mike Pagliarulo251.000Pre-ArbARB 1ARB 2ARB 3FREE AGENT
Dan Pasqua230.000Pre-ArbPre-ArbARB 1ARB 2ARB 3FREE AGENT
Dennis Rasmussen262.000ARB 1ARB 2ARB 3FREE AGENT
Andre Robertson27
Keith Smith23

Graphs

Every roster slot ranked best→worst by WAR. Bars = Yankees 1985; the black line = the league-average player at each slot that season. Staying above the line deep into the roster is the depth edge; dropping below it = holes & dead weight.

What each regime is worth — every settled team-season since 1985

RegimeSeasonsWin %Playoff %Pennant %WS %
WINDOW 28952.230.14.81.0
CONTEND 31156.863.019.310.3
FORCED-SPEND 26047.98.81.21.2
REBUILD 32843.31.20.30.3
const FONT={family:"'Roboto Mono', monospace",size:12}; const ORBIT = [[1985, 1.352, 12.53], [1986, 1.402, 5.33], [1987, 1.533, -3.16], [1988, 1.649, -8.48], [1989, 1.029, -2.54], [1990, 1.173, -15.29], [1991, 1.143, -10.09], [1992, 1.109, 0.62], [1993, 1.381, 6.52], [1994, 1.436, 12.5], [1995, 1.58, -0.14], [1996, 1.512, 2.43], [1997, 1.605, 6.43], [1998, 1.588, 17.45], [1999, 1.803, 5.82], [2000, 1.888, -3.47], [2001, 1.882, 2.14], [2002, 2.002, 13.92], [2003, 2.112, 11.88], [2004, 2.76, -6.07], [2005, 2.884, -14.29], [2006, 2.544, -3.91], [2007, 2.523, 2.09], [2008, 2.484, -6.98], [2009, 2.281, 9.29], [2010, 2.38, 3.28], [2011, 2.079, 11.29], [2012, 2.121, 7.41], [2013, 2.304, -15.17], [2014, 2.004, -7.44], [2015, 1.794, -2.14], [2016, 1.742, -7.29], [2017, 1.43, 13.9], [2018, 1.224, 16.54], [2019, 1.67, 8.1], [2021, 1.736, -0.91], [2022, 1.725, 14.19], [2023, 1.693, -12.33], [2024, 1.823, 7.16], [2025, 1.578, 10.87], [2026, 1.702, 6.42]], TEAMCOL = '#1A2B5E'; function contrastColor(hex,dark){let r=parseInt(hex.slice(1,3),16)/255,g=parseInt(hex.slice(3,5),16)/255,b=parseInt(hex.slice(5,7),16)/255; const mx=Math.max(r,g,b),mn=Math.min(r,g,b);let h=0,s=0,l=(mx+mn)/2; if(mx!==mn){const d=mx-mn;s=l>0.5?d/(2-mx-mn):d/(mx+mn);h=mx===r?(g-b)/d+(g1)t-=1;if(t<1/6)return p+(q-p)*6*t;if(t<0.5)return q;if(t<2/3)return p+(q-p)*(2/3-t)*6;return p;} let R,G,B;if(s===0){R=G=B=L;}else{const q=L<0.5?L*(1+s):L+s-L*s,p=2*L-q;R=h2(p,q,h+1/3);G=h2(p,q,h);B=h2(p,q,h-1/3);} const x=v=>('0'+Math.round(v*255).toString(16)).slice(-2);return '#'+x(R)+x(G)+x(B);} const CURRENT_YEAR = 1985; function drawOrbit(){ const orbEl=document.getElementById('orbit'); if(!ORBIT || ORBIT.length<2){ orbEl.innerHTML='

Not enough history to chart.

'; return; } const f=+document.getElementById('yfrom').value, t=+document.getElementById('yto').value, w=+document.getElementById('win').value; document.getElementById('yflab').textContent=f; document.getElementById('ytlab').textContent=t; document.getElementById('winlab').textContent = w===1?'raw':(w+'-yr'); const dark=document.documentElement.getAttribute('data-theme')==='dark'; const ink=dark?'#cdd4dc':'#1d2630', grid=dark?'#2c313a':'#d6dbe2', refc=dark?'#5a636d':'#9aa3ad', dirc=dark?'#ffffff':'#1d2630'; const col=contrastColor(TEAMCOL,dark); function sm(a,w){const h=(w-1)/2,o=[];for(let i=0;id[0]>=f&&d[0]<=t); if(raw.length<2){ Plotly.purge('orbit'); orbEl.innerHTML='

Pick a wider year range.

'; return; } const s=sm(raw,w),n=s.length,X=s.map(d=>Math.round(d[1]*100)/100),Y=s.map(d=>Math.round(d[2]*10)/10),yr=s.map(d=>d[0]); let xa=Math.min(1,...X),xb=Math.max(1,...X),ya=Math.min(0,...Y),yb=Math.max(0,...Y); const px=(xb-xa)*.12+.04,py=(yb-ya)*.12+1.5;xa-=px;xb+=px;ya-=py;yb+=py; const k=Math.max(0,n-3), ann=[]; [['WINDOW','#15b6a0',xa<1&&yb>0,xa,yb,'left','top'],['CONTEND','#2f7ed8',xb>1&&yb>0,xb,yb,'right','top'], ['FORCED-SPEND','#ec5a3c',xb>1&&ya<0,xb,ya,'right','bottom'],['REBUILD','#f0a91c',xa<1&&ya<0,xa,ya,'left','bottom']].forEach(q=>{ if(q[2]) ann.push({x:q[3],y:q[4],xref:'x',yref:'y',text:q[0],showarrow:false,xanchor:q[5],yanchor:q[6],font:{size:10,color:q[1]},opacity:.85});}); ann.push({x:X[n-1],y:Y[n-1],ax:X[n-1]-0.5*(X[n-1]-X[k]),ay:Y[n-1]-0.5*(Y[n-1]-Y[k]),xref:'x',yref:'y',axref:'x',ayref:'y',showarrow:true,arrowhead:2,arrowsize:1.3,arrowwidth:1.7,arrowcolor:dirc,text:''}); Plotly.newPlot('orbit',[{x:X,y:Y,mode:'lines+markers',line:{color:col,width:2.6,shape:'spline',smoothing:0.7}, marker:{color:col,size:s.map((d,i)=>5+7*(i/Math.max(1,n-1))),line:{color:dark?'#1b1e23':'#fff',width:0.6}}, text:yr,hovertemplate:'%{text}
payroll %{x:.2f}× lg · TAB %{y:+.1f}
'+(w===1?'single season (raw)':w+'-yr smoothed avg')+''}], {margin:{l:50,r:14,t:10,b:40},paper_bgcolor:'rgba(0,0,0,0)',plot_bgcolor:'rgba(0,0,0,0)',font:FONT, xaxis:{title:{text:'relative payroll (× lg avg)',font:{size:11}},range:[xa,xb],gridcolor:grid,zeroline:false}, yaxis:{title:{text:'TAB (talent above budget)',font:{size:11}},range:[ya,yb],gridcolor:grid,zeroline:false}, shapes:[{type:'line',x0:1,x1:1,y0:ya,y1:yb,line:{color:refc,width:1,dash:'dot'}},{type:'line',x0:xa,x1:xb,y0:0,y1:0,line:{color:refc,width:1,dash:'dot'}}], annotations:ann},{displayModeBar:false,responsive:true}); } (function initOrbitSliders(){ const yf=document.getElementById('yfrom'), yt=document.getElementById('yto'); if(ORBIT && ORBIT.length>=2){ const yrs=ORBIT.map(d=>d[0]), y0=Math.min(...yrs), y1=Math.max(...yrs); yf.min=y0; yf.max=y1; yf.value=y0; yt.min=y0; yt.max=y1; yt.value=Math.max(y0, Math.min(CURRENT_YEAR, y1)); yf.addEventListener('input',()=>{ if(+yf.value>+yt.value) yt.value=yf.value; drawOrbit(); }); yt.addEventListener('input',()=>{ if(+yt.value<+yf.value) yf.value=yt.value; drawOrbit(); }); document.getElementById('win').addEventListener('input',drawOrbit); } // only paint on load if the orbit pane is the visible default (else it'd draw into a 0-width hidden box) const _op=document.querySelector('.gpane[data-g="orbit"]'); if(!_op || _op.style.display!=='none') drawOrbit(); })(); new MutationObserver(()=>{ const p=document.querySelector('.gpane[data-g="orbit"]'); if(!p || p.style.display!=='none') drawOrbit(); }).observe(document.documentElement,{attributes:true,attributeFilter:['data-theme']}); // ---- roster depth curve (WAR by roster slot vs league-average-by-slot) ---- const WARDIST = {"cats": ["OF", "IF", "SP", "IF", "RP", "OF", "RP", "RP", "C", "SP", "C", "RP", "IF", "OF", "SP", "SP", "IF", "OF", "IF", "OF", "OF", "RP", "IF", "C", "OF", "RP", "IF", "IF", "RP", "IF", "RP", "RP", "OF", "SP", "SP", "RP", "C", "IF", "SP", "\u2014"], "league": [5.82, 4.37, 3.6, 3.22, 2.71, 2.52, 2.21, 1.99, 1.8, 1.51, 1.32, 1.19, 1.03, 0.88, 0.77, 0.62, 0.51, 0.42, 0.31, 0.25, 0.17, 0.11, 0.07, 0.03, -0.0, -0.03, -0.07, -0.11, -0.13, -0.17, -0.21, -0.26, -0.34, -0.35, -0.39, -0.5, -0.52, -0.57, -0.51, -0.63], "names": ["Rickey Henderson", "Don Mattingly", "Ron Guidry", "Willie Randolph", "Brian Fisher", "Dave Winfield", "Dave Righetti", "Bob Shirley", "Butch Wynegar", "Ed Whitson", "Ron Hassey", "Rich Bordi", "Mike Pagliarulo", "Ken Griffey Sr.", "Dennis Rasmussen", "Phil Niekro", "Don Baylor", "Dan Pasqua", "Andre Robertson", "Omar Moreno", "Bill Sample", "Neil Allen", "Bobby Meacham", "Juan Espino", "Henry Cotto", "Dale Murray", "Dale Berra", "Keith Smith", "Rod Scurry", "Juan Bonilla", "Don Cooper", "Mike Armstrong", "Victor Mata", "Joe Niekro", "Marty Bystrom", "John Montefusco", "Scott Bradley", "Rex Hudler", "Joe Cowley", "(empty slot)"], "ranks": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40], "team": [9.72, 6.05, 4.87, 4.26, 3.09, 3.03, 2.72, 2.38, 2.37, 2.04, 2.01, 1.87, 1.79, 1.65, 1.19, 1.04, 0.79, 0.59, 0.43, 0.4, 0.28, 0.23, 0.15, 0.06, 0.05, 0.03, 0.0, 0.0, -0.03, -0.07, -0.11, -0.13, -0.19, -0.25, -0.31, -0.32, -0.43, -0.43, -0.77, 0.0]}; let WD_MODE='raw', WC_MODE='team'; const POSCOL={SP:'#2f7ed8',RP:'#6fb1ec',IF:'#f0a91c',OF:'#15b6a0',C:'#ec5a3c'}; const POSLAB={SP:'Starting P',RP:'Bullpen',IF:'Infield',OF:'Outfield',C:'Catcher'}; function buildPosLegend(){ const el=document.getElementById('poslegend'); if(!el) return; el.style.display=WC_MODE==='pos'?'flex':'none'; el.innerHTML=['SP','RP','C','IF','OF'].map(k=>''+POSLAB[k]+'').join(''); } function drawWarDist(){ if(!WARDIST) return; const dark=document.documentElement.getAttribute('data-theme')==='dark'; const col=contrastColor(TEAMCOL,dark), line=dark?'#e8eef0':'#111', grid=dark?'#2c313a':'#d6dbe2', ink=dark?'#cdd4dc':'#1d2630'; let team=WARDIST.team.slice(), league=WARDIST.league.slice(); if(WD_MODE==='prop'){ const ts=team.reduce((a,b)=>a+Math.max(b,0),0)||1, ls=league.reduce((a,b)=>a+Math.max(b,0),0)||1; team=team.map(v=>v/ts); league=league.map(v=>v/ls); } const fmt=WD_MODE==='prop'?'.1%':'.1f'; const names=WARDIST.names||[], cats=WARDIST.cats||[]; const cd=WARDIST.ranks.map((_,i)=>[names[i]||'(empty slot)', WARDIST.team[i], POSLAB[cats[i]]||'']); const barcol=WC_MODE==='pos'?cats.map(c=>POSCOL[c]||'#9aa3ad'):col; const posbit=WC_MODE==='pos'?' · %{customdata[2]}':''; const htmpl=WD_MODE==='prop' ? '%{customdata[0]}'+posbit+'
slot %{x} · %{customdata[1]:.1f} WAR
%{y:.1%} of roster WAR' : '%{customdata[0]}'+posbit+'
slot %{x} · %{y:.1f} WAR'; buildPosLegend(); const _div=document.getElementById('wardist'); const traces=[ {type:'bar',x:WARDIST.ranks,y:team,name:'NYY',marker:{color:barcol},customdata:cd,hovertemplate:htmpl}, {type:'scatter',x:WARDIST.ranks,y:league,name:'league avg',mode:'lines',line:{color:line,width:2,shape:'spline',smoothing:0.6},hovertemplate:'league slot %{x}: %{y:'+fmt+'}'} ]; const layout={margin:{l:48,r:12,t:6,b:38},paper_bgcolor:'rgba(0,0,0,0)',plot_bgcolor:'rgba(0,0,0,0)',font:FONT, transition:{duration:360,easing:'cubic-in-out'}, xaxis:{title:{text:'roster slot (ranked by WAR)',font:{size:11}},gridcolor:grid,zeroline:false,color:ink}, yaxis:{title:{text:WD_MODE==='prop'?'share of roster WAR':'WAR',font:{size:11}},gridcolor:grid,zeroline:true,zerolinecolor:grid,color:ink,tickformat:WD_MODE==='prop'?'.0%':undefined}, showlegend:true,legend:{orientation:'h',y:1.13,x:0,font:{size:11}},bargap:0.14}; if(_div.data&&_div.data.length){ Plotly.react(_div,traces,layout,{displayModeBar:false,responsive:true}); } else { Plotly.newPlot(_div,traces,layout,{displayModeBar:false,responsive:true}); } } window.wdMode=function(m){WD_MODE=m;document.getElementById('wd-raw').classList.toggle('on',m==='raw');document.getElementById('wd-prop').classList.toggle('on',m==='prop');drawWarDist();}; window.wcToggle=function(){WC_MODE=WC_MODE==='pos'?'team':'pos';const b=document.getElementById('wc-btn');b.classList.toggle('on',WC_MODE==='pos');b.textContent=WC_MODE==='pos'?'Show team color':'Color by position';drawWarDist();}; // ---- Graphs dropdown switcher (orbit ⇄ roster value distribution) ---- let _wdRendered=false; window.showTeamGraph=function(g){ document.querySelectorAll('.gpane').forEach(p=>{ p.style.display=(p.dataset.g===g)?'':'none'; }); if(g==='orbit'){ drawOrbit(); } else if(g==='roster'){ if(!_wdRendered){ drawWarDist(); _wdRendered=true; } else { try{ Plotly.Plots.resize('wardist'); }catch(e){ drawWarDist(); } } } }; { const _ts=document.getElementById('tgsel'); if(_ts) _ts.addEventListener('change',()=>showTeamGraph(_ts.value)); } // initial paint of the default pane (roster when the team has roster data, else orbit already drawn above) if(WARDIST){ drawWarDist(); _wdRendered=true; } // redraw the roster pane on theme change only if it's been rendered and is visible if(WARDIST){ new MutationObserver(()=>{ const p=document.querySelector('.gpane[data-g="roster"]'); if(_wdRendered && p && p.style.display!=='none') drawWarDist(); }).observe(document.documentElement,{attributes:true,attributeFilter:['data-theme']}); } // ---- TOC scroll-spy ---- (function(){ const links=[...document.querySelectorAll('.toc a')]; const secs=links.map(a=>document.querySelector(a.getAttribute('href'))).filter(Boolean); links.forEach(a=>a.addEventListener('click',e=>{e.preventDefault();document.querySelector(a.getAttribute('href')).scrollIntoView({behavior:'smooth'});})); if('IntersectionObserver' in window && secs.length){ const obs=new IntersectionObserver(es=>{es.forEach(e=>{if(e.isIntersecting) links.forEach(l=>l.classList.toggle('on',l.getAttribute('href')==='#'+e.target.id));});},{rootMargin:'-15% 0px -75% 0px'}); secs.forEach(s=>obs.observe(s)); } })(); // ---- sortable roster table ---- const SVC_RANK={'pre-arb':0,'arb':1,'FA-elig':2,'?':3}; function cellNum(td){const n=parseFloat(td.textContent.replace(/[^0-9.\-]/g,''));return isNaN(n)?null:n;} function scale(v,mn,mx,g){ if(g==='diverge'){ if(v>=0){const t=mx>0?v/mx:0;return `rgba(26,125,90,${(0.10+0.55*t).toFixed(2)})`;} const t=mn<0?v/mn:0;return `rgba(192,73,43,${(0.10+0.55*t).toFixed(2)})`; } if(g==='salmag'){const t=mx>mn?(v-mn)/(mx-mn):0;return `rgba(128,135,143,${(0.05+0.45*t).toFixed(2)})`;} const t=mx>mn?(v-mn)/(mx-mn):0;return `rgba(26,125,90,${(0.05+0.55*t).toFixed(2)})`; } function applyGradients(table){ [...table.tHead.rows[0].cells].forEach((th,ci)=>{ if(!th.dataset.grad) return; const rows=[...table.tBodies[0].rows], vals=rows.map(r=>cellNum(r.cells[ci])).filter(v=>v!==null); if(!vals.length) return; const mn=Math.min(...vals),mx=Math.max(...vals); rows.forEach(r=>{const v=cellNum(r.cells[ci]);if(v!==null)r.cells[ci].style.background=scale(v,mn,mx,th.dataset.grad);}); }); } function makeSortable(table){ const ths=[...table.tHead.rows[0].cells]; ths.forEach((th,ci)=>{ th.dataset.label=th.textContent.trim(); th.addEventListener('click',()=>{ th._dir=(th._dir===-1)?1:-1; const dir=th._dir, tb=table.tBodies[0], svc=th.dataset.sortType==='service'; [...tb.rows].sort((a,b)=>{ let va,vb; if(svc){va=SVC_RANK[a.cells[ci].textContent.trim()]??9;vb=SVC_RANK[b.cells[ci].textContent.trim()]??9;} else{va=cellNum(a.cells[ci]);vb=cellNum(b.cells[ci]); if(va===null||vb===null){va=a.cells[ci].textContent.trim().toLowerCase();vb=b.cells[ci].textContent.trim().toLowerCase();}} return vavb?dir:0; }).forEach(r=>tb.appendChild(r)); ths.forEach(h=>h.innerHTML=h.dataset.label); th.innerHTML=th.dataset.label+' '+(dir===1?'▲':'▼')+''; }); }); } document.querySelectorAll('table.sortable').forEach(t=>{applyGradients(t);makeSortable(t);});