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#65792029" 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#65792029" 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 = "/web/tienda/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 = "/web/tienda/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-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 <div data-productid="${productId}" data-erc="${productERC}" class="options-standard selector-language_format">
150 <#if hasOptions>
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 <#else>
166 <select class="form-control select-language" disabled><option>–</option></select>
167 <select class="form-control select-format" disabled><option>–</option></select>
168 </#if>
169 </div>
170
171 <a href="#"
172 class="standard-button <#if !hasOptions>disabled</#if>"
173 aria-disabled="<#if !hasOptions>true<#else>false</#if>">
174 <#if hasOptions>Añadir a la cesta<#else>No disponible</#if>
175 </a>
176 </div>
177
178 <#-- Datos para JS -->
179 <#if hasOptions>
180 <script type="application/json" class="normas-data">[
181 <#list normasDetails as n>
182 <#-- solo pares válidos -->
183 <#if (n.language?? && n.language?has_content) && (n.format?? && n.format?has_content)>
184 {
185 "format": "${(n.format!"")?js_string}",
186 "language": "${(n.language!"")?js_string}",
187 "price": ${(n.price!'0')?c}
188 }<#if n_has_next>,</#if>
189 </#if>
190 </#list>
191 ]</script>
192 <script type="application/json" class="lang-map">{
193 <#list languages as l>
194 "${(l!"")?upper_case?js_string}": "${langLiteral(l)?js_string}"<#if l_has_next>,</#if>
195 </#list>
196 }</script>
197 </#if>
198 </div>
199 </#list>
200 <#else>
201 <div class="search-results-add-custom-empty-message"></div>
202 </#if>
203 </div>
204</section>
205
206<#-- ===== Helpers REST ===== -->
207<#function getChannelId>
208 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?filter=name eq 'Aenor España'&sort").items[0].id>
209</#function>
210
211<#function getProduct channelId name>
212 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products?filter=name eq '${name?url}'&sort").items[0]>
213</#function>
214
215<#function getProductCategories channelId productId>
216 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/categories?sort").items>
217</#function>
218
219<#function getProductSpecifications channelId productId>
220 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/product-specifications?sort").items>
221</#function>
222
223<#function getCurrentStateDate specifications>
224 <#list specifications as specification>
225 <#if specification.specificationKey == 'current-state-date'>
226 <#return specification.value>
227 </#if>
228 </#list>
229</#function>
230
231<#function getStatus categories>
232 <#list categories as category>
233 <#if category.vocabulary == 'status'>
234 <#return category.title>
235 </#if>
236 </#list>
237</#function>
238
239<#function getOrganism categories>
240 <#list categories as category>
241 <#if category.vocabulary == 'organismos'>
242 <#return category.name>
243 </#if>
244 </#list>
245</#function>
246
247<#function getNormasDetails productId>
248 <#return restClient.get("/c/standards/?filter=r_standards_CPDefinitionId eq '${productId}'").items>
249</#function>
250
251<script>
252jQuery(async function($){
253 let API_HOST = null;
254 function euros(v){
255 var n = Number(v) || 0;
256 return n.toLocaleString('es-ES', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' €';
257 }
258 function uniq(a){ return Array.from(new Set(a)); }
259
260 async function waitForEcomGlobalScripts(timeoutMs){
261 const start = Date.now();
262 return new Promise((resolve, reject) => {
263 (function check(){
264 if (window.ecomGlobalScripts?.functions?.getFieldCXCustomConfig && window.ecomGlobalScripts?.properties?.cxCustomConfigsNames) {
265 return resolve();
266 }
267 if (Date.now() - start > timeoutMs) return reject(new Error('ecomGlobalScripts no disponible a tiempo'));
268 requestAnimationFrame(check);
269 })();
270 });
271 }
272
273 const getApiHost = async () => {
274 if (API_HOST) return API_HOST;
275 try {
276 await waitForEcomGlobalScripts(5000);
277 API_HOST = await window.ecomGlobalScripts.functions.getFieldCXCustomConfig(
278 window.ecomGlobalScripts.properties.cxCustomConfigsNames.defaultName, "webApiUrl"
279 );
280 } catch (err) {
281 console.error('No se pudo resolver API_HOST', err);
282 }
283 return API_HOST;
284 };
285
286 function fill($sel, values, textFn){
287 var keep = $sel.val();
288 $sel.empty();
289 values.forEach(function(v){
290 $sel.append($('<option>', { value: v, text: textFn ? textFn(v) : v }));
291 });
292 if(keep && values.indexOf(keep) !== -1){ $sel.val(keep); }
293 else if(values.length){ $sel.val(values[0]); }
294 }
295
296 function relabel($sel, textFn){
297 $sel.find('option').each(function(){
298 var v = $(this).attr('value');
299 $(this).text(textFn ? textFn(v) : v);
300 });
301 }
302
303 function toUC(s){ return (s||'').toString().toUpperCase(); }
304 function emitCartError(msg){
305 try {
306 window.dispatchEvent(new CustomEvent('cart:error', { detail: { message: msg || 'Error al añadir el producto a la cesta' } }));
307 } catch (e) {}
308 }
309 async function resolveProductId(entryType, code, codIdioma, codFormato){
310 const host = await getApiHost();
311 if (!host) return '';
312 try{
313 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' });
314 if(!res.ok) throw new Error('HTTP '+res.status);
315 var data = await res.json();
316 return (data && (data.id)) || '';
317 } catch(e){ return ''; }
318 }
319 function getQueue(){ try { return JSON.parse(localStorage.getItem('cartQueued') || '[]'); } catch(e){ return []; } }
320 function setQueue(q){ localStorage.setItem('cartQueued', JSON.stringify(q)); }
321 function queueItem(item){
322 var q=getQueue();
323 var pid=(item&&item.productid)?String(item.productid):'';
324 var amt=Number(item&&item.amount)||1;
325 var prc=(item&&typeof item.price!=='undefined')?Number(item.price):undefined;
326 var nm =(item&&typeof item.name!=='undefined')?String(item.name):undefined;
327 var ci =(item&&typeof item.idioma!=='undefined')?String(item.idioma):undefined;
328 var cf =(item&&typeof item.formato!=='undefined')?String(item.formato):undefined;
329 if(!pid) return;
330 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; } }
331 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;} }
332 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); }
333 setQueue(q);
334 }
335 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 }})); }
336
337 function initStandardCard($card){
338 var dataNode = $card.find('script.normas-data')[0];
339 if(!dataNode) return; // sin datos -> nada que sincronizar
340
341 var data = [];
342 try { data = JSON.parse(dataNode.textContent); } catch(e) { data = []; }
343 if(!data.length) return;
344
345 var mapNode = $card.find('script.lang-map')[0];
346 var langMap = {};
347 try { if(mapNode) langMap = JSON.parse(mapNode.textContent); } catch(e) { langMap = {}; }
348
349 var $lang = $card.find('.select-language');
350 var $fmt = $card.find('.select-format');
351 var $price = $card.find('.price-ae');
352
353 function labelOf(lang){ return langMap[toUC(lang)] || lang; }
354 function formatsFor(lang){
355 return uniq(data.filter(function(d){ return d.language === lang; }).map(function(d){ return d.format; }));
356 }
357 function languagesFor(fmt){
358 return uniq(data.filter(function(d){ return d.format === fmt; }).map(function(d){ return d.language; }));
359 }
360 function priceOf(lang, fmt){
361 var m = data.find(function(d){ return d.language === lang && d.format === fmt; });
362 return m ? Number(m.price) || 0 : 0;
363 }
364
365 function onLanguageChange(){
366 var lang = $lang.val();
367 var fmts = formatsFor(lang);
368 fill($fmt, fmts, null);
369 $price.text(euros(priceOf(lang, $fmt.val())));
370 }
371 function onFormatChange(){
372 var fmt = $fmt.val();
373 var langs = languagesFor(fmt);
374 fill($lang, langs, labelOf);
375 $price.text(euros(priceOf($lang.val(), fmt)));
376 }
377
378 var l0 = $lang.val();
379 var f0 = $fmt.val();
380 if(!data.find(function(d){ return d.language === l0 && d.format === f0; })){
381 onLanguageChange();
382 } else {
383 $price.text(euros(priceOf(l0, f0)));
384 }
385
386 relabel($lang, labelOf); // literal de idioma
387
388 $lang.off('change.std').on('change.std', onLanguageChange);
389 $fmt.off('change.std').on('change.std', onFormatChange);
390
391 // Añadir a la cesta
392 $card.find('.standard-button').off('click.add').on('click.add', async function(e){
393 e.preventDefault();
394 var orderId = localStorage.getItem('salesOrderId');
395 var entryType = ($card.data('entrytype') || 'Norma');
396 var code = ($card.data('code') || '').toString();
397 var codIdioma = ($lang.val() || '').toString();
398 var codFormato = ($fmt.val() || '').toString();
399 if (!code) { code = ($card.find('.title-standard').text() || '').trim(); }
400 var priceToSend = Number(priceOf($lang.val(), $fmt.val())) || 0;
401 var resolvedId = await resolveProductId(entryType, code, codIdioma, codFormato);
402 if (!resolvedId) {
403 emitCartError('Error al añadir el producto a la cesta');
404 return;
405 }
406 var productIdForCart = resolvedId;
407 if (orderId) {
408 var host = await getApiHost();
409 if (!host) {
410 emitCartError('Error al añadir el producto a la cesta');
411 return;
412 }
413 var payload = {
414 salesorderid: orderId || '',
415 amount: 1,
416 productid: productIdForCart,
417 price: priceToSend,
418 name: ($card.data('title') || '').toString(),
419 idioma: codIdioma,
420 formato: codFormato
421 };
422 bumpBadge(1);
423 fetch(host + '/shoppingProcess/newSalesOrderProduct', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(payload), credentials:'omit' })
424 .then(function(r){ if(!r.ok) throw new Error('HTTP '+r.status); setTimeout(function(){ window.dispatchEvent(new CustomEvent('cart:updated')); }, 300); })
425 .catch(function(){ bumpBadge(-1); emitCartError('Error al añadir el producto a la cesta'); });
426 } else {
427 queueItem({ amount: 1, productid: productIdForCart, price: priceToSend, name: ($card.data('title')||'').toString(), idioma: codIdioma, formato: codFormato });
428 bumpBadge(1);
429 }
430 });
431 }
432
433 // Alturas por fila
434 function adjustHeightsByRow(){
435 var $cards = $('.list-standards-section .item-standard');
436 var $titles = $cards.find('.title-standard');
437 var $descs = $cards.find('.description-text');
438 var $infos = $cards.find('.info-standard');
439
440 $cards.css('height','auto');
441 $titles.css('height','auto');
442 $descs.css('height','auto');
443 $infos.css('height','auto');
444
445 if($(window).width() <= 767.98) return;
446
447 var rows = [];
448 var tol = 4; // tolerancia de alineación
449 $cards.each(function(){
450 var $c = $(this);
451 var top = Math.round($c.position().top);
452 var row = rows.find(function(r){ return Math.abs(r.top - top) <= tol; });
453 if(!row){ row = { top: top, cards: [] }; rows.push(row); }
454 row.cards.push($c);
455 });
456
457 rows.forEach(function(r){
458 var hCard = 0, hTitle = 0, hDesc = 0, hInfo = 0;
459 r.cards.forEach(function($c){
460 hCard = Math.max(hCard, $c.outerHeight());
461 hTitle = Math.max(hTitle, $c.find('.title-standard').outerHeight());
462 hDesc = Math.max(hDesc, $c.find('.description-text').outerHeight());
463 hInfo = Math.max(hInfo, $c.find('.info-standard').outerHeight());
464 });
465 r.cards.forEach(function($c){
466 $c.height(hCard);
467 $c.find('.title-standard').height(hTitle);
468 $c.find('.description-text').height(hDesc);
469 $c.find('.info-standard').height(hInfo);
470 });
471 });
472 }
473
474 async function init(){
475 $('.list-standards-section .item-standard').each(function(){ initStandardCard($(this)); });
476 adjustHeightsByRow();
477 setTimeout(adjustHeightsByRow, 50);
478 }
479
480 var so = localStorage.getItem('salesOrderId'); // flushQueue gestionado por header
481 await init();
482 $(window).on('resize', init);
483});
484</script>
485
486<style>
487.list-standards-section { margin: 40px auto 35px; }
488.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; }
489.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; }
490.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); }
491.list-standards-section .standards-container { display: flex; flex-wrap: wrap; gap: 20px 0; padding-right: 0; padding-left: 0; }
492.list-standards-section .item-standard { position: relative; border: 1px solid #e0e0e0; padding: 16px 14px; border-radius: 4px; display: flex; flex-direction: column; }
493.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; }
494.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; }
495.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;}
496.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; }
497.list-standards-section .info-standard { display: flex; flex-direction: column; flex: 1; }
498.list-standards-section .info-standard .status-box .tag-success {background: #2a7a36; color: #fff;}
499.list-standards-section .info-standard .status-box .tag-danger {background: #c00000; color: #fff;}
500.list-standards-section .info-standard .status-box .tag-blue {background: #0078c0; color: #fff;}
501.list-standards-section .price-container { display: flex; flex-direction: column; text-align: left; letter-spacing: -0.02em; margin-top: auto; margin-bottom: 16px; }
502.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); }
503.list-standards-section .standard-button { 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; text-decoration: none; }
504.list-standards-section .standard-button.disabled { opacity: .6; pointer-events: none; }
505.list-standards-section .view-grid{ gap: 20px 3.5%; }
506.list-standards-section .view-grid .item-standard { width: 31%; }
507@media (max-width:1200px){ .list-standards-section .view-grid .item-standard { width: 48%; } }
508@media (max-width: 576px) { .list-standards-section .view-grid .item-standard { width: 100%; } }
509.options-standard { display: flex; gap: 10px; margin-bottom: 16px; border: none; }
510.options-standard .select-language,
511.options-standard .select-format {
512 background-color: #f5f5f5;
513 border: 1px solid #d0d0d0;
514 color: #2d2d2b;
515 font-size: 13px;
516 height: 38px;
517}
518.options-standard .select-language:disabled,
519.options-standard .select-format:disabled {
520 background-color: #f5f5f5;
521 color: #2d2d2b;
522 opacity: 1;
523}
524.options-standard .select-language { flex: 2; }
525.options-standard .select-format { flex: 1; }
526select.form-control,
527select.form-control:focus,
528select.form-control:focus-visible {
529 background-image: url(/documents/d/global/ico-chevron-down);
530 background-size: 18px 10px;
531 background-position-x: 95%;
532 background-repeat: no-repeat;
533 position: relative;
534}
535.status-standard { margin-right: 10px; background-color: #107510; color: white; font-size: 12px; padding: 2px 6px; border-radius: 3px; font-weight: bold; }
536.date-standard { font-size: 12px; color: #666; }
537.js-checks-container { display: none; }
538</style>









