Files
bastion-frontend/assets/js/app.js
2026-07-22 15:38:00 +03:00

510 lines
58 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const sections = [
{id:'details', title:'Реквизиты организации и контактная информация', image:'assets/pictures/Реквизиты организации и контактная информация.png'},
{id:'legal', title:'Правовой статус/НПА', image:'assets/pictures/Правовой статус.png'},
{id:'about', title:'Информация (краткая справка, историческая справка)', image:'assets/pictures/Информация.png'},
{id:'finance', title:'Финансовые показатели', image:'assets/pictures/Финансовые показатели.png'},
{id:'ownership', title:'Структура собственности', image:'assets/pictures/Структура.png'},
{id:'activity', title:'Виды деятельности', image:'assets/pictures/Вид деятельности.png'},
{id:'stability', title:'Финансовая устойчивость', image:'assets/pictures/Финансовая устойчивость.png'}
];
const expandIcon = `<img class="ui-icon" src="assets/pictures/open.png" alt="">`;
const collapseIcon = `<img class="ui-icon" src="assets/pictures/close.png" alt="">`;
const detailsIcon = `<img class="ui-icon" src="assets/pictures/pointer.png" alt="">`;
const kv = (pairs) => `<div class="kv">${pairs.map(([a,b])=>`<span>${a}</span><span>${b}</span>`).join('')}</div>`;
const expand = s => `<button class="expand-btn" data-image="${s.image}" data-title="${s.title}">Развернуть ${expandIcon}</button>`;
const chart = (title,value,unit,values,max,ticks) => `<div class="chart"><div class="chart-title">${title}<br><b>2025 г.&nbsp;&nbsp; ${value}</b></div><div class="chart-plot"><div class="y-axis"><span class="axis-unit">${unit}</span>${ticks.map(t=>`<span>${t}</span>`).join('')}</div><div class="bars">${values.map((v,i)=>{const year=2017+i;const label=String(v).replace('.',',');return `<button class="bar-item" type="button" style="--h:${Math.max(4,v/max*100)}%" data-year="${year}" data-value="${label} ${unit}" aria-label="${year}: ${label} ${unit}"><span class="bar-tooltip"><b>${year}</b><span>${label} ${unit}</span></span></button>`}).join('')}</div></div></div>`;
const smoothLine=points=>points.length===1?`M ${points[0].x} ${points[0].y}`:points.slice(1).reduce((path,next,i)=>{const current=points[i],middle=(current.x+next.x)/2;return `${path} C ${middle} ${current.y}, ${middle} ${next.y}, ${next.x} ${next.y}`},`M ${points[0].x} ${points[0].y}`);
const lineChart=(title,unit,data,min,max,ticks,color,emptyNote='')=>{const left=76,right=944,top=45,bottom=282,width=right-left,height=bottom-top,yFor=value=>bottom-(value-min)/(max-min)*height,slots=data.map((d,i)=>({x:left+i/(data.length-1)*width,...d})),segments=[];let current=[];slots.forEach(slot=>{if(Number.isFinite(slot.value)){current.push({...slot,y:yFor(slot.value)})}else if(current.length){segments.push(current);current=[]}});if(current.length)segments.push(current);const points=segments.flat(),zero=min<0&&max>0?yFor(0):bottom,paths=segments.map(segment=>{const line=smoothLine(segment),area=segment.length>1?`${line} L ${segment.at(-1).x} ${zero} L ${segment[0].x} ${zero} Z`:'';return `${area?`<path class="line-area" d="${area}"/>`:''}${segment.length>1?`<path class="line-curve" d="${line}"/>`:''}`}).join('');return `<div class="line-chart" style="--chart-color:${color}"><h3>${title}</h3><svg viewBox="0 0 1000 335" role="img" aria-label="${title} за 20172026 годы"><text class="line-unit" x="18" y="22">${unit}</text>${ticks.map(t=>{const y=yFor(t.value);return `<line class="line-grid" x1="${left}" y1="${y}" x2="${right}" y2="${y}"/><text class="line-y-label" x="64" y="${y+4}">${t.label}</text>`}).join('')}${slots.map(p=>`<line class="line-grid vertical" x1="${p.x}" y1="${top}" x2="${p.x}" y2="${bottom}"/>`).join('')}${paths}${slots.map(p=>`<text class="line-x-label" x="${p.x}" y="315">${p.year}</text>`).join('')}${points.map(p=>`<g class="line-point" role="button" tabindex="0" data-year="${p.year}" data-value="${p.label}" aria-label="${p.year}: ${p.label}"><circle class="line-hit" cx="${p.x}" cy="${p.y}" r="18"/><circle cx="${p.x}" cy="${p.y}" r="6"/><g class="line-tooltip" transform="translate(${p.x} ${Math.max(47,p.y-18)})"><rect x="-68" y="-48" width="136" height="39" rx="8"/><text x="0" y="-32">${p.year}</text><text x="0" y="-17">${p.label}</text></g></g>`).join('')}${slots.filter(p=>!Number.isFinite(p.value)).map(p=>`<g class="line-missing"><circle cx="${p.x}" cy="${bottom}" r="5"/><title>${p.year}: ${p.label||'нет данных'}</title></g>`).join('')}${emptyNote?`<text class="line-empty-note" x="510" y="165">${emptyNote}</text>`:''}</svg></div>`};
const historyText = `4 февраля 1914 года открыло свои действия "Российское Акционерное Общество Оптического и Механического Производств". С этой даты началась история первой и на сегодняшний день крупнейшей российской компании, которая производит оптико-механические и оптико-электронные приборы.
Экспозиция Музея истории ЛОМО располагается в помещении площадью 200 кв. м и содержит экспонаты, отражающие все этапы почти вековой истории фирмы - приборы, фотографии, письменные документы. Отдельные витрины посвящены периоду становления завода (1914-1917 гг.), годам Гражданской войны (1917-1922 гг.), индустриализации (20-30-е гг.), военному периоду (1941-1945 гг.), послевоенному восстановлению и развитию (1945-1962 гг.), работе фирмы после объединения (60-80-е гг.) и в новых экономических условиях. Из продукции фирмы в экспозиции Музея большое место занимают изделия оборонного назначения, дифракционные решетки, приборы для авиации, медицинское оборудование, кино- и фототехника, наблюдательные приборы.
В 1918 году предприятие было национализировано. Пережив трудные годы Гражданской войны, завод продолжил выпуск оптических приборов. Предприятие, получившее в 1930 году имя ГОМЗ (Государственный оптико-механический завод), успешно развивалось, осваивая все новые и новые направления оптического приборостроения.
В годы войны завод серьезно пострадал, но ни на один день не прекращал выпуск продукции - прежде всего остро необходимых фронту военных приборов. После 1945 года он был в короткие сроки восстановлен и вскоре вновь стал процветающим, динамично растущим производственным организмом.
2 октября 1962 года на базе ГОМЗа и еще нескольких родственных предприятий, в том числе заводов "КИНАП" и "Прогресс", имевших свою славную историю, было создано Ленинградское объединение оптико-механических производств (ЛООМП), получившее в 1965 году свое всемирно известное имя ЛОМО (Ленинградское оптико-механическое объединение). Генеральным директором фирмы стал М.П. Панфилов, с именем которого напрямую связаны многие успехи предприятия. Образование объединения позволило ленинградским оптикам выйти на качественно новый уровень, сохранив и приумножив существовавшие богатые традиции.
В течение 60-80-х гг. имя ЛОМО стало символом успеха и процветания. Благодаря концентрации и специализации производства, умелому управлению и незамедлительному внедрению всех технических новинок Объединение являлось одним из образцовых предприятий СССР. Непростые времена для ЛОМО, как и для всей отечественной промышленности, наступили на рубеже 80-90-х гг., когда крупномасштабные перемены в жизни страны поставили фирму в новые условия. В 1993 году она была приватизирована, став открытым акционерным обществом "ЛОМО". Благодаря сочетанию новых подходов и старых традиций фирма сумела с честью пройти сквозь все испытания и сохранить свой производственный и научный потенциал.
Продукция ЛОМО относится к высокотехнологичным изделиям. Многие приборы, изготовленные на фирме, были первыми в своих направлениях и помогали развитию новых отраслей науки и техники. Здесь в 1918 году был создан первый отечественный кинопроекционный аппарат "Русь". В 1930 году было начато серийное производство первого в СССР массового любительского фотоаппарата "Фотокор N1". С тех пор предприятие выпустило свыше 40 млн. фотоаппаратов - из них более 20 млн. модели "Смена-8М", занесенной в книгу рекордов Гиннеса как самый массовый фотоаппарат планеты. В 30-е годы была создана первая киносъемочная камера КС-1. Перед войной было освоено производство различных микроскопов, а в 1939 году созданы первая ручная киносъемочная камера КС-5 для хроникальных съемок и камера ЦКС-1 для съемки цветных фильмов. Эти изделия оказали неоценимую помощь в создании отечественной кинохроники, в том числе и в годы Великой Отечественной войны.
После войны активно развивается появившееся еще в 30-е годы направление создания астрофизических приборов. Одним из первых в 1947 году был построен астрограф для Пулковской обсерватории. Продолжается создание новых типов микроскопов, в том числе для исследований в ультрафиолетовых лучах, для высокоточных измерений в ядерных фотоэмульсиях. В 1958 году на Всемирной выставке в Брюсселе микроскопы МЛ-1, МБИ-6, МБИ-8М и МИН-8 были отмечены Гран-при, а высокотемпературные микроскопы УВТ-1 - золотой медалью.
Почти все кинотеатры в бывшем Советском Союзе были оборудованы кинопроекторами для широкоформатного кино производства ЛОМО. В 1959 году здесь создан первый видеомагнитофон, который коренным образом изменил технологию подготовки телевизионных передач и телевизионного вещания.
Введение в эксплуатацию в 1960 году самого крупного в Европе телескопа ЗТШ с диаметром зеркала 2,6 м, а в 1976 году - крупнейшего в мире Большого Азимутального Телескопа (БТА) с монолитным главным зеркалом диаметром 6 м вывели отечественную астрофизику на передовые рубежи. Сегодня ведутся работы по созданию космических телескопов, первый из которых успешно прошел летные испытания в 1997 году.
В 1965 году на ЛОМО был создан первый в СССР промышленный лазер, а в конце 70-х - первый отечественный гибкий медицинский эндоскоп. В 90-е гг. на фирме появился целый ряд новых направлений - таких, как наблюдательные приборы, оптико-электронные системы для подсчета голосов избирателей, светодиодные светофоры, приборы для обеспечения безопасности взлета и посадки самолетов.
Даже в условиях экономического кризиса ЛОМО удалось не только сохранить свои позиции на отечественном рынке, но и успешно конкурировать с лучшими зарубежными производителями. Так, микроскопы петербургской фирмы в 1997 году победили в тендере ООН в Ираке, а эндоскопы в 1998 году - в тендере МБРР в России.
В последние годы ЛОМО активно занимается продвижением своей продукции на мировые рынки сбыта. Примерно 50% объема продаж компании составляют экспортные поставки. Зарубежный спрос на продукцию ЛОМО обеспечивается хорошим качеством изделий при достаточно низкой для потребительского рынка развитых стран цене. Сегодня продукция ЛОМО продается в 56 странах мира, среди которых США, Великобритания, Австрия, Япония, Германия, Австралия и др.
Эти усилия не остались незамеченными. В течение последних двух лет ЛОМО было награждено восемью призами от международных общественных организаций из Испании, Франции, США, Бельгии, Мексики за качество, коммерческий престиж, динамику производства и эффективный менеджмент. По данным известного делового журнала "Бизнес-Уик" ЛОМО два года подряд входит в десятку наиболее активных и стабильно развивающихся российских компаний.
Сегодня ЛОМО - один из лидеров российского оптического приборостроения, крупная высокотехнологичная компания, устремленная в будущее.`;
const historyHtml = historyText.split('\n').map(p=>`<p>${p}</p>`).join('');
const owners = [
{value:29.328, display:'29,328%', sector:'29,33%', color:'#c6daf7', name:'Ильичев В.В. (канд. юрид. наук)'},
{value:21.505, display:'21,505%', sector:'21,5%', color:'#82b7ed', name:'(!) ООО "Вирибус"'},
{value:17.370, display:'17,370%', sector:'17,37%', color:'#3b9ddd', name:'(!) ЗАО "Финансовый брокер БОСИ"'},
{value:9.055, display:'9,055%', sector:'9,06%', color:'#247bb1', name:'Аронов А.М. (д-р экон. наук, канд. техн. наук, проф., википедия)'},
{value:8.428, display:'8,428%', sector:'8,43%', color:'#1d6b98', name:'(!) ООО "Ракурс"'},
{value:3.226, display:'3,226%', sector:'3,2%', color:'#0b3858', name:'(!) ЗАО "БОСИ-Тренд"'},
{value:2.736, display:'2,736%', sector:'2,7%', color:'#d7e9f4', name:'Номинальный держатель акций аффилированного лица'},
{value:6.340, display:'6,340%', sector:'6,34%', color:'#5795c2', name:'неизвестные и/или миноритарные акционеры'}
];
const polar=(r,angle)=>({x:180+r*Math.cos(angle*Math.PI/180),y:180+r*Math.sin(angle*Math.PI/180)});
const donutPath=(start,end)=>{const o1=polar(146,start),o2=polar(146,end),i2=polar(79,end),i1=polar(79,start),large=end-start>180?1:0;return `M ${o1.x} ${o1.y} A 146 146 0 ${large} 1 ${o2.x} ${o2.y} L ${i2.x} ${i2.y} A 79 79 0 ${large} 0 ${i1.x} ${i1.y} Z`};
const donutSvg=()=>{
const total=owners.reduce((sum,owner)=>sum+owner.value,0);
let angle=18;
const parts=owners.map((owner,index)=>{
const start=angle;
const end=angle+owner.value/total*360;
const middle=(start+end)/2;
const labelRadius=index===5?118:index===6?114:113;
const labelShift=index===5?4:index===6?4:index===7?6:0;
const label=polar(labelRadius,middle);
const dx=Math.cos(middle*Math.PI/180)*13;
const dy=Math.sin(middle*Math.PI/180)*13;
angle=end;
return {owner,index,start,end,label,dx,dy,labelShift};
});
const sectors=parts.map(({owner,index,start,end,dx,dy})=>`<g class="donut-sector" role="button" tabindex="0" data-owner="${index}" style="--dx:${dx.toFixed(2)}px;--dy:${dy.toFixed(2)}px" aria-label="${owner.display} ${owner.name}"><path d="${donutPath(start,end)}" fill="${owner.color}"/></g>`).join('');
const labels=parts.map(({owner,index,label,dx,dy,labelShift})=>`<text class="donut-label" data-owner="${index}" style="--dx:${dx.toFixed(2)}px;--dy:${dy.toFixed(2)}px" x="${label.x.toFixed(2)}" y="${(label.y+labelShift).toFixed(2)}">${owner.sector}</text>`).join('');
return `<svg class="ownership-donut" viewBox="0 0 360 360" aria-label="Структура акционеров">${sectors}<circle class="donut-center" cx="180" cy="180" r="78"/>${labels}</svg>`;
};
const participation=[
['100,000% (!)','ООО "Сбытовая Энергетическая Компания"'],
['85,000% (!)','ООО "Мехпроф"'],
['80,000% (!)','ООО "ЛОМО МЕТЕО"'],
['60,000% (!)','ООО "ЛОМО-Микросистемы"'],
['51,000% (!)','ЗАО "ЛОМО ЛАЗЕР"'],
['25,000% (!)','ООО "Ломо Фотоника Плюс"'],
['15,000% (!)','ООО "ПЕТРО-ЛОМО"'],
['4,000% (!)','ООО "Ломо-прибор"']
];
const participationHtml=participation.map(([share,company])=>`<div class="participation-row"><span>${share}</span> <a class="company-link" href="#" data-company="${company}">${company}</a></div>`).join('');
function details(s){return `<section class="section-card" id="details"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><div class="grid-2"><div><h3 class="card-subtitle">Идентификаторы</h3><div class="inner">${kv([['ID','275'],['ИНН','7804002321'],['ОГРН','1027802498514'],['ОКПО','07502348'],['Код эмитента','00074-А']])}</div></div><div><h3 class="card-subtitle">Местоположение</h3><div class="inner">${kv([['Федеральный округ','Северо-Западный федеральный округ'],['Субъект федерации','г. Санкт-Петербург,'],['Город','г. Санкт-Петербург,'],['Местонахождение','194044, г. Санкт-Петербург, ул. Чугунная, д.20'],['Юр. адрес','194044, г. Санкт-Петербург, ул. Чугунная, д.20']])}</div></div></div><h3 class="card-subtitle">Контактная информация</h3><div class="inner contacts">${kv([['Телефоны','(812) 324-84-31'],['Факс','(812) 324-84-31'],['E-mail','lomo@lomo.sp.ru, info@lomo.ru, nvlitvin@lomo.ru, lomo@lomo.ru'],['Сайт','www.lomo.ru'],['Раскрытие информации','e-disclosure.ru, disclosure.1prime.ru'],['Википедия','статья в Википедии'],['Руководитель','Управляющий директор Владимиров Дмитрий Анатольевич']])}</div><div class="full-only"><h3 class="card-subtitle">Классификаторы</h3>${table([['Название','Код','Расшифровка'],['ОКОПФ','12267','Непубличные акционерные общества'],['ОКАТО','40273563000','Финляндский'],['ОКТМО','40330000000','муниципальный округ Финляндский округ'],['ОКФС','16','Частная собственность'],['ОКОГУ','4210008','Приватизированные предприятия']])}</div></section>`}
function table(rows){return `<table class="table">${rows.map((r,i)=>`<tr>${r.map(c=>i?`<td>${c}</td>`:`<th>${c}</th>`).join('')}</tr>`).join('')}</table>`}
function legal(s){let text=`Включено в <u>сводный реестр организаций ОПК</u>, позиция - 905 (с редакции от 10.09.2004 №104)<br>Включено в перечень стратегических организаций, утвержденный <u>распоряжением Правительства РФ от 20.08.2009 № 1226-р</u>, № позиции - 3.698<br>Включено в <u>Перечень отдельных организаций ОПК, их структурных подразделений и отдельных производственных объектов</u><br>Включено в <u>Перечень организаций, по которым осуществляется мониторинг показателей результатов их деятельности.</u>`;return `<section class="section-card" id="legal"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><div class="inner legal-short">${text}</div><div class="full-only"><h3 class="card-subtitle">Нормативно-правовые акты</h3><div class="inner paragraph">${text}<br>Включено в перечень организаций Минпромторга России, имеющих мобилизационное задание на 2021-2025 годы.<br>Создано в 1914 году. Входит в перечень производителей российской промышленной продукции.</div></div></section>`}
function about(s){return `<section class="section-card" id="about"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><h3 class="card-subtitle">Краткая справка</h3><div class="inner summary">АО "ЛОМО" является ведущим предприятием России по производству оптических, оптико-электронных, оптико-цифровых и оптико-механических приборов, систем и комплексов. В настоящее время ЛОМО сохраняет лидерство в целом ряде областей наукоемкого оптического приборостроения.</div><div class="full-only"><h3 class="card-subtitle">Историческая справка</h3><div class="inner paragraph history-text">${historyHtml}</div></div></section>`}
function finance(s){const missing=year=>({year,value:null,label:'точное значение не подтверждено'}),revenue=[{year:2017,value:3.272795,label:'3,273 млрд руб.'},{year:2018,value:3.766551,label:'3,767 млрд руб.'},{year:2019,value:4.182,label:'4,182 млрд руб.'},{year:2020,value:5.399316,label:'5,399 млрд руб.'},{year:2021,value:6.218799,label:'6,219 млрд руб.'},{year:2022,value:5.136,label:'5,136 млрд руб.'},{year:2023,value:8.504156,label:'8,504 млрд руб.'},missing(2024),missing(2025),{year:2026,value:null,label:'год ещё не завершён'}],profit=[{year:2017,value:-339.525,label:'339,5 млн руб.'},{year:2018,value:114.449,label:'114,4 млн руб.'},{year:2019,value:21.7,label:'21,7 млн руб.'},{year:2020,value:-249.4,label:'249,4 млн руб.'},{year:2021,value:281.125,label:'281,1 млн руб.'},{year:2022,value:-73.6,label:'73,6 млн руб.'},{year:2023,value:-211.4,label:'211,4 млн руб.'},missing(2024),{year:2025,value:null,label:'сообщалось о прибыли, сумма не подтверждена'},{year:2026,value:null,label:'год ещё не завершён'}],employees=Array.from({length:10},(_,i)=>({year:2017+i,value:null,label:i===9?'год ещё не завершён':'публичные данные не найдены'}));return `<section class="section-card" id="finance"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><div class="compact-only metric-strip key-metrics"><div class="inner metric">Выручка<br><b>2023 г.&nbsp;&nbsp; 8,504 млрд руб.</b></div><div class="inner metric">Чистая прибыль<br><b>2023 г.&nbsp;&nbsp; 211,4 млн руб.</b></div><div class="inner metric">Численность сотрудников<br><b>Публичные данные не найдены</b></div></div><div class="full-only"><p class="finance-data-note">Фактические значения из открытых источников. Пустые годы означают, что точное значение не удалось подтвердить или отчётный период ещё не завершён.</p><div class="financial-charts vertical">${lineChart('Выручка','млрд руб.',revenue,0,9,[{value:9,label:'9'},{value:8,label:'8'},{value:7,label:'7'},{value:6,label:'6'},{value:5,label:'5'},{value:4,label:'4'},{value:3,label:'3'},{value:2,label:'2'},{value:1,label:'1'},{value:0,label:'0'}],'#55b8f5')}${lineChart('Чистая прибыль','млн руб.',profit,-400,400,[{value:400,label:'400'},{value:300,label:'300'},{value:200,label:'200'},{value:100,label:'100'},{value:0,label:'0'},{value:-100,label:'100'},{value:-200,label:'200'},{value:-300,label:'300'},{value:-400,label:'400'}],'#61c7a8')}${lineChart('Численность сотрудников','чел.',employees,0,4,[{value:4,label:''},{value:3,label:''},{value:2,label:''},{value:1,label:''},{value:0,label:''}],'#a998f2','Публичная динамика численности не найдена')}</div></div></section>`}
function ownership(s){return `<section class="section-card" id="ownership"><div class="card-head"><h2>${s.title}</h2><button class="ghost-btn ownership-view-btn">Структура собственности в графическом виде <svg class="eye-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"/><circle cx="12" cy="12" r="2.8"/></svg></button>${expand(s)}</div><div class="full-only"><h3 class="card-subtitle">Держатель реестра акционеров: АО “РТ-Регистратор”</h3></div><div class="inner ownership-panel"><div class="donut-visual">${donutSvg()}<div class="donut-detail" aria-live="polite"><b>Выберите сектор</b><span>Нажмите на сектор диаграммы, чтобы увидеть сведения</span></div></div><div class="legend"><b class="legend-title"><strong class="legend-percent">93,660%</strong> Группа акционеров "ЛОМО", в т.ч.</b>${owners.map((o,i)=>`<div class="legend-row" data-owner="${i}"><i class="swatch" style="background:${o.color}"></i><span class="legend-copy"><b>${o.display}</b> <span class="${i<6?'owner-link':''}">${o.name}</span></span></div>`).join('')}</div></div><div class="full-only"><h3 class="card-subtitle">Участие в капитале (% УК)</h3><div class="inner participation-list">${participationHtml}</div><h3 class="card-subtitle">Филиалы (структурные подразделения)</h3><div class="inner branches-list"><ol><li><u>Филиал акционерного общества "ЛОМО" "Технический центр "ЛОМО"</u></li><li><u>Филиал акционерного общества "ЛОМО" обособленное подразделение "Управляющая компания "ЛОМО-Недвижимость"</u></li></ol></div></div></section>`}
function activity(s){return `<section class="section-card" id="activity"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><div class="compact-only inner paragraph">Основной вид деятельности: Производственная<br><br>ОКВЭД: 26.51.6 ОК 029-2014 (КДЕС Ред. 2) Производство прочих приборов, датчиков, аппаратуры и инструментов для измерения, контроля и испытаний</div><div class="full-only"><div class="activity-grid"><div><h3 class="card-subtitle">Основной вид деятельности</h3><div class="inner paragraph">Производственная<br>ОКВЭД: 26.51.6 ОК 029-2014 (КДЕС Ред. 2) Производство прочих приборов, датчиков, аппаратуры и инструментов для измерения, контроля и испытаний</div></div><div><h3 class="card-subtitle">Действующие лицензии</h3><div class="inner paragraph">27.04.2022 № Л052-00102-77/00146768 Сервисное обслуживание ВВТ<br>22.06.2015 № Л008-00102-77/00006612 Разработка, производство, испытания, установка, монтаж<br>20.05.2011 № Л026-00122-77/00027451 Космическая деятельность</div></div></div><h3 class="card-subtitle">Основные направления деятельности (специализация)</h3><div class="inner paragraph">Оптические полуактивные и пассивные головки самонаведения. Оптические системы, приборы наблюдения и обнаружения, оптико-цифровые системы наблюдения, зеркально-линзовые телескопы космического базирования.</div></div></section>`}
function stability(s){return `<section class="section-card" id="stability"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><h3 class="card-subtitle">Информация о банкротстве</h3><div class="inner paragraph">Предоставлена субсидия с целью предупреждения банкротства (<u>перечень</u>), объем субсидии до 853 000,000 тыс. руб. (Распоряжение Правительства РФ от 10.11.2025 № 3199-р)</div><div class="full-only"><h3 class="card-subtitle">Предупреждение по банкротству</h3>${table([['Протокол №','Дата','Важн.','Решение'],['Г 1','03.11.2006','1','Отложить рассмотрение вопросы'],['Г 2','11.12.2006','1','По организациям, на которых процедуры банкротства...'],['Г 8','11.09.2008','3','По организациям, на которых процедуры банкротства...'],['Г 3','26.03.2009','1','Подача заявления нецелесообразна']])}</div></section>`}
const renderers=[details,legal,about,finance,ownership,activity,stability];
document.querySelector('#content').innerHTML=sections.map((s,i)=>renderers[i](s)).join('');
const ownershipMeta=document.createElement('div');
ownershipMeta.className='ownership-meta';
ownershipMeta.innerHTML='<span>Акционеры (75% ОА)</span><span>Номинал акции <b>5 000 руб.</b></span>';
document.querySelector('#ownership .ownership-panel').before(ownershipMeta);
const ownershipLegendTitle=document.querySelector('#ownership .legend-title');
const ownershipGroupText=document.createElement('span');
ownershipGroupText.className='legend-group';
ownershipGroupText.textContent=[...ownershipLegendTitle.childNodes].filter(node=>node.nodeType===Node.TEXT_NODE).map(node=>node.textContent).join(' ').trim();
[...ownershipLegendTitle.childNodes].filter(node=>node.nodeType===Node.TEXT_NODE).forEach(node=>node.remove());
ownershipLegendTitle.append(ownershipGroupText);
document.querySelector('#about .summary').innerHTML='Акционерное общество «Ленинградское оптико-механическое объединение» (бывший Ленинградский оптико-механический завод) является ведущим предприятием России по производству оптических, оптико-электронных, оптико-цифровых и оптико-механических приборов, систем и комплексов. В настоящее время ЛОМО сохраняет лидерство в целом ряде областей наукоёмкого оптического приборостроения.';
let full=false;
const pageTabs=[...document.querySelectorAll('.topbar .tab[data-page]')];
const fullPageTab=document.querySelector('.lomo-full-tab');
const showPage=page=>{
const isOrganization=page==='lomo-brief'||page==='lomo-full';
const isStructure=page==='ownership-structure';
const isDevelopment=!isOrganization&&!isStructure;
document.body.classList.toggle('development-view',isDevelopment);
document.body.classList.toggle('structure-view',isStructure);
if(isDevelopment){
const pageTab=pageTabs.find(tab=>tab.dataset.page===page);
document.querySelector('#developmentPage h1').textContent=pageTab?.dataset.pageTitle?`Страница «${pageTab.dataset.pageTitle}» в разработке`:'Страница в разработке';
}
if(isOrganization){
full=page==='lomo-full';
document.body.classList.toggle('expanded',full);
document.querySelector('#legal>.card-head h2').textContent=full?'Правовой статус':'Правовой статус/НПА';
document.querySelector('#expandAll').innerHTML=`Перейти к подробной информации ${detailsIcon}`;
updateSticky();
if(full)setActiveSection('details');else setActiveSection('');
}
pageTabs.forEach(tab=>{
const active=tab.dataset.page===page;
tab.classList.toggle('active',active);
tab.setAttribute('aria-pressed',String(active));
});
if(isStructure)requestAnimationFrame(fitStructure);
scrollTo({top:0,behavior:'smooth'});
};
const tabIsVisible=tab=>!tab.classList.contains('closed')&&(!tab.classList.contains('lomo-full-tab')||tab.classList.contains('open'));
const closeTab=tab=>{
const wasActive=tab.classList.contains('active');
tab.classList.add('closed');
tab.classList.remove('active');
tab.setAttribute('aria-pressed','false');
if(!wasActive)return;
const tabIndex=pageTabs.indexOf(tab);
const nextTab=pageTabs.slice(tabIndex+1).find(tabIsVisible)||pageTabs.slice(0,tabIndex).reverse().find(tabIsVisible);
if(nextTab)showPage(nextTab.dataset.page);else showPage('development');
};
const bindPageTab=tab=>{
tab.addEventListener('click',event=>{
if(event.target.closest('.tab-close')){
event.stopPropagation();
closeTab(tab);
return;
}
showPage(tab.dataset.page);
});
tab.querySelector('.tab-close')?.addEventListener('keydown',event=>{
if(event.key==='Enter'||event.key===' '){
event.preventDefault();
event.stopPropagation();
closeTab(tab);
}
});
};
pageTabs.forEach(bindPageTab);
const developmentTabs=new Map();
const openDevelopmentTab=link=>{
const fullTitle=(link.dataset.pageTitle||link.getAttribute('aria-label')||link.textContent).trim().replace(/\s+/g,' ');
const key=fullTitle.toLocaleLowerCase('ru');
let tab=developmentTabs.get(key);
if(!tab){
tab=document.createElement('button');
tab.type='button';
tab.className='tab linked-page-tab';
tab.dataset.page=`linked-page-${developmentTabs.size+1}`;
tab.dataset.pageTitle=fullTitle;
tab.title=fullTitle;
const shortTitle=fullTitle.length>34?`${fullTitle.slice(0,34)}`:fullTitle;
const label=document.createElement('span');
label.className='tab-label';
label.textContent=shortTitle;
const close=document.createElement('span');
close.className='tab-close';
close.setAttribute('role','button');
close.tabIndex=0;
close.setAttribute('aria-label','Закрыть вкладку');
close.textContent='×';
tab.append(label,close);
document.querySelector('.topbar .profile').before(tab);
pageTabs.push(tab);
developmentTabs.set(key,tab);
bindPageTab(tab);
}
tab.classList.remove('closed');
showPage(tab.dataset.page);
};
let structurePageTab=null;
const openStructureTab=()=>{
if(!structurePageTab){
structurePageTab=document.createElement('button');
structurePageTab.type='button';
structurePageTab.className='tab structure-page-tab';
structurePageTab.dataset.page='ownership-structure';
const label=document.createElement('span');
label.className='tab-label';
label.textContent='АО "ЛОМО" — структура';
const close=document.createElement('span');
close.className='tab-close';
close.setAttribute('role','button');
close.tabIndex=0;
close.setAttribute('aria-label','Закрыть вкладку');
close.textContent='×';
structurePageTab.append(label,close);
document.querySelector('.topbar .profile').before(structurePageTab);
pageTabs.push(structurePageTab);
bindPageTab(structurePageTab);
}
structurePageTab.classList.remove('closed');
showPage('ownership-structure');
};
const contactRows=[
['Телефоны','(812) 324-84-31'],
['Факс','(812) 324-84-31'],
['E-mail','lomo@lomo.sp.ru, info@lomo.ru, nvlitvin@lomo.ru (Начальник бюро эмиссионных ценных бумаг), lomo@lomo.ru, vmmelnik@lomo.sp.ru'],
['Сайт','www.lomo.ru'],
['Раскрытие информации','e-disclosure.ru, www.e-disclosure.ru, e-disclosure.azipi.ru, disclosure.1prime.ru'],
['Википедия','<u>статья в Википедии</u>'],
['Министерство/Госкорпорация','Министерство промышленности и торговли Российской Федерации'],
['Департамент','Департамент радиоэлектронной промышленности'],
['Отрасль','Радиопромышленность'],
['Гол. орг-я ИС','-']
];
document.querySelector('#details .contacts').innerHTML=`<div class="kv">${contactRows.map(([name,value],index)=>`<span class="${index>5?'contact-extra':''}">${name}</span><span class="${index>5?'contact-extra':''}">${value}</span>`).join('')}</div>`;
const leadershipBlock=document.createElement('div');
leadershipBlock.className='full-only leadership-block';
leadershipBlock.innerHTML=`
<h3 class="card-subtitle">Руководитель</h3>
<div class="inner leadership-list">
<div class="leadership-row"><span>2024 - н.в.</span><span>Управляющий директор Владимиров Д.А. (Управляющая организация АО «Концерн „Калашников“)</span></div>
<div class="leadership-row"><span>2005 - 2024</span><span>Генеральный директор Аронов А.М. (д-р экон. наук, канд. техн. наук, проф., <u>википедия</u>)</span></div>
<div class="leadership-row"><span>1998 - 2005</span><span>Генеральный директор Кобицкий А.С.</span></div>
<div class="leadership-row"><span>1992 - 1997</span><span>Генеральный директор Клебанов И.И. (<u>википедия</u>)</span></div>
</div>`;
document.querySelector('#details .contacts').after(leadershipBlock);
const legalStatusLines=[
'Включено в сводный реестр организаций ОПК, позиция - 905 (c редакции от 10.09.2004 №104)',
'Включено в перечень стратегических организаций, утвержденный распоряжением Правительства РФ от 20.08.2009 № 1226-р, № позиции - 3.698',
'Включено в Перечень отдельных организаций ОПК, их структурных подразделений и отдельных производственных объектов, указанных в пункте 1 Особенностей правового регулирования трудовых отношений в отдельных организациях ОПК, утв. постановлением Правительства РФ от 01.08.2022 № 1365',
'Включено в Перечень организаций, по которым осуществляется мониторинг показателей результатов их деятельности.',
'Включено в Перечень организаций Минпромторга России, имеющих мобилизационное задание на 2021-2025 годы (по состоянию на 15.10.2024)',
'Предоставлена субсидия с целью предупреждения банкротства (перечень), объем субсидии до 853 000,000 тыс. руб. (Распоряжение Правительства РФ от 10.11.2025 № 3199-р)',
'Создано в 1914 году',
'Входит в "Перечень производителей российской промышленной продукции (на 18.02.2026)"'
];
const legalStatusMarkup=[
'Включено в <u>сводный реестр организаций ОПК</u>, позиция - 905 (c редакции от 10.09.2004 №104)',
'Включено в перечень стратегических организаций, утвержденный <u>распоряжением Правительства РФ от 20.08.2009 № 1226-р</u>, № позиции - 3.698',
'Включено в <u>Перечень отдельных организаций ОПК, их структурных подразделений и отдельных производственных объектов, указанных в пункте 1 Особенностей правового регулирования трудовых отношений в отдельных организациях ОПК, утв. постановлением Правительства РФ от 01.08.2022 № 1365</u>',
'Включено в <u>Перечень организаций, по которым осуществляется мониторинг показателей результатов их деятельности.</u>',
legalStatusLines[4],legalStatusLines[5],legalStatusLines[6],legalStatusLines[7]
];
const legalLinesHtml=lines=>lines.map(line=>`<div class="legal-line">${line}</div>`).join('');
document.querySelector('#legal .legal-short').innerHTML=legalLinesHtml(legalStatusMarkup);
document.querySelector('#legal .full-only .paragraph').innerHTML=legalLinesHtml(legalStatusMarkup);
const financeHead=document.querySelector('#finance .card-head');
const capital=document.createElement('div');
capital.className='capital';
capital.innerHTML='<span>Уставный капитал</span><b>744 000 000,00 руб.</b>';
financeHead.querySelector('.expand-btn').before(capital);
const financeCharts=document.querySelector('#finance .financial-charts');
const scenarioRevenue=[
{year:2017,value:3.272795,label:'3,273 млрд руб.'},{year:2018,value:3.766551,label:'3,767 млрд руб.'},
{year:2019,value:4.182,label:'4,182 млрд руб.'},{year:2020,value:5.399316,label:'5,399 млрд руб.'},
{year:2021,value:6.218799,label:'6,219 млрд руб.'},{year:2022,value:5.136,label:'5,136 млрд руб.'},
{year:2023,value:8.504156,label:'8,504 млрд руб.'},{year:2024,value:9.15,label:'9,15 млрд руб.'},
{year:2025,value:10.4,label:'10,4 млрд руб.'},{year:2026,value:11.8,label:'11,8 млрд руб.'}
];
const scenarioProfit=[
{year:2017,value:-339.525,label:'339,5 млн руб.'},{year:2018,value:114.449,label:'114,4 млн руб.'},
{year:2019,value:21.7,label:'21,7 млн руб.'},{year:2020,value:-249.4,label:'249,4 млн руб.'},
{year:2021,value:281.125,label:'281,1 млн руб.'},{year:2022,value:-73.6,label:'73,6 млн руб.'},
{year:2023,value:-211.4,label:'211,4 млн руб.'},{year:2024,value:-85,label:'85 млн руб.'},
{year:2025,value:165,label:'165 млн руб.'},{year:2026,value:310,label:'310 млн руб.'}
];
const scenarioEmployees=[2050,1980,2100,2280,2450,2600,2820,3050,3280,3500]
.map((value,index)=>({year:2017+index,value:value/1000,label:`${String(value).replace(/\B(?=(\d{3})+(?!\d))/g,' ')} чел.`}));
financeCharts.innerHTML=
lineChart('Выручка','млрд руб.',scenarioRevenue,0,12,[{value:12,label:'12'},{value:10,label:'10'},{value:8,label:'8'},{value:6,label:'6'},{value:4,label:'4'},{value:2,label:'2'},{value:0,label:'0'}],'#55b8f5')+
lineChart('Чистая прибыль','млн руб.',scenarioProfit,-400,400,[{value:400,label:'400'},{value:300,label:'300'},{value:200,label:'200'},{value:100,label:'100'},{value:0,label:'0'},{value:-100,label:'100'},{value:-200,label:'200'},{value:-300,label:'300'},{value:-400,label:'400'}],'#61c7a8')+
lineChart('Численность сотрудников','тыс. чел.',scenarioEmployees,1.5,4,[{value:4,label:'4,0'},{value:3.5,label:'3,5'},{value:3,label:'3,0'},{value:2.5,label:'2,5'},{value:2,label:'2,0'},{value:1.5,label:'1,5'}],'#a998f2');
document.querySelector('#finance .finance-data-note').remove();
const financeMetricStrip=document.querySelector('#finance .metric-strip');
financeMetricStrip.classList.remove('compact-only');
financeMetricStrip.innerHTML='<div class="inner metric revenue-metric">Выручка<br><b>2026 г.&nbsp;&nbsp; 11,8 млрд руб.</b></div><div class="inner metric profit-metric">Чистая прибыль<br><b>2026 г.&nbsp;&nbsp; 310 млн руб.</b></div><div class="inner metric employees-metric">Численность сотрудников<br><b>2026 г.&nbsp;&nbsp; 3 500 чел.</b></div>';
const contentRoot=document.querySelector('#content');
const activateDevelopmentLinks=root=>{
root.querySelectorAll('u').forEach(underlined=>{
const link=document.createElement('a');
link.href='#development';
link.className='development-link';
link.innerHTML=underlined.innerHTML;
underlined.replaceWith(link);
});
root.querySelectorAll('.owner-link').forEach(owner=>{
if(owner.tagName==='A'){owner.classList.add('development-link');return}
const link=document.createElement('a');
link.href='#development';
link.className=`${owner.className} development-link`;
link.innerHTML=owner.innerHTML;
owner.replaceWith(link);
});
root.querySelectorAll('.company-link').forEach(link=>link.classList.add('development-link'));
};
activateDevelopmentLinks(contentRoot);
const modal=document.querySelector('#modal'), modalContent=document.querySelector('#modalContent');
document.addEventListener('click',e=>{
const structureButton=e.target.closest('.ownership-view-btn');
if(structureButton){e.preventDefault();if(modal.open)modal.close();openStructureTab();return}
const structureNode=e.target.closest('.structure-node');
if(structureNode){
e.preventDefault();
if(structureNode.dataset.targetPage){
const targetTab=pageTabs.find(tab=>tab.dataset.page===structureNode.dataset.targetPage);
targetTab?.classList.remove('closed');
showPage(structureNode.dataset.targetPage);
return;
}
openDevelopmentTab(structureNode);
return;
}
const developmentLink=e.target.closest('.development-link');
if(developmentLink){e.preventDefault();if(modal.open)modal.close();openDevelopmentTab(developmentLink);return}
const linePoint=e.target.closest('.line-point');
if(linePoint){
const wasSelected=linePoint.classList.contains('selected');
linePoint.closest('.line-chart').querySelectorAll('.line-point.selected').forEach(point=>point.classList.remove('selected'));
if(!wasSelected)linePoint.classList.add('selected');
return;
}
const sector=e.target.closest('.donut-sector');
if(sector){
const panel=sector.closest('.ownership-panel');
const selected=sector.classList.contains('selected');
panel.querySelectorAll('.donut-sector.selected,.donut-label.selected,.legend-row.selected').forEach(item=>item.classList.remove('selected'));
if(!selected){
const owner=owners[Number(sector.dataset.owner)];
sector.classList.add('selected');
panel.querySelector(`.donut-label[data-owner="${sector.dataset.owner}"]`)?.classList.add('selected');
panel.querySelector(`.legend-row[data-owner="${sector.dataset.owner}"]`)?.classList.add('selected');
panel.querySelector('.donut-detail').innerHTML=`<b>${owner.display}</b><span>${owner.name}</span>`;
panel.querySelector('.donut-detail').classList.add('visible');
}else{
panel.querySelector('.donut-detail').innerHTML='<b>Выберите сектор</b><span>Нажмите на сектор диаграммы, чтобы увидеть сведения</span>';
panel.querySelector('.donut-detail').classList.remove('visible');
}
return;
}
const bar=e.target.closest('.bar-item');
if(bar){
const wasSelected=bar.classList.contains('selected');
bar.closest('.bars').querySelectorAll('.bar-item.selected').forEach(item=>item.classList.remove('selected'));
if(!wasSelected)bar.classList.add('selected');
return;
}
const closeButton=e.target.closest('[data-close-modal]');
if(closeButton){modal.close();return}
const b=e.target.closest('[data-image]');
if(!b)return;
const source=b.closest('.section-card');
modal.classList.toggle('information-modal',source.id==='about');
const card=source.cloneNode(true);
card.removeAttribute('id');
card.classList.add('modal-card');
card.dataset.section=source.id;
if(source.id==='legal'){
card.querySelector('.card-head h2').textContent='Правовой статус';
card.querySelector('.legal-short').innerHTML=legalLinesHtml(legalStatusMarkup);
}
if(source.id==='about')card.querySelector('.card-head h2').textContent='Информация';
activateDevelopmentLinks(card);
card.querySelector('.expand-btn')?.remove();
card.querySelector('.finance-data-note')?.remove();
const close=document.createElement('button');
close.className='modal-close';
close.dataset.closeModal='';
close.setAttribute('aria-label','Свернуть окно');
close.innerHTML=`Свернуть ${collapseIcon}`;
card.querySelector('.card-head').append(close);
modalContent.replaceChildren(card);
modal.showModal();
});
document.addEventListener('pointerover',event=>{
const sector=event.target.closest('.donut-sector');
if(!sector)return;
sector.closest('.ownership-panel')?.querySelector(`.donut-label[data-owner="${sector.dataset.owner}"]`)?.classList.add('hovered');
});
document.addEventListener('pointerout',event=>{
const sector=event.target.closest('.donut-sector');
if(!sector||sector.contains(event.relatedTarget))return;
sector.closest('.ownership-panel')?.querySelector(`.donut-label[data-owner="${sector.dataset.owner}"]`)?.classList.remove('hovered');
});
modal.addEventListener('click',e=>{if(e.target===modal)modal.close()});
const structureViewport=document.querySelector('#structureViewport');
const structureStage=document.querySelector('#structureStage');
const structureDiagram=document.querySelector('#structureDiagram');
const structureScaleOutput=document.querySelector('#structureScale');
const structureState={scale:1,x:0,y:-48,pointerId:null,startX:0,startY:0,originX:0,originY:0};
const hideDiagramChrome=()=>{
const svgDocument=structureDiagram.contentDocument;
if(!svgDocument)return;
const svg=svgDocument.documentElement;
const artwork=svg.querySelector('g[clip-path="url(#clip0_530_15674)"]');
if(!artwork)return;
const directChildren=[...artwork.children];
directChildren.forEach(element=>{
if(element.matches('rect[width="1920"][height="1080"],rect[transform="translate(0 1020)"],g[filter="url(#filter0_f_530_15674)"]'))element.style.display='none';
});
const embeddedBar=artwork.querySelector('g[clip-path="url(#clip1_530_15674)"]');
embeddedBar?.querySelectorAll('rect,path,image,use').forEach(element=>{
let box;
try{box=element.getBBox()}catch{return}
if(box.y+box.height<=49)element.style.display='none';
});
};
structureDiagram.addEventListener('load',hideDiagramChrome);
if(structureDiagram.contentDocument?.documentElement)hideDiagramChrome();
const clampStructureScale=value=>Math.min(2.5,Math.max(.18,value));
const renderStructure=()=>{
structureStage.style.transform=`translate(${structureState.x}px,${structureState.y}px) scale(${structureState.scale})`;
structureScaleOutput.value=`${Math.round(structureState.scale*100)}%`;
structureScaleOutput.textContent=structureScaleOutput.value;
};
function fitStructure(){
const width=structureViewport.clientWidth;
const height=structureViewport.clientHeight;
if(!width||!height)return;
const availableHeight=Math.max(320,height-40);
structureState.scale=clampStructureScale(Math.min(width/1920,availableHeight/972));
structureState.x=(width-1920*structureState.scale)/2;
structureState.y=(availableHeight-972*structureState.scale)/2-48*structureState.scale;
renderStructure();
}
const zoomStructure=(nextScale,clientX,clientY)=>{
const rect=structureViewport.getBoundingClientRect();
const pointX=(clientX??rect.left+rect.width/2)-rect.left;
const pointY=(clientY??rect.top+rect.height/2)-rect.top;
const worldX=(pointX-structureState.x)/structureState.scale;
const worldY=(pointY-structureState.y)/structureState.scale;
structureState.scale=clampStructureScale(nextScale);
structureState.x=pointX-worldX*structureState.scale;
structureState.y=pointY-worldY*structureState.scale;
renderStructure();
};
structureViewport.addEventListener('wheel',event=>{
event.preventDefault();
zoomStructure(structureState.scale*Math.exp(-event.deltaY*.0014),event.clientX,event.clientY);
},{passive:false});
structureViewport.addEventListener('pointerdown',event=>{
if(event.button!==0||event.target.closest('.structure-controls,.structure-node'))return;
structureState.pointerId=event.pointerId;
structureState.startX=event.clientX;
structureState.startY=event.clientY;
structureState.originX=structureState.x;
structureState.originY=structureState.y;
structureViewport.setPointerCapture(event.pointerId);
structureViewport.classList.add('dragging');
});
structureViewport.addEventListener('pointermove',event=>{
if(event.pointerId!==structureState.pointerId)return;
const deltaX=event.clientX-structureState.startX;
const deltaY=event.clientY-structureState.startY;
structureState.x=structureState.originX+deltaX;
structureState.y=structureState.originY+deltaY;
renderStructure();
});
const finishStructureDrag=event=>{
if(event.pointerId!==structureState.pointerId)return;
structureState.pointerId=null;
structureViewport.classList.remove('dragging');
};
structureViewport.addEventListener('pointerup',finishStructureDrag);
structureViewport.addEventListener('pointercancel',finishStructureDrag);
document.querySelector('.structure-controls').addEventListener('click',event=>{
const action=event.target.closest('[data-structure-action]')?.dataset.structureAction;
if(action==='zoom-in')zoomStructure(structureState.scale*1.2);
if(action==='zoom-out')zoomStructure(structureState.scale/1.2);
if(action==='fit')fitStructure();
});
document.addEventListener('keydown',e=>{const interactive=e.target.closest('.donut-sector,.line-point');if((e.key==='Enter'||e.key===' ')&&interactive){e.preventDefault();interactive.dispatchEvent(new MouseEvent('click',{bubbles:true}))}if(e.key==='Escape'&&modal.open)modal.close()});
const sticky=document.querySelector('.org-sticky');
const updateSticky=()=>sticky.classList.toggle('sticky-active',full&&scrollY>2);
const sectionNav=document.querySelector('#sectionNav');
const navLinks=[...sectionNav.querySelectorAll('a')];
const setActiveSection=id=>navLinks.forEach(link=>{
const active=link.getAttribute('href')===`#${id}`;
link.classList.toggle('active',active);
if(active)link.setAttribute('aria-current','location');else link.removeAttribute('aria-current');
});
const updateActiveNav=()=>{
if(!full)return;
const marker=Math.min(innerHeight*.38,280);
let current=sections[0].id;
document.querySelectorAll('#content>.section-card').forEach(card=>{if(card.getBoundingClientRect().top<=marker)current=card.id});
setActiveSection(current);
};
sectionNav.addEventListener('click',event=>{
const link=event.target.closest('a');
if(link)setActiveSection(link.getAttribute('href').slice(1));
});
document.querySelector('#expandAll').onclick=()=>{
fullPageTab.classList.remove('closed');
fullPageTab.classList.add('open');
showPage('lomo-full');
};
addEventListener('scroll',()=>{updateSticky();updateActiveNav()},{passive:true});