Filtrar:
Se ha producido un error al procesar la plantilla.
The following has evaluated to null or missing:
==> getProduct(channelId, entry.getTitle()) [in template "34352066712900#33336#153601689" at line 32, column 28]
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign product = getProduct(channelI... [in template "34352066712900#33336#153601689" at line 32, column 9]
----
1<#setting url_escaping_charset="UTF-8">
2
3<#-- ===== Idiomas: helpers y datos al inicio ===== -->
4<#function getListTypeEntriesByERC erc>
5 <#attempt>
6 <#return restClient.get(
7 "/headless-admin-list-type/v1.0/list-type-definitions/by-external-reference-code/${erc}/list-type-entries?fields=key,name&sort"
8 ).items>
9 <#recover>
10 <#return []>
11 </#attempt>
12</#function>
13
14<#-- Siempre lista, nunca null -->
15<#assign LANG_ENTRIES = (getListTypeEntriesByERC("IDIOMAS_NORMAS_PICKLIST")?default([]))![]>
16
17<#function langLiteral key>
18 <#assign k = (key!"")?upper_case>
19 <#list LANG_ENTRIES as e>
20 <#if (e.key!"")?upper_case == k>
21 <#return e.name!"">
22 </#if>
23 </#list>
24 <#return key!"" >
25</#function>
26
27<section class="list-standards-section">
28 <div class="standards-container view-grid">
29 <#if entries?has_content>
30 <#assign channelId = getChannelId()>
31 <#list entries as entry>
32 <#assign product = getProduct(channelId, entry.getTitle())>
33 <#assign productId = product.productId />
34 <#assign cpDefinitionId = product.id />
35 <#assign productERC = product.externalReferenceCode />
36 <#assign categories = getProductCategories(channelId, product.productId)![]>
37 <#assign specs = getProductSpecifications(channelId, product.productId)![]>
38 <#assign status = getStatus(categories)!"" >
39 <#assign organism = getOrganism(categories)!"" >
40 <#assign currentStateDate = getCurrentStateDate(specs)!"" >
41 <#assign entryUrl = "">
42 <#attempt>
43 <#-- si el entry trae slug -->
44 <#assign entryUrl = "/p/${entry.getUrl()}">
45 <#recover>
46 <#-- si no, usa viewURL o el slug del product -->
47 <#assign entryUrl = (entry.getViewURL()!"")>
48 <#if !entryUrl?has_content && (product.slug?? && product.slug?has_content)>
49 <#assign entryUrl = "/p/${product.slug}">
50 </#if>
51 <#if !entryUrl?has_content>
52 <#assign entryUrl = "#">
53 </#if>
54 </#attempt>
55
56 <#-- Detalle de normas (idioma, formato, precio) -->
57 <#assign normasDetails = getNormasDetails(product.id)![]>
58
59 <#-- idiomas únicos -->
60 <#assign languages = []>
61 <#list normasDetails as n>
62 <#if n.language?? && n.language?has_content && !languages?seq_contains(n.language)>
63 <#assign languages = languages + [n.language]>
64 </#if>
65 </#list>
66
67 <#-- combinación por defecto -->
68 <#assign defaultLang = "">
69 <#assign defaultFmt = "">
70 <#assign defaultPrice = 0>
71 <#if normasDetails?has_content>
72 <#assign defaultLang = (normasDetails[0].language!"")>
73 <#assign defaultFmt = (normasDetails[0].format!"")>
74 <#assign defaultPrice = (normasDetails[0].price!'0')?number>
75 </#if>
76
77 <#-- formatos válidos para el idioma por defecto -->
78 <#assign formatsForDefault = []>
79 <#list normasDetails?filter(nd -> (nd.language!"") == defaultLang) as nd>
80 <#if nd.format?? && nd.format?has_content && !formatsForDefault?seq_contains(nd.format)>
81 <#assign formatsForDefault = formatsForDefault + [nd.format]>
82 </#if>
83 </#list>
84 <#if formatsForDefault?has_content && !formatsForDefault?seq_contains(defaultFmt)>
85 <#assign defaultFmt = formatsForDefault[0]>
86 </#if>
87
88 <#-- precio real para la combinación por defecto -->
89 <#list normasDetails as nd>
90 <#if (nd.language!"") == defaultLang && (nd.format!"") == defaultFmt>
91 <#assign defaultPrice = (nd.price!'0')?number>
92 </#if>
93 </#list>
94
95 <#assign hasOptions = (languages?has_content && formatsForDefault?has_content && (defaultLang?has_content) && (defaultFmt?has_content))>
96
97 <div class="item-result-buscador item-standard"
98 data-entrytype="Norma"
99 data-code="${(product.externalReferenceCode!entry.getTitle())?html}"
100 data-title="${product.name?html}">
101 <#if organism?has_content>
102 <div class="tag-standard">${organism}</div>
103 <#else>
104 <div class="tag-standard">TAG</div>
105 </#if>
106
107 <div class="info-standard">
108 <a href=${entryUrl} data-senna-off="true"><h3 class="title-standard">${product.name}</h3></a>
109
110 <div class="status-box">
111
112 <#if status?? && status?has_content>
113 <#assign statusTagClass = ''>
114
115 <#if status?trim?upper_case == 'EN VIGOR'>
116 <#assign statusTagClass = 'tag-success'>
117 <#elseif status?trim?upper_case == 'ANULADA'>
118 <#assign statusTagClass = 'tag-danger'>
119 <#elseif status?trim?upper_case == 'PROYECTO'>
120 <#assign statusTagClass = 'tag-blue'>
121 </#if>
122
123 <#if statusTagClass?? && statusTagClass?has_content>
124 <#assign statusTagClass = "status-standard " + statusTagClass>
125 </#if>
126
127 <div class="badge ${statusTagClass}">${status}</div>
128 </#if>
129
130 <span class="date-standard">
131 <#if currentStateDate?has_content>
132 ${currentStateDate?date.iso?string('yyyy-MM-dd')}
133 <#else>
134 -
135 </#if>
136 </span>
137 </div>
138
139 <div class="description-text">
140 ${product.description}
141 </div>
142
143 <#if author?has_content>${author?html}<#else> </#if>
144
145 <div class="price-container">
146 <span class="price price-ae"></span>
147 </div>
148
149 <#if hasOptions>
150 <div data-productid="${productId}" data-erc="${productERC}" class="options-standard selector-language_format">
151 <select class="form-control select-language">
152 <#list languages as l>
153 <option value="${l?html}" <#if l == defaultLang>selected</#if>>
154 ${langLiteral(l)?html}
155 </option>
156 </#list>
157 </select>
158 <select class="form-control select-format">
159 <#list formatsForDefault as f>
160 <option value="${f?html}" <#if f == defaultFmt>selected</#if>>
161 ${f?html}
162 </option>
163 </#list>
164 </select>
165 </div>
166 <#else>
167 <div class="standard-not-available">
168 Si desea adquirir esta norma, envíenos su solicitud a <a href="mailto:normas@aenor.com">normas@aenor.com</a>
169 </div>
170 </#if>
171
172 <#if hasOptions>
173 <button
174 class="standard-button"
175 aria-disabled="false">
176 ${languageUtil.get(locale, "ecom-add_cart")}
177 </button>
178 </#if>
179 </div>
180
181 <#-- Datos para JS -->
182 <#if hasOptions>
183 <script type="application/json" class="normas-data">[
184 <#list normasDetails as n>
185 <#-- solo pares válidos -->
186 <#if (n.language?? && n.language?has_content) && (n.format?? && n.format?has_content)>
187 {
188 "format": "${(n.format!"")?js_string}",
189 "language": "${(n.language!"")?js_string}",
190 "price": ${(n.price!'0')?c}
191 }<#if n_has_next>,</#if>
192 </#if>
193 </#list>
194 ]</script>
195 <script type="application/json" class="lang-map">{
196 <#list languages as l>
197 "${(l!"")?upper_case?js_string}": "${langLiteral(l)?js_string}"<#if l_has_next>,</#if>
198 </#list>
199 }</script>
200 </#if>
201 </div>
202 </#list>
203 <#else>
204 <div class="search-results-add-custom-empty-message"></div>
205 </#if>
206 </div>
207</section>
208
209<#-- ===== Helpers REST ===== -->
210<#function getChannelId>
211 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?filter=name eq 'Aenor España'&sort").items[0].id>
212</#function>
213
214<#function getProduct channelId name>
215 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products?filter=name eq '${name?url}'&sort").items[0]>
216</#function>
217
218<#function getProductCategories channelId productId>
219 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/categories?sort").items>
220</#function>
221
222<#function getProductSpecifications channelId productId>
223 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/product-specifications?sort").items>
224</#function>
225
226<#function getCurrentStateDate specifications>
227 <#list specifications as specification>
228 <#if specification.specificationKey == 'current-state-date'>
229 <#return specification.value>
230 </#if>
231 </#list>
232</#function>
233
234<#function getStatus categories>
235 <#list categories as category>
236 <#if category.vocabulary == 'status'>
237 <#return category.title>
238 </#if>
239 </#list>
240</#function>
241
242<#function getOrganism categories>
243 <#list categories as category>
244 <#if category.vocabulary == 'organismos'>
245 <#return category.name>
246 </#if>
247 </#list>
248</#function>
249
250<#function getNormasDetails productId>
251 <#return restClient.get("/c/standards/?filter=r_standards_CPDefinitionId eq '${productId}'").items>
252</#function>
253
254<script>
255jQuery(async function($){
256 let API_HOST = null;
257 function euros(v){
258 var n = Number(v) || 0;
259 return n.toLocaleString('es-ES', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' €';
260 }
261 function uniq(a){ return Array.from(new Set(a)); }
262
263 async function waitForEcomGlobalScripts(timeoutMs){
264 const start = Date.now();
265 return new Promise((resolve, reject) => {
266 (function check(){
267 if (window.ecomGlobalScripts?.functions?.getFieldCXCustomConfig && window.ecomGlobalScripts?.properties?.cxCustomConfigsNames) {
268 return resolve();
269 }
270 if (Date.now() - start > timeoutMs) return reject(new Error('ecomGlobalScripts no disponible a tiempo'));
271 requestAnimationFrame(check);
272 })();
273 });
274 }
275
276 const getApiHost = async () => {
277 if (API_HOST) return API_HOST;
278 try {
279 await waitForEcomGlobalScripts(5000);
280 API_HOST = await window.ecomGlobalScripts.functions.getFieldCXCustomConfig(
281 window.ecomGlobalScripts.properties.cxCustomConfigsNames.defaultName, "webApiUrl"
282 );
283 } catch (err) {
284 console.error('No se pudo resolver API_HOST', err);
285 }
286 return API_HOST;
287 };
288
289 function fill($sel, values, textFn){
290 var keep = $sel.val();
291 $sel.empty();
292 values.forEach(function(v){
293 $sel.append($('<option>', { value: v, text: textFn ? textFn(v) : v }));
294 });
295 if(keep && values.indexOf(keep) !== -1){ $sel.val(keep); }
296 else if(values.length){ $sel.val(values[0]); }
297 }
298
299 function relabel($sel, textFn){
300 $sel.find('option').each(function(){
301 var v = $(this).attr('value');
302 $(this).text(textFn ? textFn(v) : v);
303 });
304 }
305
306 function toUC(s){ return (s||'').toString().toUpperCase(); }
307 function emitCartError(msg){
308 try {
309 window.dispatchEvent(new CustomEvent('cart:error', { detail: { message: msg || 'Error al añadir el producto a la cesta' } }));
310 } catch (e) {}
311 }
312 async function resolveProductId(entryType, code, codIdioma, codFormato){
313 const host = await getApiHost();
314 if (!host) return '';
315 try{
316 var res = await fetch(host + '/product/getProductId', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ entryType: entryType, code: code, codIdioma: codIdioma, codFormato: codFormato }), credentials:'omit' });
317 if(!res.ok) throw new Error('HTTP '+res.status);
318 var data = await res.json();
319 return (data && (data.id)) || '';
320 } catch(e){ return ''; }
321 }
322 function getQueue(){ try { return JSON.parse(localStorage.getItem('cartQueued') || '[]'); } catch(e){ return []; } }
323 function setQueue(q){ localStorage.setItem('cartQueued', JSON.stringify(q)); }
324 function queueItem(item){
325 var q=getQueue();
326 var pid=(item&&item.productid)?String(item.productid):'';
327 var amt=Number(item&&item.amount)||1;
328 var prc=(item&&typeof item.price!=='undefined')?Number(item.price):undefined;
329 var nm =(item&&typeof item.name!=='undefined')?String(item.name):undefined;
330 var ci =(item&&typeof item.idioma!=='undefined')?String(item.idioma):undefined;
331 var cf =(item&&typeof item.formato!=='undefined')?String(item.formato):undefined;
332 if(!pid) return;
333 var idx=-1; for(var i=0;i<q.length;i++){ var qp=q[i]&&q[i].productid?String(q[i].productid):''; if(qp===pid){ idx=i; break; } }
334 if(idx>=0){ var cur=Number(q[idx].amount)||0; q[idx].amount=Math.max(1, cur+amt); if(typeof prc!=='undefined'){ q[idx].price=prc; } if(typeof nm!=='undefined'){ q[idx].name=nm;} if(typeof ci!=='undefined'){ q[idx].idioma=ci;} if(typeof cf!=='undefined'){ q[idx].formato=cf;} }
335 else { var obj={ amount: Math.max(1,amt), productid: pid }; if(typeof prc!=='undefined') obj.price=prc; if(typeof nm!=='undefined') obj.name=nm; if(typeof ci!=='undefined') obj.idioma=ci; if(typeof cf!=='undefined') obj.formato=cf; q.push(obj); }
336 setQueue(q);
337 }
338 function bumpBadge(amt){ var cur=parseInt(localStorage.getItem('cartCount')||'0',10)||0; var next=Math.max(0, cur+(amt|0)); localStorage.setItem('cartCount', String(next)); window.dispatchEvent(new CustomEvent('cart:updated', { detail:{ count: next }})); }
339
340 function initStandardCard($card){
341 var dataNode = $card.find('script.normas-data')[0];
342 if(!dataNode) return; // sin datos -> nada que sincronizar
343
344 var data = [];
345 try { data = JSON.parse(dataNode.textContent); } catch(e) { data = []; }
346 if(!data.length) return;
347
348 var mapNode = $card.find('script.lang-map')[0];
349 var langMap = {};
350 try { if(mapNode) langMap = JSON.parse(mapNode.textContent); } catch(e) { langMap = {}; }
351
352 var $lang = $card.find('.select-language');
353 var $fmt = $card.find('.select-format');
354 var $price = $card.find('.price-ae');
355
356 function labelOf(lang){ return langMap[toUC(lang)] || lang; }
357 function formatsFor(lang){
358 return uniq(data.filter(function(d){ return d.language === lang; }).map(function(d){ return d.format; }));
359 }
360 function languagesFor(fmt){
361 return uniq(data.filter(function(d){ return d.format === fmt; }).map(function(d){ return d.language; }));
362 }
363 function priceOf(lang, fmt){
364 var m = data.find(function(d){ return d.language === lang && d.format === fmt; });
365 return m ? Number(m.price) || 0 : 0;
366 }
367
368 function onLanguageChange(){
369 var lang = $lang.val();
370 var fmts = formatsFor(lang);
371 fill($fmt, fmts, null);
372 $price.text(euros(priceOf(lang, $fmt.val())));
373 }
374 function onFormatChange(){
375 var fmt = $fmt.val();
376 var langs = languagesFor(fmt);
377 fill($lang, langs, labelOf);
378 $price.text(euros(priceOf($lang.val(), fmt)));
379 }
380
381 var l0 = $lang.val();
382 var f0 = $fmt.val();
383 if(!data.find(function(d){ return d.language === l0 && d.format === f0; })){
384 onLanguageChange();
385 } else {
386 $price.text(euros(priceOf(l0, f0)));
387 }
388
389 relabel($lang, labelOf); // literal de idioma
390
391 $lang.off('change.std').on('change.std', onLanguageChange);
392 $fmt.off('change.std').on('change.std', onFormatChange);
393
394 // Añadir a la cesta
395 $card.find('.standard-button').off('click.add').on('click.add', function(e){
396 var btn = this;
397 if ($(btn).hasClass('disabled')) { e.preventDefault(); return; }
398 var run = async function(){
399 e.preventDefault();
400 var orderId = localStorage.getItem('salesOrderId');
401 var entryType = ($card.data('entrytype') || 'Norma');
402 var code = ($card.data('code') || '').toString();
403 var $langSel = $card.find('.select-language');
404 var $fmtSel = $card.find('.select-format');
405 var codIdioma = ($langSel.filter(function(){ return this.value; }).first().val() || $langSel.val() || '').toString();
406 var codFormato = ($fmtSel.filter(function(){ return this.value; }).first().val() || $fmtSel.val() || '').toString();
407 if ((!codIdioma || !codFormato) && data && data.length){
408 codIdioma = codIdioma || (data[0].language || data[0].codLanguage || '');
409 codFormato = codFormato || (data[0].format || data[0].codFormat || '');
410 }
411 if (!code) { code = ($card.find('.title-standard').text() || '').trim(); }
412 var priceToSend = Number(priceOf(codIdioma, codFormato)) || 0;
413 var resolvedId = await resolveProductId(entryType, code, codIdioma, codFormato);
414 if (!resolvedId) {
415 emitCartError('Error al añadir el producto a la cesta');
416 return;
417 }
418 var productIdForCart = resolvedId;
419 if (orderId) {
420 var host = await getApiHost();
421 if (!host) {
422 emitCartError('Error al añadir el producto a la cesta');
423 return;
424 }
425 var payload = {
426 salesorderid: orderId || '',
427 amount: 1,
428 productid: productIdForCart,
429 price: priceToSend,
430 name: ($card.data('title') || '').toString(),
431 idioma: codIdioma,
432 formato: codFormato
433 };
434 bumpBadge(1);
435 fetch(host + '/shoppingProcess/newSalesOrderProduct', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(payload), credentials:'omit' })
436 .then(function(r){ if(!r.ok) throw new Error('HTTP '+r.status); setTimeout(function(){ window.dispatchEvent(new CustomEvent('cart:updated')); }, 300); })
437 .catch(function(){ bumpBadge(-1); emitCartError('Error al añadir el producto a la cesta'); });
438 } else {
439 queueItem({ amount: 1, productid: productIdForCart, price: priceToSend, name: ($card.data('title')||'').toString(), idioma: codIdioma, formato: codFormato });
440 bumpBadge(1);
441 }
442 };
443 var helper = window.ecomGlobalScripts?.functions?.withButtonSpinner;
444 if (typeof helper === 'function') {
445 return helper(btn, run, { spinnerClass: 'spinner-border spinner-border-sm text-light', mode: 'replace' });
446 }
447 return run();
448 });
449 }
450
451 // Alturas por fila
452 function adjustHeightsByRow(){
453 var $cards = $('.list-standards-section .item-standard');
454 var $titles = $cards.find('.title-standard');
455 var $descs = $cards.find('.description-text');
456 var $infos = $cards.find('.info-standard');
457
458 $cards.css('height','auto');
459 $titles.css('height','auto');
460 $descs.css('height','auto');
461 $infos.css('height','auto');
462
463 if($(window).width() <= 767.98) return;
464
465 var rows = [];
466 var tol = 4; // tolerancia de alineación
467 $cards.each(function(){
468 var $c = $(this);
469 var top = Math.round($c.position().top);
470 var row = rows.find(function(r){ return Math.abs(r.top - top) <= tol; });
471 if(!row){ row = { top: top, cards: [] }; rows.push(row); }
472 row.cards.push($c);
473 });
474
475 rows.forEach(function(r){
476 var hCard = 0, hTitle = 0, hDesc = 0, hInfo = 0;
477 r.cards.forEach(function($c){
478 hCard = Math.max(hCard, $c.outerHeight());
479 hTitle = Math.max(hTitle, $c.find('.title-standard').outerHeight());
480 hDesc = Math.max(hDesc, $c.find('.description-text').outerHeight());
481 hInfo = Math.max(hInfo, $c.find('.info-standard').outerHeight());
482 });
483 r.cards.forEach(function($c){
484 $c.height(hCard);
485 $c.find('.title-standard').height(hTitle);
486 $c.find('.description-text').height(hDesc);
487 $c.find('.info-standard').height(hInfo);
488 });
489 });
490 }
491
492 async function init(){
493 $('.list-standards-section .item-standard').each(function(){ initStandardCard($(this)); });
494 adjustHeightsByRow();
495 setTimeout(adjustHeightsByRow, 50);
496 }
497
498 var so = localStorage.getItem('salesOrderId'); // flushQueue gestionado por header
499 await init();
500 $(window).on('resize', init);
501});
502</script>
503
504<style>
505.list-standards-section { margin: 40px auto 35px; }
506.list-standards-section .header-section { border-bottom: 1px solid #dbdbdb; margin-bottom: 32px; display: flex; justify-content: space-between; margin-left: 2px; margin-right: 2px; align-items: center; }
507.list-standards-section .header-section .order-elements { font-family: Segoe-UI-This; font-size: 16px; font-weight: 400; line-height: 23px; text-align: left; color: #2d2d2b; }
508.list-standards-section .title-section { font-family: SohoStd-Medium; font-size: 24px; font-weight: 500; line-height: 28.8px; text-align: left; color: var(--brand-color-3, #29337f); }
509.list-standards-section .standards-container { display: flex; flex-wrap: wrap; gap: 20px 0; padding-right: 0; padding-left: 0; }
510.list-standards-section .item-standard { position: relative; border: 1px solid #e0e0e0; padding: 16px 14px; border-radius: 4px; display: flex; flex-direction: column; }
511.list-standards-section .tag-standard { position: absolute; top: -10px; left: 16px; padding: 4px 10px; border-radius: 4px; background-color: #6a9bd3; color: #fff; font-weight: bold; font-size: 12px; z-index: 5; }
512.list-standards-section .date-ISO { font-family: Segoe-UI-This; font-size: 14px; font-weight: 400; line-height: 18.62px; text-align: left; color: #444; }
513.list-standards-section .title-standard { font-family: SohoGothicPro-Regular; font-size: 16px; font-weight: bold; color: #1a4b94; line-height: 24px; text-align: left; padding-top: 10px;}
514.list-standards-section .description-text { margin-top: 10px; margin-bottom: 12px; font-family: SohoGothicPro-Regular; font-weight: 400; line-height: 24px; font-size: 13px; text-align: left; color: #333; }
515.list-standards-section .info-standard { display: flex; flex-direction: column; flex: 1; }
516.list-standards-section .info-standard .status-box .tag-success {background: #2a7a36; color: #fff;}
517.list-standards-section .info-standard .status-box .tag-danger {background: #c00000; color: #fff;}
518.list-standards-section .info-standard .status-box .tag-blue {background: #0078c0; color: #fff;}
519.list-standards-section .price-container { display: flex; flex-direction: column; text-align: left; letter-spacing: -0.02em; margin-top: auto; margin-bottom: 16px; }
520.list-standards-section .price-container .price-ae { font-size: 23px; font-weight: bold; line-height: 22px; margin-bottom: 10px; color: var(--brand-color-1, #1f57a3); }
521.list-standards-section .standard-not-available {
522 border-style: solid;
523 border-width: 2px;
524 background-color: #f2dede;
525 border-color: #ebcccc;
526 color: #a94442;
527 margin-left: -2px !important;
528 padding-left: 4px !important;
529 margin-top: 25px;
530}
531.list-standards-section .standard-button { border: 0; outline: 0; box-shadow: none; appearance: none; -webkit-appearance: none; -moz-appearance: none; padding: 17px; width: 100%; text-align: center; display: block; background-color: var(--brand-color-1, #1f57a3); color: #fff; text-transform: uppercase; font-family: SohoStd-Medium; font-size: 14px; font-weight: 500; line-height: 14px; cursor: pointer; text-decoration: none; }
532.list-standards-section .standard-button.disabled,
533.list-standards-section .standard-button.ecom-btn-loading {
534 opacity: .6;
535 pointer-events: none;
536 filter: brightness(0.85);
537}
538.list-standards-section .standard-button:hover,
539.list-standards-section .standard-button:focus,
540.list-standards-section .standard-button:focus-visible,
541.list-standards-section .standard-button:active {
542 background-color: var(--brand-color-1, #1f57a3);
543 color: #fff;
544 text-decoration: none;
545 outline: 2px solid var(--brand-color-2, #6a9bd3);
546 outline-offset: 2px;
547 box-shadow: 0 0 0 3px rgba(106, 155, 211, 0.35);
548}
549.list-standards-section .standard-button:active {
550 filter: brightness(0.85);
551}
552.list-standards-section .view-grid{ gap: 20px 3.5%; }
553.list-standards-section .view-grid .item-standard { width: 31%; }
554@media (max-width:1200px){ .list-standards-section .view-grid .item-standard { width: 48%; } }
555@media (max-width: 576px) { .list-standards-section .view-grid .item-standard { width: 100%; } }
556.options-standard { display: flex; gap: 10px; margin-bottom: 16px; border: none; }
557.options-standard .select-language,
558.options-standard .select-format {
559 background-color: #f5f5f5;
560 border: 1px solid #d0d0d0;
561 color: #2d2d2b;
562 font-size: 13px;
563 height: 38px;
564}
565.options-standard .select-language:disabled,
566.options-standard .select-format:disabled {
567 background-color: #f5f5f5;
568 color: #2d2d2b;
569 opacity: 1;
570}
571.options-standard .select-language { flex: 2; }
572.options-standard .select-format { flex: 1; }
573select.form-control,
574select.form-control:focus,
575select.form-control:focus-visible {
576 background-image: url(/documents/d/global/ico-chevron-down);
577 background-size: 18px 10px;
578 background-position-x: 95%;
579 background-repeat: no-repeat;
580 position: relative;
581}
582.status-standard { margin-right: 10px; background-color: #107510; color: white; font-size: 12px; padding: 2px 6px; border-radius: 3px; font-weight: bold; }
583.date-standard { font-size: 12px; color: #666; }
584.js-checks-container { display: none; }
585</style>










