php2shell-scanner.git

php2shell-scanner

~ Check PHP2Shell (CVE-2026-109618, CVE-2026-109619) from inside your server: distribution backports, missed restarts and interim mitigations, verdicts computed in the browser.
git clone https://github.com/debuman/php2shell-scanner.git

site/style.css (22901B)

      1 /* PHP2Shell exposure check.
      2    A working tool, not a landing page: input on the left, result on the right,
      3    reference data underneath. Light only. The crimson and warm neutrals come
      4    from sqzer.com; status colours are kept separate from the brand colour so
      5    "vulnerable" never reads as decoration. No inline styles: the CSP forbids
      6    them. */
      7 
      8 @font-face {
      9   font-family: "JetBrains Mono";
     10   src: url("fonts/jetbrains-mono-400.woff2") format("woff2");
     11   font-weight: 400;
     12   font-style: normal;
     13   font-display: swap;
     14 }
     15 @font-face {
     16   font-family: "JetBrains Mono";
     17   src: url("fonts/jetbrains-mono-700.woff2") format("woff2");
     18   font-weight: 700;
     19   font-style: normal;
     20   font-display: swap;
     21 }
     22 
     23 :root {
     24   --bg: #f6f4ef;
     25   --panel: #ffffff;
     26   --sunken: #f9f8f5;
     27   --code: #f3f1ec;
     28   --line: #e3ded4;
     29   --line-2: #cfc8bb;
     30   /* Edges of form controls: 3.8:1 on the white pane, 3.6:1 on the textarea fill
     31      (WCAG 1.4.11 asks for 3:1). --line and --line-2 stay for dividers. */
     32   --control: #8a8275;
     33   --text: #1c1915;
     34   --muted: #57524a;
     35   --faint: #6f695f;
     36   --brand: #a51c30;
     37   --brand-dark: #771120;
     38   --ink: #23201b;
     39 
     40   --ok: #067647;   --ok-bg: #ecfdf3;   --ok-line: #abefc6;
     41   --bad: #b42318;  --bad-bg: #fef3f2;  --bad-line: #fecdca;
     42   --warn: #b54708; --warn-bg: #fffaeb; --warn-line: #fedf89;
     43   --info: #344054; --info-bg: #f2f4f7; --info-line: #d0d5dd;
     44 
     45   /* Pretendard covers Hangul and Latin with one design and stays crisp at small sizes on Windows. */
     46   --sans: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, "Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans KR", "Segoe UI", Roboto, sans-serif;
     47   --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
     48   --radius: 6px;
     49   --max: 84rem;
     50   color-scheme: light;
     51 }
     52 
     53 *, *::before, *::after { box-sizing: border-box; }
     54 
     55 /* Everything is sized in rem, so the root size scales text and spacing together. */
     56 html { -webkit-text-size-adjust: 100%; font-size: 125%; }
     57 [hidden] { display: none !important; }
     58 body {
     59   margin: 0;
     60   background: var(--bg);
     61   color: var(--text);
     62   font-family: var(--sans);
     63   font-size: 0.9375rem;
     64   line-height: 1.55;
     65   -webkit-font-smoothing: antialiased;
     66 }
     67 
     68 a { color: var(--brand); text-decoration-thickness: 1px; text-underline-offset: 2px; }
     69 a:hover { color: var(--brand-dark); }
     70 :focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
     71 
     72 code, pre, textarea, .mono { font-family: var(--mono); }
     73 code { font-size: 0.86em; }
     74 :where(p, li, td, dd) code { padding: 0.05em 0.3em; border-radius: 3px; background: var(--code); }
     75 code.lit { white-space: nowrap; }
     76 
     77 h1, h2, h3, h4 { margin: 0; line-height: 1.25; }
     78 
     79 /* Korean: break between words, not inside them, and prefer Korean system faces. */
     80 html[lang="ko"] body { word-break: keep-all; overflow-wrap: anywhere; }
     81 html[lang="ko"] .badge { letter-spacing: 0; }
     82 html[lang="ko"] .block h4, html[lang="ko"] .verdict-label { letter-spacing: 0.02em; }
     83 /* In tables, "anywhere" would let automatic column sizing squeeze a cell down
     84    to one character; break-word still breaks a word that cannot fit, but only
     85    after the columns are sized around whole words. */
     86 table { overflow-wrap: break-word; }
     87 
     88 .sr-only {
     89   position: absolute;
     90   width: 1px;
     91   height: 1px;
     92   margin: -1px;
     93   padding: 0;
     94   overflow: hidden;
     95   clip-path: inset(50%);
     96   white-space: nowrap;
     97   border: 0;
     98 }
     99 .skip { position: absolute; left: -999px; top: 0; z-index: 10; padding: 0.4rem 0.8rem; background: var(--ink); color: #fff; }
    100 .skip:focus { left: 0.5rem; top: 0.5rem; }
    101 
    102 /* ── Top bar ─────────────────────────────────────────────────────── */
    103 
    104 .topbar { background: var(--panel); border-bottom: 1px solid var(--line); }
    105 .topbar-in {
    106   display: flex;
    107   align-items: center;
    108   gap: 0.6rem 1.25rem;
    109   flex-wrap: wrap;
    110   max-width: var(--max);
    111   margin: 0 auto;
    112   padding: 0.7rem 1.5rem;
    113 }
    114 .brand { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--brand); text-decoration: none; }
    115 .brand span { font-family: var(--mono); font-size: 0.9rem; font-weight: 700; color: var(--text); letter-spacing: -0.01em; }
    116 .cves { display: flex; gap: 0.4rem; }
    117 .cves a {
    118   padding: 0.12rem 0.45rem;
    119   border: 1px solid var(--line);
    120   border-radius: 4px;
    121   font-family: var(--mono);
    122   font-size: 0.72rem;
    123   color: var(--muted);
    124   text-decoration: none;
    125 }
    126 .cves a:hover { border-color: var(--brand); color: var(--brand); }
    127 .topbar-end { display: flex; align-items: center; gap: 1rem; margin-left: auto; }
    128 .lang-toggle {
    129   display: inline-flex;
    130   align-items: center;
    131   gap: 0.3rem;
    132   height: 2rem;
    133   padding: 0 0.55rem;
    134   border: 1px solid var(--line);
    135   border-radius: 4px;
    136   color: var(--text);
    137   font-family: var(--mono);
    138   font-size: 0.72rem;
    139   font-weight: 700;
    140   text-decoration: none;
    141 }
    142 .lang-toggle:hover { color: var(--brand); border-color: var(--brand); }
    143 .topbar-end { gap: 0.5rem; }
    144 .report-link {
    145   display: inline-flex;
    146   align-items: center;
    147   gap: 0.35rem;
    148   height: 2rem;
    149   padding: 0 0.7rem;
    150   border: 1px solid var(--line);
    151   border-radius: 4px;
    152   color: var(--text);
    153   font-size: 0.8rem;
    154   font-weight: 600;
    155   white-space: nowrap;
    156   text-decoration: none;
    157 }
    158 .report-link svg { flex: none; color: var(--brand); }
    159 .report-link:hover { color: var(--brand); border-color: var(--brand); }
    160 .source { display: inline-grid; place-items: center; width: 2rem; height: 2rem; border-radius: 4px; color: var(--text); }
    161 .source:hover { color: var(--brand); background: var(--sunken); }
    162 
    163 /* ── Workspace ───────────────────────────────────────────────────── */
    164 
    165 .workspace {
    166   display: grid;
    167   grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    168   gap: 1.25rem;
    169   align-items: start;
    170   max-width: var(--max);
    171   margin: 0 auto;
    172   padding: 1.5rem;
    173 }
    174 .pane {
    175   min-width: 0;
    176   padding: 1.4rem 1.5rem 1.5rem;
    177   background: var(--panel);
    178   border: 1px solid var(--line);
    179   border-radius: var(--radius);
    180 }
    181 .pane-result { position: sticky; top: 1rem; max-height: calc(100vh - 2rem); overflow: auto; }
    182 
    183 h1 { font-size: 1.3rem; font-weight: 650; letter-spacing: -0.01em; }
    184 .lede { margin: 0.45rem 0 0; color: var(--muted); font-size: 0.9rem; max-width: 62ch; }
    185 
    186 .step { margin-top: 1.4rem; }
    187 .step-head { display: flex; align-items: center; gap: 0.55rem; font-size: 0.95rem; font-weight: 650; }
    188 .step-head label { cursor: pointer; }
    189 .step-n {
    190   display: inline-grid;
    191   place-items: center;
    192   width: 1.3rem;
    193   height: 1.3rem;
    194   border-radius: 50%;
    195   background: var(--ink);
    196   color: #fff;
    197   font-family: var(--mono);
    198   font-size: 0.7rem;
    199   font-weight: 700;
    200 }
    201 .step > .step-head, .step-head-row { margin-bottom: 0.65rem; }
    202 .step-head-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; }
    203 
    204 /* Collector */
    205 /* The tab strip never scrolls: when the labels do not fit, each tab shrinks and
    206    its label wraps onto a second line, so every tab stays visible. */
    207 .collector { border: 1px solid var(--line); border-radius: var(--radius); container-type: inline-size; }
    208 .tabs { display: flex; border-bottom: 1px solid var(--line); background: var(--sunken); border-radius: var(--radius) var(--radius) 0 0; }
    209 .tab {
    210   flex: 0 1 auto;
    211   position: relative;
    212   padding: 0.6rem 0.9rem;
    213   border: 0;
    214   background: transparent;
    215   color: var(--muted);
    216   font: inherit;
    217   font-size: 0.85rem;
    218   font-weight: 600;
    219   line-height: 1.35;
    220   cursor: pointer;
    221 }
    222 .tab:first-child { border-top-left-radius: calc(var(--radius) - 1px); }
    223 .tab:hover { color: var(--text); }
    224 .tab:focus-visible { outline-offset: -2px; }
    225 .tab[aria-selected="true"] { color: var(--text); background: var(--panel); }
    226 .tab[aria-selected="true"]::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--brand); }
    227 .tab-hint { margin-left: 0.25rem; font-size: 0.7rem; font-weight: 500; color: var(--ok); }
    228 @container (max-width: 28rem) {
    229   .tab-hint { display: none; }
    230 }
    231 .tab-panel { padding: 0.9rem; }
    232 .tab-panel[hidden] { display: none; }
    233 .panel-title { display: none; }
    234 
    235 .get { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.9rem; }
    236 .btn-download { gap: 0.45rem; text-decoration: none; }
    237 .btn-download:hover { color: var(--text); }
    238 .btn-download svg { flex: none; color: var(--brand); }
    239 .or {
    240   display: flex;
    241   align-items: center;
    242   gap: 0.6rem;
    243   margin: 0.8rem 0 0.5rem;
    244   font-size: 0.74rem;
    245   color: var(--faint);
    246 }
    247 .or::after { content: ""; flex: 1; height: 1px; background: var(--line); }
    248 
    249 .cmdline {
    250   display: flex;
    251   align-items: center;
    252   gap: 0.4rem;
    253   min-width: 0;
    254   padding: 0.2rem 0.25rem 0.2rem 0.7rem;
    255   background: var(--code);
    256   border: 1px solid var(--line);
    257   border-radius: 4px;
    258 }
    259 .cmd {
    260   flex: 1 1 auto;
    261   min-width: 0;
    262   overflow-x: auto;
    263   padding: 0.4rem 0;
    264   font-size: 0.78rem;
    265   color: var(--text);
    266   white-space: nowrap;
    267   scrollbar-width: thin;
    268 }
    269 .cmd::before { content: "$ "; color: var(--faint); }
    270 .cmd.multi { margin: 0; white-space: pre; line-height: 1.7; }
    271 .copy {
    272   flex: none;
    273   display: grid;
    274   place-items: center;
    275   width: 1.9rem;
    276   height: 1.9rem;
    277   padding: 0;
    278   border: 0;
    279   border-radius: 4px;
    280   background: transparent;
    281   color: var(--muted);
    282   cursor: pointer;
    283 }
    284 .copy:hover { background: var(--line); color: var(--text); }
    285 .copy .i-check { display: none; }
    286 .copy.is-done { color: var(--ok); }
    287 .copy.is-done .i-copy { display: none; }
    288 .copy.is-done .i-check { display: block; }
    289 
    290 .howto { margin: 0.75rem 0 0; padding-left: 1.15rem; font-size: 0.84rem; color: var(--muted); }
    291 .howto li + li { margin-top: 0.25rem; }
    292 .sha { margin: 0.6rem 0 0; font-family: var(--mono); font-size: 0.68rem; color: var(--faint); word-break: break-all; }
    293 .sha:empty { display: none; }
    294 
    295 /* Form */
    296 textarea {
    297   display: block;
    298   width: 100%;
    299   min-height: 15rem;
    300   padding: 0.7rem 0.8rem;
    301   border: 1px solid var(--control);
    302   border-radius: 4px;
    303   background: var(--sunken);
    304   color: var(--text);
    305   font-size: 0.78rem;
    306   line-height: 1.55;
    307   resize: vertical;
    308 }
    309 textarea::placeholder { color: var(--faint); }
    310 textarea:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(165, 28, 48, 0.12); background: var(--panel); }
    311 
    312 select {
    313   min-height: 2.25rem;
    314   max-width: 100%;
    315   padding: 0 2rem 0 0.6rem;
    316   border: 1px solid var(--control);
    317   border-radius: 4px;
    318   background: var(--panel) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2357524a' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 0.55rem center / 0.9rem;
    319   color: var(--text);
    320   font: inherit;
    321   font-size: 0.85rem;
    322   -webkit-appearance: none;
    323   appearance: none;
    324   cursor: pointer;
    325 }
    326 .select-sm { min-height: 1.9rem; font-size: 0.8rem; color: var(--muted); }
    327 
    328 /* Example inputs: picking one does nothing until Load is pressed. */
    329 .examples { display: flex; flex: 0 1 auto; align-items: center; gap: 0.4rem; min-width: 0; margin-left: auto; }
    330 .examples select { flex: 0 1 auto; min-width: 0; }
    331 .examples .btn { flex: none; }
    332 /* Keep the examples beside the heading on wider screens: the select gives up
    333    width before the row wraps. Phones put them on their own row instead. */
    334 #check-form > .step-head-row { flex-wrap: nowrap; }
    335 #check-form > .step-head-row > .step-head { flex: none; }
    336 
    337 .form-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; margin-top: 0.75rem; }
    338 .field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; font-size: 0.78rem; font-weight: 600; color: var(--muted); }
    339 .field select { min-width: 14rem; }
    340 .form-buttons { display: flex; gap: 0.5rem; }
    341 
    342 .btn {
    343   display: inline-flex;
    344   align-items: center;
    345   justify-content: center;
    346   min-height: 2.25rem;
    347   padding: 0 0.95rem;
    348   border: 1px solid var(--control);
    349   border-radius: 4px;
    350   background: var(--panel);
    351   color: var(--text);
    352   font: inherit;
    353   font-size: 0.85rem;
    354   font-weight: 600;
    355   cursor: pointer;
    356 }
    357 .btn:hover { background: var(--sunken); border-color: var(--muted); }
    358 .btn-primary { background: var(--ink); border-color: var(--ink); color: #fff; }
    359 .btn-primary:hover { background: #000; border-color: #000; }
    360 .btn-sm { min-height: 1.9rem; padding: 0 0.7rem; font-size: 0.8rem; }
    361 
    362 .fine { display: flex; align-items: center; gap: 0.35rem; margin: 0.7rem 0 0; font-size: 0.76rem; color: var(--faint); }
    363 .fine svg { flex: none; }
    364 .fine-block { margin: 0.4rem 0 0; font-size: 0.84rem; color: var(--muted); }
    365 .noscript { margin: 0 0 1rem; padding: 0.75rem 0.9rem; border: 1px solid var(--warn-line); border-radius: 4px; background: var(--warn-bg); color: var(--warn); font-size: 0.85rem; }
    366 .noscript a { color: inherit; }
    367 
    368 /* Without JavaScript. A browser parses the contents of <noscript> as elements
    369    only when scripting is off, so p.noscript exists only then and these rules
    370    never apply to the scripted page. All collection methods are shown one after
    371    another, and controls and tables that need the script are left out. */
    372 body:has(p.noscript) .tabs,
    373 body:has(p.noscript) .copy,
    374 body:has(p.noscript) .examples,
    375 body:has(p.noscript) #upstream-table,
    376 body:has(p.noscript) .ref-col .disclosure { display: none; }
    377 body:has(p.noscript) .tab-panel[hidden] { display: block !important; }
    378 body:has(p.noscript) .tab-panel + .tab-panel { border-top: 1px solid var(--line); }
    379 body:has(p.noscript) .panel-title { display: block; margin: 0 0 0.7rem; font-size: 0.85rem; font-weight: 650; }
    380 
    381 /* ── Result ──────────────────────────────────────────────────────── */
    382 
    383 .empty p { margin: 0 0 0.9rem; color: var(--muted); font-size: 0.88rem; }
    384 .legend { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
    385 .legend th, .legend td { padding: 0.5rem 0; border-top: 1px solid var(--line); text-align: left; vertical-align: top; }
    386 .legend th { width: 8.5rem; padding-right: 0.75rem; font-weight: 400; }
    387 .legend td { color: var(--muted); }
    388 
    389 .badge {
    390   display: inline-block;
    391   padding: 0.1rem 0.45rem;
    392   border: 1px solid;
    393   border-radius: 4px;
    394   font-family: var(--sans);
    395   font-size: 0.72rem;
    396   font-weight: 700;
    397   letter-spacing: 0.03em;
    398   text-transform: uppercase;
    399   white-space: nowrap;
    400 }
    401 .badge-patched, .badge-ok { color: var(--ok); background: var(--ok-bg); border-color: var(--ok-line); }
    402 .badge-vulnerable, .badge-pending, .badge-bad, .badge-high { color: var(--bad); background: var(--bad-bg); border-color: var(--bad-line); }
    403 .badge-restart, .badge-warn, .badge-medium { color: var(--warn); background: var(--warn-bg); border-color: var(--warn-line); }
    404 .badge-unknown, .badge-info { color: var(--info); background: var(--info-bg); border-color: var(--info-line); }
    405 
    406 .verdict {
    407   --v: var(--info); --v-bg: var(--info-bg); --v-line: var(--info-line);
    408   padding: 1rem 1.1rem;
    409   border: 1px solid var(--v-line);
    410   border-left: 4px solid var(--v);
    411   border-radius: var(--radius);
    412   background: var(--v-bg);
    413 }
    414 .verdict[data-verdict="patched"] { --v: var(--ok); --v-bg: var(--ok-bg); --v-line: var(--ok-line); }
    415 .verdict[data-verdict="vulnerable"], .verdict[data-verdict="pending"] { --v: var(--bad); --v-bg: var(--bad-bg); --v-line: var(--bad-line); }
    416 .verdict[data-verdict="restart"] { --v: var(--warn); --v-bg: var(--warn-bg); --v-line: var(--warn-line); }
    417 .verdict-label { margin: 0 0 0.3rem; font-family: var(--sans); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--v); }
    418 .verdict h3 { font-size: 1.15rem; font-weight: 650; }
    419 .verdict h3:focus { outline: none; }
    420 .reasons { margin: 0.55rem 0 0; padding-left: 1.1rem; font-size: 0.88rem; }
    421 .reasons li + li { margin-top: 0.3rem; }
    422 .verdict-meta { margin: 0.7rem 0 0; font-size: 0.74rem; color: var(--muted); }
    423 
    424 .block { margin-top: 1.25rem; }
    425 .block h4 { margin-bottom: 0.5rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
    426 .block > p { margin: 0 0 0.6rem; font-size: 0.84rem; color: var(--muted); }
    427 
    428 .kv { width: 100%; border-collapse: collapse; font-size: 0.84rem; }
    429 .kv th, .kv td { padding: 0.42rem 0; border-top: 1px solid var(--line); text-align: left; vertical-align: top; }
    430 .kv tr:last-child > * { border-bottom: 1px solid var(--line); }
    431 .kv th { width: 9.5rem; padding-right: 0.75rem; font-weight: 500; color: var(--muted); }
    432 .kv td { overflow-wrap: anywhere; }
    433 .kv td.mono { font-size: 0.8rem; }
    434 .kv .badge { margin-right: 0.4rem; }
    435 
    436 .actions { margin: 0; padding-left: 1.2rem; font-size: 0.88rem; }
    437 .actions li + li { margin-top: 0.6rem; }
    438 .actions .cmdline { margin-top: 0.35rem; }
    439 
    440 .mit { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
    441 .mit th, .mit td { padding: 0.45rem 0.6rem 0.45rem 0; text-align: left; vertical-align: top; }
    442 .mit thead th { font-size: 0.7rem; font-weight: 600; color: var(--faint); border-bottom: 1px solid var(--line); }
    443 .mit tbody tr.mit-row > * { border-top: 1px solid var(--line); }
    444 .mit tbody tr.mit-row:first-child > * { border-top: 0; }
    445 .mit td.setting { font-family: var(--mono); font-size: 0.78rem; font-weight: 700; overflow-wrap: break-word; word-break: normal; }
    446 .mit td.value { font-family: var(--mono); font-size: 0.78rem; white-space: nowrap; color: var(--muted); }
    447 .mit td.status { text-align: right; padding-right: 0; }
    448 /* On phones the value and status move under the setting name (see the 40rem query). */
    449 .mit-inline { display: none; }
    450 .mit tr.mit-note td { padding-top: 0; color: var(--muted); font-size: 0.8rem; }
    451 
    452 .plain { margin: 0; padding-left: 1.1rem; font-size: 0.86rem; }
    453 .plain li + li { margin-top: 0.35rem; }
    454 .indicators { list-style: none; margin: 0; padding: 0; font-size: 0.86rem; }
    455 .indicators li { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 0.55rem; align-items: start; }
    456 .indicators li + li { margin-top: 0.45rem; }
    457 .indicators .badge { margin-top: 0.1rem; }
    458 
    459 /* ── Reference ───────────────────────────────────────────────────── */
    460 
    461 .reference { border-top: 1px solid var(--line); background: var(--panel); }
    462 .reference-in {
    463   display: grid;
    464   grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    465   gap: 2.5rem;
    466   max-width: var(--max);
    467   margin: 0 auto;
    468   padding: 1.75rem 1.5rem 2rem;
    469 }
    470 .ref-col h2 { margin: 0 0 0.6rem; font-size: 0.95rem; font-weight: 650; }
    471 .ref-col h2:not(:first-child) { margin-top: 1.4rem; }
    472 
    473 .data { width: 100%; border-collapse: collapse; font-size: 0.84rem; }
    474 .data th, .data td { padding: 0.45rem 0.75rem 0.45rem 0; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
    475 .data thead th { font-size: 0.72rem; font-weight: 600; color: var(--faint); }
    476 .data tbody th { font-weight: 600; white-space: nowrap; }
    477 .data td.mono { font-family: var(--mono); font-size: 0.78rem; white-space: nowrap; }
    478 /* Long distribution versions may wrap, but only at the <wbr> that app.js puts
    479    after "-" and "~" and before "+", never inside a number. */
    480 .data td.ver { white-space: normal; overflow-wrap: normal; word-break: normal; }
    481 .data .ver-line { display: block; }
    482 .data .dim { color: var(--faint); font-weight: 400; }
    483 .data .eol::before { content: " · "; }
    484 .data .badge { margin-left: 0.35rem; }
    485 
    486 .disclosure { margin-top: 0.8rem; border: 1px solid var(--line); border-radius: var(--radius); }
    487 .disclosure > summary { padding: 0.55rem 0.8rem; font-size: 0.85rem; font-weight: 600; cursor: pointer; }
    488 .disclosure > summary::marker { color: var(--faint); }
    489 .disclosure[open] > summary { border-bottom: 1px solid var(--line); }
    490 .disclosure > table, .disclosure > div { padding: 0 0.8rem 0.6rem; }
    491 .disclosure > table { display: block; overflow-x: auto; }
    492 .rh-intro { margin: 0.6rem 0; font-size: 0.82rem; color: var(--muted); }
    493 .rh { width: 100%; border-collapse: collapse; font-size: 0.78rem; }
    494 .rh th, .rh td { padding: 0.35rem 0.75rem 0.35rem 0; border-top: 1px solid var(--line); text-align: left; vertical-align: top; }
    495 .rh th { white-space: nowrap; font-weight: 600; }
    496 .rh td { font-family: var(--mono); overflow-wrap: anywhere; }
    497 
    498 .method { margin: 0; padding-left: 1.2rem; font-size: 0.84rem; color: var(--muted); }
    499 .method li + li { margin-top: 0.3rem; }
    500 
    501 .footer { max-width: var(--max); margin: 0 auto; padding: 1rem 1.5rem 2rem; }
    502 .footer p { margin: 0; font-size: 0.78rem; color: var(--faint); }
    503 .footer a { color: var(--muted); }
    504 
    505 /* ── Narrow screens ──────────────────────────────────────────────── */
    506 
    507 /* Media queries count rem from the browser default (16px), not the root size above. */
    508 @media (max-width: 75rem) {
    509   .workspace { grid-template-columns: minmax(0, 1fr); }
    510   .pane-result { position: static; max-height: none; overflow: visible; }
    511   .reference-in { grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
    512 }
    513 @media (max-width: 40rem) {
    514   html { font-size: 112.5%; }
    515   .topbar-in, .workspace, .reference-in, .footer { padding-left: 1rem; padding-right: 1rem; }
    516   .workspace { padding-top: 1rem; gap: 1rem; }
    517   .pane { padding: 1.1rem 1rem 1.2rem; }
    518   .tab-hint { display: none; }
    519   .tab { padding: 0.6rem; font-size: 0.8rem; }
    520   /* 16px or more, or iOS Safari zooms the page when the field gets focus. */
    521   textarea, select, select.select-sm { font-size: 1rem; }
    522   #check-form > .step-head-row { flex-wrap: wrap; }
    523   .examples { flex: 1 1 100%; }
    524   .examples select { flex: 1 1 auto; }
    525   .form-row { flex-direction: column; align-items: stretch; }
    526   .field select { min-width: 0; width: 100%; }
    527   .form-buttons .btn { flex: 1; }
    528   .kv th { width: 7rem; }
    529   .legend th { width: 7.5rem; }
    530   .data th, .data td { padding-right: 0.5rem; }
    531   .data th:last-child, .data td:last-child { padding-right: 0; }
    532   .disclosure > table, .disclosure > div { padding-left: 0.6rem; padding-right: 0.6rem; }
    533   .data .eol { display: block; white-space: normal; }
    534   .data .eol::before { content: none; }
    535   .data tbody th { white-space: normal; }
    536   .mit td.value, .mit td.status, .mit thead th:not(:first-child) { display: none; }
    537   .mit-inline { display: flex; flex-wrap: wrap; align-items: center; gap: 0.2rem 0.5rem; margin-top: 0.15rem; font-weight: 400; color: var(--muted); }
    538 }
    539 
    540 /* Phones: buttons share the brand row, the report button shrinks to its icon,
    541    and the CVE links take the second row. */
    542 @media (max-width: 30rem) {
    543   .topbar-end { order: 2; }
    544   .cves { order: 3; width: 100%; }
    545   .report-link { padding: 0; width: 2rem; justify-content: center; }
    546   .report-link span { display: none; }
    547   .lang-toggle svg { display: none; }
    548   .brand span { font-size: 0.8rem; }
    549 }