/* Additions to the mockup's stylesheet: the pages the mockup didn't cover
   (sign-in, set-password, admin) plus flash messages. Same tokens throughout —
   nothing new is invented, only reused. */

/* flash messages */
.flashes{padding:16px 0 0}
.flash{
  border-left:4px solid var(--ok);background:var(--ok-wash);color:var(--body);
  padding:13px 17px;border-radius:0 3px 3px 0;font-size:15px;margin:0 0 10px;
}
.flash.err{border-left-color:var(--bad);background:var(--bad-wash)}
.flash b{color:var(--ink);font-weight:600;text-transform:uppercase;letter-spacing:.06em;font-size:13px;display:block;margin-bottom:3px}

/* auth pages */
.authwrap{max-width:520px;margin:0 auto;padding:56px 24px 72px}
.authcard{background:var(--card);border:1px solid var(--line);border-radius:3px;overflow:hidden}
.authcard .head{background:var(--band);border-bottom:1px solid var(--line);padding:20px 24px}
.authcard .head h1{font-size:22px}
.authcard .body{padding:24px}
.authcard .f{margin-bottom:14px}
.authcard .btn{width:100%}
.authmeta{margin-top:18px;font-size:14px;color:var(--muted);text-align:center}
.authmeta a{color:var(--orange-txt);font-weight:600;text-decoration:none}

/* admin */
.adminbar{background:var(--band-2);border-bottom:1px solid var(--line)}
.adminbar .inner{max-width:1180px;margin:0 auto;padding:11px 24px;display:flex;gap:22px;align-items:center;flex-wrap:wrap;font-size:14px}
.adminbar a{color:var(--ink);font-weight:600;text-decoration:none;text-transform:uppercase;letter-spacing:.06em;font-size:13px}
.adminbar a:hover{color:var(--orange-txt)}
.adminbar .push{flex:1 1 auto}
table.admin{min-width:900px}
table.admin td .chip{font-size:11.5px;padding:4px 8px}
.adminform{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:14px;align-items:end}
.adminform .f.s1{grid-column:span 1}
.adminform .f.s2{grid-column:span 2}
.adminform .f.s3{grid-column:span 3}
.adminform .f.s6{grid-column:span 6}
.adminform select,.adminform input{font-family:inherit;font-size:15px;color:var(--ink);background:var(--field);
  border:1px solid var(--line-2);border-radius:3px;padding:10px 11px;width:100%}
@media (max-width:760px){.adminform .f.s1,.adminform .f.s2,.adminform .f.s3{grid-column:span 6}}
.stack{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
.linkish{color:var(--orange-txt);font-weight:600;text-decoration:none}
.subtle{color:var(--muted);font-size:13.5px}
code.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;color:var(--ink);
  background:var(--band-2);padding:2px 6px;border-radius:3px;overflow-wrap:anywhere}

/* ══════════════════════════════════════════════════════════════════════
   INLINE-STYLE REPLACEMENTS
   The app sends `style-src 'self'` with no 'unsafe-inline', so the browser
   discards every style="" attribute. The mockup is a standalone file with no
   CSP, so its 47 inline styles render there and were silently dropped here —
   blank colour swatches being the visible symptom, dozens of wrong margins
   being the rest. These classes are a *literal* port of those values, named
   after the value itself so the port stays checkable against the mockup line
   by line. Loosening the CSP was the wrong fix: this page renders
   creator-entered text and winners' addresses.
   ══════════════════════════════════════════════════════════════════════ */

/* spacing — margin-bottom only */
.mb-10{margin-bottom:10px}
.mb-11{margin-bottom:11px}
.mb-12{margin-bottom:12px}
.mb-14{margin-bottom:14px}
.mb-18{margin-bottom:18px}
/* spacing — margin-top only */
.mt-8{margin-top:8px}
.mt-10{margin-top:10px}
.mt-12{margin-top:12px}
.mt-14{margin-top:14px}
.mt-16{margin-top:16px}
.mt-18{margin-top:18px}
.mt-20{margin-top:20px}
.mt-22{margin-top:22px}
/* full block margins — also zero the UA <p> side and bottom margins */
.gap-10{margin:10px 0 0}
.gap-12{margin:12px 0 0}
.gap-14{margin:14px 0 0}
.gap-16{margin:16px 0 0}
.gap-20{margin:20px 0 0}
.gap-12-22{margin:12px 0 22px}
.gap-16-22{margin:16px 0 22px}
.gap-b20{margin:0 0 20px}

/* colour and weight emphasis */
.ink{color:var(--ink)}
.orange-txt{color:var(--orange-txt)}
.bad-txt{color:var(--bad)}
.fs-13{font-size:13px}
.v.big{font-size:22px;font-weight:600}
.v.big.is-orange{color:var(--orange)}

/* small layout blocks lifted from the mockup */
.actionrow{display:flex;gap:16px;align-items:center;flex-wrap:wrap;margin-top:20px}
.btnrow{display:flex;gap:12px;flex-wrap:wrap}
.tablehead{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;margin-bottom:14px}
.note.flexnote{flex:1 1 320px;min-width:0}
.note.lede-note{margin:20px 0 0;font-size:16px;max-width:64ch}
.note.wide-note{margin-top:18px;max-width:88ch}
.f.bottom{justify-content:flex-end}
.inline{display:inline}
.hero.compact{padding:32px 0 22px}
table.admin.narrow{min-width:520px}
/* a checkbox that should actually be visible inside a .sw pill */
.sw input.cb{position:static;opacity:1;width:auto;height:auto}

/* ══════════════════════════════════════════════════════════════════════
   STAGED PROGRESSION
   One programme unfolding through its stages, not four independent cards
   side by side (Yaniv, 2026-08-05: "After Shipped with tracking we can fold
   to another step the activate coupon stage"). Built on <details>/<summary>
   so folding works with no JavaScript and is keyboard-operable for free.
   A finished stage folds to a one-line summary — the information is never
   deleted, it just stops competing for attention.
   ══════════════════════════════════════════════════════════════════════ */
.stage{scroll-margin-top:16px}
.stage > details > summary{
  list-style:none;cursor:pointer;
  background:var(--band);border-bottom:1px solid var(--line);
  padding:16px 20px;display:flex;align-items:flex-start;gap:14px;flex-wrap:wrap;
}
.stage > details > summary::-webkit-details-marker{display:none}
.stage > details:not([open]) > summary{border-bottom:0}
.stage > details > summary:hover{background:var(--band-2)}
.stage > details > summary:focus-visible{outline:2px solid var(--orange);outline-offset:-2px}
.stage summary .t{min-width:0;flex:1 1 240px}
.stage summary h2{font-size:19px}
.stage summary .gate{margin-top:11px;font-size:13.5px;color:var(--muted)}
.stage summary .gate b{color:var(--ink);font-weight:600}

/* the step marker: 1 · 2 · 3, then an ONGOING pill for commission */
.step{
  width:30px;height:30px;flex:0 0 auto;border-radius:50%;margin-top:2px;
  display:grid;place-items:center;font-weight:600;font-size:14px;
  background:var(--card);border:1px solid var(--line-2);color:var(--muted);
}
.step.done{background:var(--ok);border-color:var(--ok);color:#fff}
.step.now{background:var(--orange);border-color:var(--orange);color:#000}
.step.ongoing{
  width:auto;height:auto;border-radius:3px;padding:7px 10px;
  font-size:11px;letter-spacing:.1em;text-transform:uppercase;
}
.chev{flex:0 0 auto;margin-top:7px;color:var(--muted);transition:transform .15s ease}
.stage > details[open] > summary .chev{transform:rotate(180deg)}
/* "you are here" — a quiet accent, never a badge that shouts */
.stage.is-now{box-shadow:inset 3px 0 0 var(--orange)}
.stage.is-done > details:not([open]) > summary h2{color:var(--body)}
@media (max-width:520px){
  .stage summary .chev{display:none}
  .step{width:26px;height:26px;font-size:13px}
}

/* ══════════════════════════════════════════════════════════════════════
   MORE INFO / CREATOR VIDEOS
   The two reference cards at the bottom of the portal: setup footage,
   credentials, downloads, roadmap, and other creators' videos. Ported from
   the approved standalone mockup (build_portal_page.py, 8 Aug) — the same
   rules, with its data: URIs swapped for real /static/media files and its
   one inline style moved to .tile .val.words in portal.css, because
   `style-src 'self'` discards style="" attributes on this page.
   ══════════════════════════════════════════════════════════════════════ */

/* --- resource rows --- */
.reslist{display:flex; flex-direction:column}
.resrow{
  display:flex; gap:14px; align-items:center;
  padding:14px 0; border-top:1px solid var(--line);
}
.resitem:first-child > .resrow{border-top:0; padding-top:0}
.restype{
  flex:none; width:48px; height:48px; border-radius:5px; display:grid; place-items:center;
  background:var(--band); border:1px solid var(--line); color:var(--body);
  font-size:10px; font-weight:700; letter-spacing:.06em;
}
.restype.hot{background:var(--orange-wash); border-color:var(--orange-line); color:var(--orange-txt)}
.resmeta{flex:1; min-width:0; display:flex; flex-direction:column; gap:3px}
.resmeta .rt{font-size:15.5px; font-weight:700; color:var(--ink); line-height:1.25}
.resmeta .rs{font-size:13px; color:var(--muted); line-height:1.45}

/* --- video grid --- */
.vgrid{display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:16px}
.vcard{border:1px solid var(--line); background:var(--card); display:flex; flex-direction:column}
.vcard video{width:100%; display:block; background:#111; aspect-ratio:16/9; object-fit:cover}
.vcard .vmeta{padding:11px 13px; display:flex; flex-direction:column; gap:3px}
.vcard .vmeta .vt{font-size:14.5px; font-weight:700; color:var(--ink); line-height:1.3}
.vcard .vmeta .vs{font-size:12.5px; color:var(--muted); line-height:1.4}

/* --- download rows that fold open to a preview --- */
.resitem > summary{list-style:none; cursor:pointer}
.resitem > summary::-webkit-details-marker{display:none}
.resitem > summary:hover .rt{color:var(--orange-txt)}
.respeek{
  flex:none; display:flex; align-items:center; gap:6px;
  font-size:11.5px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  color:var(--muted);
}
.rescv{display:inline-block; font-size:9px; transition:transform .15s ease}
.resitem[open] > summary .rescv{transform:rotate(180deg)}
.respane{padding:2px 0 18px}
/* The summary row already carries the top border; the pane must not add another */
.resitem[open] > summary{border-bottom:0}

/* --- embedded YouTube (creator videos) ---
   The embeds point at youtube-nocookie.com, the single external host main.py's
   frame-src allows. Nothing is layered BEHIND these frames: a browser that
   refuses to load a frame paints its own error page over everything inside it,
   so a fallback there is invisible exactly when it is needed (measured — an
   earlier revision did it that way). The durable link is .ytlink, below the
   frame and outside it. */
.ytgrid{display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:16px; align-items:start}
.ytcard{border:1px solid var(--line); background:var(--card); display:flex; flex-direction:column}
.ytframe{position:relative; background:#0E0E0E; overflow:hidden}
.ytframe.short{aspect-ratio:9/16; max-height:520px}
.ytframe.wide{aspect-ratio:16/9}
.ytframe iframe{position:absolute; inset:0; width:100%; height:100%; border:0; display:block}
.ytmeta{padding:12px 14px; display:flex; flex-direction:column; gap:3px}
.ytt{font-size:15px; font-weight:700; color:var(--ink); line-height:1.3}
.yts{font-size:12.5px; color:var(--muted)}
.yts b{color:var(--body); font-weight:650}
/* The route that always works, whatever an ad-blocker, a corporate proxy or a
   future header change does to the frame above it. */
.ytlink, .reslink{
  align-self:flex-start; display:inline-block;
  font-size:12.5px; font-weight:700; letter-spacing:.04em;
  color:var(--orange-txt); text-decoration:none;
}
.ytlink{margin-top:6px}
.ytlink:hover, .reslink:hover{text-decoration:underline}

/* --- nested collapsible section (What's coming) --- */
.subsection{border:1px solid var(--line); background:var(--band)}
.subsection > .subsum{
  list-style:none; cursor:pointer; padding:13px 15px;
  display:flex; align-items:center; gap:12px;
}
.subsection > .subsum::-webkit-details-marker{display:none}
.subsection[open] > .subsum{border-bottom:1px solid var(--line)}
.subsection > .subsum:hover .subt{color:var(--orange-txt)}
.subt{font-size:15.5px; font-weight:700; color:var(--ink)}
.subhint{flex:1; font-size:13px; color:var(--muted); min-width:0}
.subsection[open] > .subsum .rescv{transform:rotate(180deg)}
.subpane{padding:15px}

/* --- certification row: optically-weighted badges (Yaniv, 7 Aug) --- */
.certrow{
  display:flex; align-items:flex-end; justify-content:flex-start;
  gap:26px; flex-wrap:wrap; padding:20px 0 4px;
}
.certrow figure{margin:0; display:flex; flex-direction:column; align-items:center; gap:8px}
/* The badge artwork is OPAQUE, not transparent — five have solid white grounds
   and NATO has a near-black one. Dropped straight onto a card they'd be white
   slabs in dark mode and NATO would vanish. Seating every badge on its own
   white chip makes them consistent in both themes and reads as a credential
   rather than a floating cutout. */
.certrow .cchip{
  background:#FFFFFF; border:1px solid rgba(0,0,0,.14); border-radius:4px;
  padding:9px 11px; display:flex; align-items:center; justify-content:center;
}
/* Each PNG was trimmed of its (wildly uneven, 1%–45%) padding, then sized by
   OPTICAL WEIGHT, not by bounding box and not by one edge.
   Why not bounding box: these marks range from 28% ink coverage (ISO — fine
   line-art) to 95% (NATO — a filled rectangle). Equal boxes made ISO read as
   noticeably smaller than NATO even though the boxes matched.
   Why not equal ink either: that overcorrects, collapsing a solid rectangle to
   a stamp. So the scale is damped — linear factor (median_ink/ink)^0.25 — which
   nudges light line-art up and heavy solids down without either extreme.
   Each one's resulting display size is baked into its width/height attributes.
   Do NOT add a max-height or max-width here: a shared cap re-scales a wide mark
   and a tall mark differently and undoes all of it. */
.certrow img{display:block; max-width:100%; height:auto}
.certrow figcaption{
  font-size:9.5px; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
  color:var(--muted); text-align:center; line-height:1.3;
}
.certrow figcaption b{display:block; font-size:11.5px; color:var(--ink); letter-spacing:.04em}

/* --- roadmap --- */
.road{display:flex; flex-direction:column}
.roadrow{
  display:flex; gap:16px; align-items:flex-start;
  padding:14px 0; border-top:1px solid var(--line);
}
.roadrow:first-child{border-top:0; padding-top:2px}
.roadwhen{
  flex:none; width:104px; padding-top:2px;
  font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
  color:var(--orange-txt);
}
.roadwhat{flex:1; min-width:0; display:flex; flex-direction:column; gap:3px}
.roadwhat .rn{font-size:15.5px; font-weight:700; color:var(--ink); line-height:1.25}
.roadwhat .rd{font-size:13.5px; color:var(--muted); line-height:1.45}
.tbd{
  font-size:9.5px; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted); border:1px solid var(--line-2); border-radius:3px;
  padding:2px 5px; margin-left:8px; vertical-align:middle;
}
/* The insider line rides the same row, right-aligned and understated. A boxed
   CONFIDENTIAL banner performs secrecy; two words in the margin read like a
   confidence. */
.roadaside{
  flex:none; max-width:186px; text-align:right; padding-top:3px;
  font-size:13px; color:var(--muted); line-height:1.35;
}
.roadaside .ral{
  display:block; font-size:9px; font-weight:700; letter-spacing:.14em;
  text-transform:uppercase; color:var(--muted); margin-bottom:2px;
}

/* --- logo previews ---
   Neutral well behind each mark (Yaniv, 8 Aug). These are transparent PNGs, so
   without a ground one of the two always disappears — the white mark vanishes
   on a light card, the charcoal one on a dark card. Each therefore sits on the
   ground it was drawn for, in muted greys rather than pure white/black so the
   well reads as recessed rather than as a colour statement. Identical in both
   themes on purpose: the point is to show the asset, not the page. */
.logorow{display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:16px}
.logobox{border:1px solid var(--line); overflow:hidden; background:transparent}
.logobox .lswatch{
  min-height:126px; padding:20px;
  display:flex; align-items:center; justify-content:center;
}
.logobox .lswatch.well-dark{background:#232323}
.logobox .lswatch.well-light{background:#F4F4F4}
.logobox .lswatch img{max-width:100%; max-height:80px; width:auto; height:auto; display:block}
.logobox .lcap{
  padding:9px 12px; border-top:1px solid var(--line); background:var(--band);
  font-size:12px; color:var(--muted);
}
.logobox .lcap b{display:block; color:var(--ink); font-size:12.5px}

/* Plain, no orange box (Yaniv, 8 Aug). A warranty this good doesn't need a
   highlight panel to be noticed — boxing it made it read as a promotion. The
   seal alone carries it. */
.warrline{
  display:flex; gap:18px; align-items:flex-start;
  background:transparent; border:0; padding:2px 0;
}
.warrline img{width:64px; height:auto; flex:none}
.warrline .wtxt{display:flex; flex-direction:column; gap:7px}
.warrline .wh{
  font-size:12px; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--orange-txt);
}
.warrline .wb{font-size:14.5px; color:var(--ink); line-height:1.55}

.subhead{
  font-size:16px; font-weight:700; color:var(--ink); line-height:1.25;
  padding-top:4px;
}
.blockgap{display:flex; flex-direction:column; gap:10px}

@media (max-width:640px){
  .roadrow{flex-wrap:wrap}
  .roadaside{max-width:none; text-align:left; padding-top:8px; flex:1 1 100%}
  .roadwhen{width:80px}
  /* Scale the whole row, never the individual images. Capping max-height or
     max-width here re-broke the equal-ink sizing at mobile (spread went back
     to 21%) — the same mistake as the desktop rule above. zoom scales every
     badge by the identical factor and still reflows. */
  .certrow{gap:16px 18px; zoom:.82}
  .certrow .cchip{padding:7px 9px}
}

/* Narrow phones: the download row's fixed furniture (48px type badge, the
   "Preview" label, a padded Download button) does not fit beside the title at
   320px — measured, the button ended 28px past the row and the title was
   squeezed to zero width. Wrap it, and drop the redundant "Preview" label since
   tapping the row is what opens the preview anyway. */
@media (max-width:640px){
  .resrow{flex-wrap:wrap; row-gap:10px}
  .resmeta{flex:1 1 100%; order:2}
  .restype{order:1}
  .respeek{display:none}
  .resrow .btn{order:3; margin-left:auto}
}
