/* Vazirmatn 33 — self-hosted (SIL OFL 1.1, /fonts/OFL.txt). No CDN. */
@font-face{
  font-family:"Vazirmatn";
  src:url("/fonts/Vazirmatn-Regular.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap;
}
@supports (font-variation-settings:normal){
  @font-face{
    font-family:"Vazirmatn";
    src:url("/fonts/Vazirmatn-Variable.woff2") format("woff2-variations");
    font-weight:100 900;font-style:normal;font-display:swap;
  }
}

/* ============================================================== tokens ====
   One ramp per role, shared with the other two products in this family
   (Tarazban, ChatYar) so a person moving between them is not relearning what
   blue means. The rules of the palette, stated once here because every rule
   below assumes them:

   - Blue is an accent, not a surface. It marks the one action a screen is for,
     the current item, and links. A blue block the size of a card is a claim
     that the whole card is the action.
   - Depth is carried by weight and colour, not by size. Body text is --ink-2,
     headings and key figures --ink, secondary --ink-3. --ink-4 is decorative
     only: it measures ~3.1:1 and must never carry a word anybody reads.
   - Status changes hue, never depth. ok/bad/warn are the same lightness as one
     another so a result does not look more urgent for being green.
   - Every text colour here clears WCAG AA against every surface it is used on,
     measured composited (test/uitest.js §4 does the measuring, not a promise).
*/
:root{
  /* brand ramp */
  --brand-50:#EEF4FF;
  --brand-100:#DDE9FD;
  --brand-300:#9CC0F5;
  --brand:#1257D2;          /* the brand: primary buttons, current state, dots */
  --brand-deep:#0E46AB;     /* hover, and brand-as-text on a brand tint */

  /* cool neutrals */
  --surface:#FFFFFF;
  --surface-2:#FBFCFE;      /* a hair off white: hovers, table heads, code */
  --canvas:#F8FAFD;         /* the page itself */
  --n-100:#EFF3F9;
  --n-200:#EAEFF7;

  /* ink */
  --ink:#0B1220;            /* headings and key figures */
  --ink-2:#2B3648;          /* body */
  --ink-3:#5A6577;          /* secondary, labels, hints */
  --ink-4:#8791A3;          /* decorative only — never running text */

  /* lines: a control's outline and a separator are different jobs */
  --line:#E4E9F0;           /* card borders, control outlines, cell rules */
  --line-strong:#CFD7E3;    /* hover on an outlined control */
  --line-soft:#EFF3F9;      /* rows inside one list */
  --divider:#D8DFE8;        /* where two regions meet */

  /* status: hue changes, depth does not */
  --ok:#10774D;      --ok-soft:#E9F6F0;   --ok-line:#C6E5D6;
  --bad:#B3261E;     --bad-soft:#FBEDEC;  --bad-line:#F2D0CC;
  --warn:#8A5A00;    --warn-soft:#FAF1E1; --warn-line:#EDDCB8;
  --note:#102A5E;    --note-soft:#E9EEF8; --note-line:#D5DEF0;

  /* ---------------------------------------------------------------- type ---
     Two families, because this page has two jobs.

     The steps below are the interface: labels, table data, controls, headings.
     There were twenty-three distinct sizes before this — 12.8px, 14.5px, 8.5px
     among them — which is what a scale looks like when it is tuned one selector
     at a time: every value is defensible on the line it was written and no two
     of them agree. A closed set is the point, not round numbers. This is a
     dense data UI, the real working range is 11.5–14, so the steps crowd there
     and stretch out above it.

     --fs-800 is 16px and load-bearing: iOS Safari zooms the page when a focused
     input is smaller than that. --fs-field is an alias of it so the rule is
     visible at the point of use, and no field may sit below it.

     The display family is fluid rather than stepped. A v4 address, a v6 address
     and a Jalali date are wildly different lengths in the same box, and a fixed
     size can only be right for one of them; clamp() lets the box decide. */
  --fs-100:9px;      /* micro tags: a self-scan marker, a byline */
  --fs-200:10px;     /* version chips, occasion badges */
  --fs-300:11.5px;   /* chips, inline code, toggles */
  --fs-400:12.5px;   /* dense table data, notes, hints — the densest reading size */
  --fs-500:13px;     /* menu, buttons, secondary controls */
  --fs-600:14px;     /* body */
  --fs-700:15px;     /* lead paragraphs, card intros */
  --fs-800:16px;     /* sub-heads, and the floor for any input */
  --fs-900:18px;     /* section heads */
  --fs-1000:22px;    /* page heads */
  --fs-field:16px;   /* every text input. Never smaller — see above. */

  --fs-ip:clamp(1.75rem,5.6vw,2.15rem);        /* the address on page one */
  --fs-ip-long:clamp(1.05rem,3.4vw,1.45rem);   /* the same box holding a v6 address */
  --fs-ip-sm:var(--fs-ip-sm);       /* phone: the box goes full width, so
                                                  the ratio to the viewport changes */
  --fs-ip-long-sm:var(--fs-ip-long-sm);
  --fs-resolved:var(--fs-resolved);    /* the answer on /lookup */
  --fs-clock:clamp(2.1rem,6.4vw,2.6rem);       /* the date on /date */
  --fs-numeral:64px;                           /* the 404 watermark. aria-hidden, so
                                                  it is exempt from the contrast floor */
  --fs-numeral-sm:52px;

  /* -------------------------------------------------------------- spacing ---
     Twelve steps on a 2px grid. Two decisions worth stating, because both went
     the other way first:

     The grid is 2px rather than 4px because this stylesheet was already 85% on
     one — 16, 20, 12 and 8 carry most of the layout — and the genuine mess was
     the odd pixel: 1, 3, 5, 7, 9 and 11 turned up 43 times between them, each
     one a nudge that made a single component look right and nothing else agree.
     Imposing a 4px modulus instead would have moved every dense surface on the
     site to serve a rounder number, which is churn dressed as rigour.

     The steps crowd between 8 and 20 for the same reason the type scale does:
     that is where a data-dense interface actually lives, and the difference
     between 12 and 14 of padding is visible in a table cell in a way that the
     difference between 32 and 40 is not.

     Borders are not spacing and do not come from here; neither do control
     heights, which are --h-ctl and --h-ctl-lg. */
  --sp-1:2px;
  --sp-2:4px;
  --sp-3:6px;
  --sp-4:8px;
  --sp-5:10px;
  --sp-6:12px;
  --sp-7:14px;
  --sp-8:16px;
  --sp-9:20px;
  --sp-10:24px;
  --sp-11:32px;
  --sp-12:40px;

  /* ---------------------------------------------------------- breakpoints ---
     Four, and a closed set. There were nine — 340, 400, 480, 620, 640, 800,
     860, 900, 1100 — so no two components ever changed shape at the same width
     and the layout reflowed continuously all the way down instead of at a few
     deliberate moments.

     These cannot be custom properties: a media query is evaluated before custom
     properties are resolved, so there is nothing to substitute. They are
     literals, held to this list by test/consistency.js — which is the only
     enforcement a project with no build step can have.

       400px   one column, everywhere
       620px   phone
       860px   tablet, and where every two-column split folds
      1100px   narrow desktop
  */

  /* geometry */
  --r-1:5px; --r-2:7px; --r-3:10px; --r-4:14px; --r-pill:999px;
  --h-ctl:38px;             /* secondary control */
  --h-ctl-lg:44px;          /* field, primary action, anything a thumb aims at */

  /* elevation — a whisper, then a lift, then a float */
  --sh-1:0 1px 2px rgba(11,18,32,.05);
  --sh-2:0 2px 8px rgba(11,18,32,.06);

  --sans:"Vazirmatn",system-ui,"Segoe UI",Tahoma,sans-serif;
  /* Vazirmatn rides at the tail of the mono stack, after the generic keyword,
     purely as the per-character fallback. Everywhere the site controls its own
     output, isMachineText() in tools-ui.js keeps Persian out of this face
     entirely. The one place it cannot is the raw-JSON pane, whose whole point is
     to show the response verbatim — recommendation strings and verdicts included.
     No font in the stack above carries Persian, so those characters fall back
     one by one to whatever the system happens to have, which differs per machine.
     Naming Vazirmatn last makes that fallback the same font as the rest of the
     page instead of a lottery. Latin and digits never reach it: they are matched
     by the monospace faces ahead of it. */
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace,"Vazirmatn";
}

/* ================================================================ base ==== */
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--canvas);color:var(--ink-2);
  font-family:var(--sans);font-size:var(--fs-600);line-height:1.65;
  -webkit-font-smoothing:antialiased;
}
.wrap{max-width:940px;margin:0 auto;padding:0 var(--sp-9)}
button,input{font:inherit;font-family:var(--sans);color:inherit}
button{cursor:pointer;border:0;background:none}
/* [hidden] has to win, once, for everything.
   A class selector that sets a display beats the user agent's own
   [hidden]{display:none} — same specificity, later in the cascade — and this has
   bitten this site three separate times: the second-address row stayed on screen
   as an empty strip, the ping pill sat there showing its "—" placeholder, and
   the توقف button offered to stop a run that had not started. Each was fixed with
   its own `.thing[hidden]` rule, which only ever fixes the one that was noticed.
   Stating it once, with the weight to hold against any rule below, is the version
   that also covers the next control someone gives a display to. */
[hidden]{display:none!important}
:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:var(--r-2)}
::selection{background:#DDE9FD;background:color-mix(in srgb,var(--brand) 16%,transparent)}

/* Vertical rhythm: one rule owns the gap between every top-level block, instead
   of two adjacent blocks each padding their own side and hoping the sum looks
   right. A single margin cannot drift, because there is only one number. */
section{padding:0}
main.wrap>.hero,main.wrap>section{margin-top:var(--sp-12)}
main.wrap>.hero:first-child,main.wrap>section:first-child{margin-top:var(--sp-10)}

.sechead{margin:0 0 var(--sp-6);font-size:var(--fs-900);font-weight:700;color:var(--ink);letter-spacing:-.015em}
.sechead.big{font-size:var(--fs-1000);margin-bottom:var(--sp-4);line-height:1.35}

/* ================================================================= nav ==== */
nav{background:var(--surface);border-bottom:1px solid var(--divider)}
/* padding-block, not the padding shorthand: .nav shares this element with .wrap
   (`<div class="wrap nav">`), and a same-specificity shorthand here would wipe
   out .wrap's horizontal padding instead of adding vertical padding to it —
   which is exactly what left the menu flush with the viewport edge while every
   other .wrap stayed inset. */
.nav{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-8);padding-block:var(--sp-6)}
.brand{display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp-1);line-height:1}
.wordmark{
  text-decoration:none;color:var(--ink);
  direction:ltr;font-weight:800;font-size:var(--fs-1000);letter-spacing:-.035em;
  /* line-height is pinned: Vazirmatn's vertical metrics are sized for Persian
     ascenders and leave a Latin wordmark floating in dead space otherwise. */
  line-height:1.05;
}
.wordmark .accent{color:var(--brand)}
.byline{
  direction:ltr;font-size:var(--fs-100);font-weight:600;letter-spacing:.13em;
  color:var(--ink-3);text-transform:uppercase;text-decoration:none;transition:.15s;
  line-height:1.2;
}
.byline:hover{color:var(--brand-deep)}
.ver{
  direction:ltr;font-size:var(--fs-200);font-weight:500;letter-spacing:.03em;
  color:var(--ink-3);line-height:1.2;font-variant-numeric:tabular-nums;
}
.menu{display:flex;gap:var(--sp-1);flex-wrap:wrap}
.menu a{
  color:var(--ink-3);text-decoration:none;font-size:var(--fs-500);
  padding:var(--sp-4) var(--sp-6);border-radius:var(--r-2);transition:.15s;
}
.menu a:hover{color:var(--ink);background:var(--n-100)}
.menu a[aria-current="page"]{color:var(--brand-deep);background:var(--brand-50);font-weight:600}

/* =========================================== controls: buttons and fields ==
   Two heights and one radius across the whole site. A control is either the
   thing the screen is for (--h-ctl-lg, solid brand) or it is not (--h-ctl,
   outlined). There is no third kind, and blue is not used for the second. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-4);
  height:var(--h-ctl);padding:0 var(--sp-8);border-radius:var(--r-3);
  border:1px solid var(--line);background:var(--surface);color:var(--ink-2);
  font-size:var(--fs-500);font-weight:500;white-space:nowrap;transition:.15s;
  text-decoration:none;
}
.btn:hover{border-color:var(--line-strong);background:var(--surface-2);color:var(--ink)}
.btn:active{transform:translateY(1px)}
.btn.primary{
  height:var(--h-ctl-lg);padding:0 var(--sp-9);font-size:var(--fs-600);font-weight:600;
  background:var(--brand);border-color:var(--brand);color:#fff;box-shadow:var(--sh-1);
}
.btn.primary:hover{background:var(--brand-deep);border-color:var(--brand-deep);color:#fff}
.btn.primary:disabled{opacity:.5;cursor:default;transform:none}
.btn.danger{color:var(--bad);border-color:var(--bad-line)}
.btn.danger:hover{background:var(--bad-soft);border-color:var(--bad);color:var(--bad)}

/* One field, everywhere something is typed. */
.field{
  height:var(--h-ctl-lg);min-width:0;
  border:1px solid var(--line);background:var(--surface);border-radius:var(--r-3);
  padding:0 var(--sp-7);font-size:var(--fs-600);color:var(--ink);
  direction:ltr;font-variant-numeric:tabular-nums;transition:.15s;
}
/* --ink-3, not the decorative tone. A placeholder is read — it is usually the
   only worked example of what the field wants — so it is held to the same 4.5
   as any other text, and only the weight of the real value separates them. */
.field::placeholder{color:var(--ink-3)}
.field:focus{
  outline:none;border-color:var(--brand);
  box-shadow:0 0 0 3px rgba(18,87,210,.12);
}

/* =============================================================== cards ==== */
.card{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-4);
  box-shadow:var(--sh-1);overflow:hidden;
}
.card.big{box-shadow:var(--sh-2)}
.head{
  display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-6);
  padding:var(--sp-7) var(--sp-9);border-bottom:1px solid var(--line);
}
.head h2,.head h3{margin:0;font-size:var(--fs-700);font-weight:600;color:var(--ink)}
.head span{font-size:var(--fs-400);color:var(--ink-3)}
/* The saved-result page's own padded block. */
.pad{padding:var(--sp-9) var(--sp-9)}
/* The renderers below inset themselves by 20px because on /tools they sit
   directly against a card edge. Inside .pad that inset is added to the block's
   own padding and every row drifts 42px off the heading above it, so it is
   cancelled here rather than made conditional in twenty-five renderers. */
#detail .verdict,#detail pre.raw{margin-inline:0}
#detail .shead,#detail .probe,#detail .banner,#detail .qual,
#detail .subhead,#detail .foot,#detail .vantage,
#detail .rtable th,#detail .rtable td{padding-inline:0}

/* Section intros sit in a card like every other block, and share the body
   measurements used in .faq so paragraph size and leading match across the whole
   page rather than shrinking wherever a section happens to open. */
.intro{margin-bottom:var(--sp-7)}
.intro p{margin:0;padding:var(--sp-8) var(--sp-9);font-size:var(--fs-700);line-height:1.95;color:var(--ink-2)}

/* Dividers: every cell draws its own top and inline-start line, and the grid is
   pulled 1px out of the card on those two sides so the outer lines fall outside
   and get clipped by the card's overflow:hidden.

   Two earlier approaches were wrong. nth-child arithmetic broke on grids holding
   a .cell.wide, because a spanning cell counts as one child while occupying a
   whole row. Painting the container and showing it through 1px gaps fixed that
   but left the empty area of an incomplete last row filled with the line colour.
   Per-cell borders have neither problem — but a final row that does not fill its
   columns then ends in blank, unbordered space, and the count that causes this
   changes with the breakpoint, so no fixed number of filler cells is ever right.

   Wrapping flex removes the question instead of answering it: the last row's
   cells grow into the space, so there is never an unfilled remainder. This is
   not CSS Grid. Do not add filler cells. */
.grid{
  display:flex;flex-wrap:wrap;
  margin-block-start:calc(-1 * var(--sp-1));margin-inline-start:-1px;width:calc(100% + 1px);
}
.cell{
  flex:1 1 calc(100% / 3);min-width:0;
  padding:var(--sp-7) var(--sp-9);
  border-top:1px solid var(--line);border-inline-start:1px solid var(--line);
}
.cell dt{font-size:var(--fs-400);color:var(--ink-3);margin:0;line-height:1.6}
/* Values keep a fixed size here; fitValue() in app.js steps the few that are too
   long down to fit. A CSS clamp cannot do this job: the layout is capped at
   940px, so viewport units stop changing once the container stops growing, and
   no length unit knows how many characters the text actually has. */
.cell dd{
  margin:0;font-size:var(--fs-600);font-weight:600;color:var(--ink);
  min-width:0;overflow-wrap:break-word;text-wrap:balance;line-height:1.5;
}
/* One face for every Latin value on the page. These cells were monospace while
   the address above them was not, so a single card showed three Latin faces —
   and the mono stack resolves differently on every platform. Monospace is kept
   for literal code only (see `pre`, `.ep code`, the UA string, result tables). */
.cell dd.ltr,.cell dd.num{
  direction:ltr;text-align:end;font-family:var(--sans);
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;
  font-size:var(--fs-600);font-weight:600;
}
.cell dd.none{color:var(--ink-3);font-weight:400}
.cell.wide{flex-basis:100%}
.cell.wide dd.ltr,.cell.wide dd.num{text-align:start;font-size:var(--fs-400);line-height:1.7;font-weight:500}
.cell a{color:var(--brand-deep);text-decoration:none}
.cell a:hover{text-decoration:underline}
@media (max-width:860px){ .cell{flex-basis:50%} }
@media (max-width:400px){ .cell{flex-basis:100%} }
.grid.two>.cell{flex-basis:50%}
@media (max-width:400px){ .grid.two>.cell{flex-basis:100%} }

/* A quiet informational strip, closing a card. */
.note{
  padding:var(--sp-6) var(--sp-9);border-top:1px solid var(--line);
  background:var(--note-soft);font-size:var(--fs-400);line-height:1.75;color:var(--note);
}
.pad>.note{border:1px solid var(--note-line);border-radius:var(--r-3);margin:var(--sp-6) 0 0}
.skel{
  display:inline-block;width:88px;height:.8em;border-radius:var(--r-1);
  background:var(--n-200);animation:pulse 1.4s ease-in-out infinite;
}
@keyframes pulse{50%{opacity:.45}}

/* ================================================== the address, page one ==
   The figure is the hero, not the container it sits in. Everything around the
   address — the label pill, the ping reading, the second family — is set quiet
   so there is exactly one thing to read first. */
.hero{padding:0}
.iphero{padding:var(--sp-9) var(--sp-9) var(--sp-9)}
.ipmain{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-9);flex-wrap:wrap}
.ipcol{display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp-6);min-width:0;flex:1 1 auto}
.kicker{
  display:inline-flex;align-items:center;gap:var(--sp-4);font-size:var(--fs-400);
  color:var(--brand-deep);background:var(--brand-50);
  border-radius:var(--r-pill);padding:var(--sp-2) var(--sp-6);margin:0 0 var(--sp-7);font-weight:600;
}
.ipcol .kicker{margin-bottom:0}
.pip{position:relative;width:6px;height:6px;border-radius:50%;background:var(--brand);flex:none}
.pip::after{
  content:"";position:absolute;inset:0;border-radius:50%;background:var(--brand);
  animation:ping 2.6s cubic-bezier(0,0,.2,1) infinite;
}
@keyframes ping{0%{transform:scale(1);opacity:.65}70%,100%{transform:scale(3.4);opacity:0}}
/* The ping reading is a second live signal, and green so the two dots are not
   the same dot with a different label. */
.pip.green,.pip.green::after{background:var(--ok)}
.kicker.ping{background:var(--ok-soft);color:var(--ok)}

.ip{
  direction:ltr;font-weight:700;color:var(--ink);
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;
  font-size:var(--fs-ip);line-height:1.15;letter-spacing:-.025em;
  display:flex;align-items:baseline;flex-wrap:wrap;
}
.ip.long{font-size:var(--fs-ip-long);letter-spacing:-.01em;word-break:break-all}
/* The dots and colons are part of the address, so they are read, not decoration:
   they get a colour that clears AA rather than the accent. */
.sep{color:var(--ink-3)}
@media (hover:hover){
  .ip .u:not(.sep){transition:color .15s;cursor:default}
  .ip .u:not(.sep):hover{color:var(--brand)}
}
.ip.on .u{animation:rise .42s cubic-bezier(.2,.85,.3,1) backwards}
@keyframes rise{from{opacity:0;transform:translateY(.12em)}to{opacity:1;transform:none}}

.alt{display:flex;gap:var(--sp-5);align-items:center;flex-wrap:wrap;font-size:var(--fs-500);color:var(--ink-3)}
.iphero .alt{margin-top:var(--sp-8);padding-top:var(--sp-7);border-top:1px solid var(--line)}
.alt code{
  direction:ltr;font-family:var(--sans);font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;font-size:var(--fs-500);color:var(--ink-2);
}
.chip{
  border:1px solid var(--line);border-radius:var(--r-pill);
  padding:var(--sp-1) var(--sp-5);font-size:var(--fs-300);color:var(--ink-3);
}

/* ============================================================ code, api ====
   The tab strip and the sample belong to one framed panel, so the code and the
   thing that switches it read as a single object. */
.tabs{
  display:flex;align-items:center;gap:var(--sp-1);flex-wrap:wrap;
  padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--line);background:var(--surface-2);
}
/* The tabs sit in their own element because role="tablist" may only contain
   tabs, and the copy button shares this row. Splitting the role off the flex
   container keeps both true without moving anything. */
.tablist{display:flex;align-items:center;gap:var(--sp-1);flex-wrap:wrap}
.tab{
  color:var(--ink-3);padding:var(--sp-4) var(--sp-6);border-radius:var(--r-2);font-size:var(--fs-500);
  border:1px solid transparent;transition:.15s;
}
.tab:hover{color:var(--ink);background:var(--surface)}
.tab[aria-selected="true"]{
  background:var(--surface);border-color:var(--line);
  color:var(--brand-deep);font-weight:600;box-shadow:var(--sh-1);
}
.ccode{
  margin-inline-start:auto;border:1px solid var(--line);background:var(--surface);
  padding:var(--sp-3) var(--sp-6);border-radius:var(--r-2);font-size:var(--fs-300);color:var(--ink-3);transition:.15s;
}
.ccode:hover{color:var(--brand-deep);border-color:var(--line-strong)}
pre{
  -webkit-overflow-scrolling:touch;
  direction:ltr;margin:0;background:var(--surface-2);border:0;border-radius:0;
  padding:var(--sp-8) var(--sp-9);overflow-x:auto;color:var(--ink-2);
  font-family:var(--mono);font-size:var(--fs-400);line-height:1.8;
}
pre .c{color:var(--ink-3)}
pre .s{color:var(--ok)}
pre .k{color:var(--brand-deep)}

.eps{margin-top:var(--sp-7)}
.ep{
  display:grid;grid-template-columns:auto max-content minmax(0,1fr);
  gap:var(--sp-7);padding:var(--sp-6) var(--sp-9);border-top:1px solid var(--line);align-items:center;
}
.ep:first-child{border-top:0}
.eps .head + .ep{border-top:0}
.ep:hover{background:var(--surface-2)}
.verb{
  font-size:var(--fs-200);font-weight:700;letter-spacing:.06em;line-height:1;
  padding:var(--sp-3) var(--sp-4);border-radius:var(--r-1);background:var(--brand-50);color:var(--brand-deep);
  direction:ltr;text-align:center;min-width:44px;
}
.verb.head-verb{background:var(--n-100);color:var(--ink-2)}
.ep code{direction:ltr;font-family:var(--mono);font-size:var(--fs-400);overflow-wrap:anywhere;color:var(--ink)}
.epval{display:flex;align-items:center;gap:var(--sp-5);min-width:0}
.epdesc{color:var(--ink-3);font-size:var(--fs-500);text-align:end}
@media (max-width:620px){
  .ep{grid-template-columns:auto minmax(0,1fr);gap:var(--sp-3) var(--sp-6)}
  .epdesc{grid-column:2;text-align:start}
  .epval{gap:var(--sp-4)}
}

/* Compact copy controls. Same icon as the full button, without the word. */
.copy,.ccode{display:inline-flex;align-items:center;gap:var(--sp-4);justify-content:center}
.copy svg,.ccode svg{flex:none}
.iconbtn,.cmini{
  display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:32px;height:32px;border:1px solid var(--line);border-radius:var(--r-2);
  background:var(--surface);color:var(--ink-3);transition:.15s;
}
.cmini{margin-inline-start:calc(-1 * var(--sp-3))}
.iconbtn:hover,.cmini:hover{color:var(--brand-deep);border-color:var(--line-strong);background:var(--surface-2)}
.iconbtn.done,.cmini.done{color:var(--ok);border-color:var(--ok-line);background:var(--ok-soft)}

.uaraw{display:flex;align-items:flex-start;gap:var(--sp-4);margin-top:var(--sp-4)}
.uaraw code{
  flex:1;min-width:0;direction:ltr;font-family:var(--mono);font-size:var(--fs-300);
  color:var(--ink-3);line-height:1.75;word-break:break-all;
}

/* ============================================================== lookup ==== */
.lookupbox{padding:var(--sp-8) var(--sp-9)}
.lform{display:flex;gap:var(--sp-4);align-items:stretch}
.lform input{flex:1 1 auto;font-size:var(--fs-field)}
.lhint{
  margin-top:var(--sp-6);font-size:var(--fs-400);color:var(--ink-3);
  display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;
}
.chip-btn{
  display:inline-flex;align-items:center;height:32px;
  border:1px solid var(--line);border-radius:var(--r-pill);padding:0 var(--sp-6);
  font-size:var(--fs-400);color:var(--ink-2);direction:ltr;background:var(--surface);
  font-variant-numeric:tabular-nums;transition:.15s;
}
.chip-btn:hover{color:var(--brand-deep);border-color:var(--brand-300);background:var(--brand-50)}

.reshead{padding:var(--sp-9) var(--sp-9);margin-top:var(--sp-7)}
.resmain{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-8);flex-wrap:wrap}
.rescol{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0}
.reslabel{font-size:var(--fs-400);color:var(--ink-3)}
.resip{
  font-size:var(--fs-resolved);font-weight:700;color:var(--ink);
  letter-spacing:-.025em;line-height:1.2;overflow-wrap:anywhere;
}
.resolved{
  padding:var(--sp-6) var(--sp-9);background:var(--surface-2);border-bottom:1px solid var(--line);
  font-size:var(--fs-500);color:var(--ink-3);direction:ltr;font-variant-numeric:tabular-nums;
}
/* .resolved bleeds to the card's edges with negative margins, the bottom one
   cancelling the card's padding so it sits flush. When a note follows it, that
   negative bottom margin pulled the next block up over it — so whichever of the
   two is last is the one allowed to close the card. */
.reshead .resolved{margin:var(--sp-8) calc(-1 * var(--sp-9)) calc(-1 * var(--sp-9));border-top:1px solid var(--line);border-bottom:0}
.reshead .resolved:not(:last-child){margin-bottom:0}
.reshead .note{margin:0 calc(-1 * var(--sp-9)) calc(-1 * var(--sp-9));border-top:1px solid var(--line);border-radius:0}
.resblock{margin-top:var(--sp-7)}
#lout{margin-top:var(--sp-7)}
.err{padding:var(--sp-8) var(--sp-9);color:var(--bad);font-size:var(--fs-500)}
.wait{padding:var(--sp-8) var(--sp-9);color:var(--ink-3);font-size:var(--fs-500)}
#lout .wait,#lout .err{padding:var(--sp-9) var(--sp-9);font-size:var(--fs-600)}

/* The strip that hands an address on to the toolkit. Equal tiles rather than
   pills sized by their own labels — the ragged row read as an accident. */
.quick{display:grid;grid-template-columns:repeat(auto-fit,minmax(124px,1fr));gap:var(--sp-4);padding:var(--sp-8) var(--sp-9)}
.qlink{
  display:flex;align-items:center;justify-content:center;min-height:var(--h-ctl);
  border:1px solid var(--line);background:var(--surface);color:var(--ink-2);
  padding:var(--sp-5) var(--sp-6);border-radius:var(--r-3);font-size:var(--fs-500);text-decoration:none;
  text-align:center;transition:.15s;
}
.qlink:hover{color:var(--brand-deep);border-color:var(--brand-300);background:var(--brand-50)}
.qlink.main{
  grid-column:1/-1;min-height:var(--h-ctl-lg);
  background:var(--brand);border-color:var(--brand);color:#fff;font-weight:600;
  box-shadow:var(--sh-1);
}
.qlink.main:hover{background:var(--brand-deep);border-color:var(--brand-deep);color:#fff}

/* ============================================================= toolkit ====
   The active tool and the field you type into are one block, and it is a card
   like every other card on the site. It used to be a saturated blue slab, which
   made the loudest thing on the page a container rather than an action. */
.toolcard{padding:var(--sp-8) var(--sp-9) var(--sp-9);margin-bottom:var(--sp-8)}
.htop{display:flex;align-items:center;gap:var(--sp-6)}
.hicon{
  flex:none;width:44px;height:44px;border-radius:var(--r-3);
  display:grid;place-items:center;
  background:var(--brand-50);border:1px solid var(--brand-100);color:var(--brand-deep);
}
.hmeta{min-width:0;flex:1}
.eyebrow{display:block;font-size:var(--fs-400);color:var(--ink-3);line-height:1.4}
.htop h2{margin:var(--sp-1) 0 0;font-size:var(--fs-900);font-weight:700;color:var(--ink);letter-spacing:-.015em}
/* The rate note sits at the end of the header line, not stranded at the bottom
   of the card with a stretch of empty colour above it. */
.pill{
  flex:none;border-radius:var(--r-pill);padding:var(--sp-3) var(--sp-6);
  font-size:var(--fs-400);font-weight:600;background:var(--n-100);color:var(--ink-3);
  white-space:nowrap;
}
.hhint{margin:var(--sp-6) 0 0;font-size:var(--fs-500);line-height:1.75;color:var(--ink-3);max-width:66ch}
.hhint:empty{display:none}
.runner{display:flex;gap:var(--sp-4);margin-top:var(--sp-7);flex-wrap:wrap}
.runner input{flex:1 1 260px;font-size:var(--fs-field)}
/* The field, the primary action and «توقف» share one row, so they share one
   height — a 38px secondary beside a 44px field reads as a mistake. */
.runner .btn{height:var(--h-ctl-lg)}
.herofoot{display:flex;align-items:center;gap:var(--sp-5);margin-top:var(--sp-5);flex-wrap:wrap}
.herofoot:empty,.runnote:empty{display:none}
.runnote{font-size:var(--fs-400);color:var(--ink-3)}
.runnote a{color:var(--brand-deep);text-decoration:underline;text-underline-offset:3px}

/* ---------------------------------------------------------- the tool list ---
   Twenty-five one-line chips, five to a row. The largest group has thirteen
   tools, which lands 5 + 5 + 3 and never leaves one chip alone at the end.

   Every chip is a real <a href="/tools/{slug}">. That is not a detail: the 25
   landing pages sat in the sitemap as "Discovered - currently not indexed, last
   crawled N/A" for as long as this picker was a row of buttons, because a
   crawler cannot press a button. The two things an anchor brings with it have to
   be turned off explicitly — the underline, and the user-agent link colour. */
.picker{padding:var(--sp-2) var(--sp-9) var(--sp-8)}
.gtitle{font-size:var(--fs-400);font-weight:700;color:var(--ink-3);letter-spacing:.02em;margin:var(--sp-8) 0 var(--sp-4)}
.gtitle:first-child{margin-top:var(--sp-4)}
.tgrid{display:grid;grid-template-columns:repeat(5,1fr);gap:var(--sp-4)}
@media (max-width:1100px){ .tgrid{grid-template-columns:repeat(4,1fr)} }
@media (max-width:860px){ .tgrid{grid-template-columns:repeat(3,1fr)} }
@media (max-width:620px){ .tgrid{grid-template-columns:repeat(2,1fr)} }
@media (max-width:400px){ .tgrid{grid-template-columns:1fr} }
.pick{
  display:flex;align-items:center;justify-content:flex-start;gap:var(--sp-4);
  height:var(--h-ctl-lg);padding:0 var(--sp-6);border-radius:var(--r-3);
  border:1px solid var(--line);background:var(--surface);color:var(--ink-2);
  text-align:start;text-decoration:none;cursor:pointer;transition:.15s;
}
.pick:hover{border-color:var(--line-strong);background:var(--surface-2);color:var(--ink)}
.pick svg{flex:none;width:16px;height:16px;color:var(--ink-3)}
/* The names are short (a `short` field on the tool, used only here), so nowrap
   costs nothing: nothing is truncated, and one long label no longer sets the
   height of every chip in its row. */
.pick .plabel{
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  font-size:var(--fs-400);font-weight:500;line-height:1.2;color:inherit;
}
.pick[aria-current="page"]{
  border-color:var(--brand);background:var(--brand-50);color:var(--brand-deep);
  box-shadow:inset 0 0 0 1px var(--brand);
}
.pick[aria-current="page"] .plabel{font-weight:700}
.pick[aria-current="page"] svg{color:var(--brand)}
/* A mark, not a banner. It says one thing about one tool and does not need to be
   read before the tool's own name. */
.pick .tag.self{
  flex:none;font-size:var(--fs-100);font-weight:700;line-height:1;white-space:nowrap;
  padding:var(--sp-2) var(--sp-3);border-radius:var(--r-1);
  background:var(--bad-soft);color:var(--bad);
}
.picker-foot{padding:0 var(--sp-9) var(--sp-8)}

/* ------------------------------------------------------------- the output ---
   Small outlined controls above the result. They are secondary to the result
   below them and are sized and coloured to say so. */
.headtools{display:flex;gap:var(--sp-3);flex-wrap:wrap}
.tgl{
  display:inline-flex;align-items:center;height:32px;padding:0 var(--sp-6);
  border:1px solid var(--line);background:var(--surface);color:var(--ink-3);
  border-radius:var(--r-2);font-size:var(--fs-300);transition:.15s;
}
.tgl:hover{color:var(--ink);border-color:var(--line-strong);background:var(--surface-2)}
.tgl[aria-pressed="true"]{color:var(--brand-deep);border-color:var(--brand);background:var(--brand-50);font-weight:600}

/* The link every run mints, in a row of its own: it is a thing to be read,
   selected and sent, not a sentence dropped into whatever node was nearest. */
.sharebar{
  display:flex;align-items:center;gap:var(--sp-5);
  padding:var(--sp-5) var(--sp-9);background:var(--surface-2);border-bottom:1px solid var(--line);
}
.sharebar .sicon{
  flex:none;width:26px;height:26px;border-radius:var(--r-2);
  background:var(--brand-50);color:var(--brand-deep);display:grid;place-items:center;
}
.sharebar .surl{
  flex:1;min-width:0;direction:ltr;text-align:start;
  font-family:var(--mono);font-size:var(--fs-400);color:var(--brand-deep);text-decoration:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.sharebar .surl:hover{text-decoration:underline}
.sharebar .sbtn{background:var(--brand);border-color:var(--brand);color:#fff;font-weight:600}
.sharebar .sbtn:hover{background:var(--brand-deep);border-color:var(--brand-deep);color:#fff}

.subhead{
  padding:var(--sp-7) var(--sp-9) var(--sp-2);font-size:var(--fs-400);font-weight:700;color:var(--ink-3);
  border-top:1px solid var(--line);
}
.subhead:first-child{border-top:0}
.foot{padding:var(--sp-5) var(--sp-9) var(--sp-7);font-size:var(--fs-400);color:var(--ink-3);line-height:1.75}

/* A banner states one fact about the whole result. Soft tint, status-coloured
   text — never a saturated fill, which reads as an alert whatever it says. */
.banner{
  padding:var(--sp-6) var(--sp-9);font-size:var(--fs-500);line-height:1.75;
  border-top:1px solid var(--line);background:var(--note-soft);color:var(--note);
}
.banner:first-child{border-top:0}
.banner.ok{background:var(--ok-soft);color:var(--ok)}
.banner.warn{background:var(--warn-soft);color:var(--warn)}
.banner.bad{background:var(--bad-soft);color:var(--bad);font-weight:600}

.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.rtable{width:100%;border-collapse:collapse;font-size:var(--fs-500)}
.rtable th{
  text-align:start;font-weight:600;color:var(--ink-3);font-size:var(--fs-300);
  padding:var(--sp-5) var(--sp-9);background:var(--surface-2);
  border-bottom:1px solid var(--line);white-space:nowrap;
}
.rtable td{
  padding:var(--sp-5) var(--sp-9);border-bottom:1px solid var(--line-soft);vertical-align:top;
  color:var(--ink-2);overflow-wrap:anywhere;line-height:1.7;
}
.rtable tr:last-child td{border-bottom:0}
/* Machine values only. Persian never reaches this rule — see isMachineText() in
   tools-ui.js — because the monospace stack carries no Persian glyphs and the
   text would fall back to whatever the system happened to have. */
.rtable td.ltr{direction:ltr;text-align:start;font-family:var(--mono);font-size:var(--fs-400)}
/* Columns are sized from their content, so one cell holding ten mail servers
   claimed two thirds of the table. Capping the greedy cell leaves the rest their
   natural width; the list simply wraps onto more lines. */
.rtable td.long{max-width:34ch}
@media (min-width:860px){ .rtable td.long{max-width:46ch} }
.rtable td:not(.ltr){white-space:normal;overflow-wrap:break-word;min-width:6ch}

#out pre.raw{
  margin:0 var(--sp-9) var(--sp-8);border:1px solid var(--line);border-radius:var(--r-3);
  background:var(--canvas);font-size:var(--fs-300);max-height:340px;overflow:auto;
}
#raw{
  margin:0;border-radius:0;border:0;border-top:1px solid var(--line);
  background:var(--canvas);max-height:420px;overflow:auto;font-size:var(--fs-300);
}

/* ============================================================ verdicts ====
   A result panel used to be a flat wall of 13px text: the finding, the evidence
   and the footnotes all at one size, so the sentence a reader came for carried
   no more weight than a table cell. The verdict is a tinted card in its own
   status family — text and border take the colour, the fill stays soft. */
.verdict{
  display:flex;align-items:flex-start;gap:var(--sp-6);
  margin:var(--sp-8) var(--sp-9);padding:var(--sp-8);border-radius:var(--r-3);
  border:1px solid var(--note-line);background:var(--note-soft);
}
.verdict .vmark{
  flex:none;width:38px;height:38px;border-radius:var(--r-3);
  display:grid;place-items:center;
  background:var(--surface);border:1px solid var(--note-line);color:var(--note);
}
.verdict .vbody{min-width:0;flex:1}
.verdict .vtitle{margin:0;font-size:var(--fs-900);font-weight:700;line-height:1.45;color:var(--note);letter-spacing:-.01em}
.verdict .vsub{margin:var(--sp-2) 0 0;font-size:var(--fs-500);line-height:1.75;color:var(--ink-3)}

.verdict.ok{background:var(--ok-soft);border-color:var(--ok-line)}
.verdict.ok .vtitle,.verdict.ok .vmark{color:var(--ok)}
.verdict.ok .vmark{border-color:var(--ok-line)}
.verdict.bad{background:var(--bad-soft);border-color:var(--bad-line)}
.verdict.bad .vtitle,.verdict.bad .vmark{color:var(--bad)}
.verdict.bad .vmark{border-color:var(--bad-line)}
.verdict.warn{background:var(--warn-soft);border-color:var(--warn-line)}
.verdict.warn .vtitle,.verdict.warn .vmark{color:var(--warn)}
.verdict.warn .vmark{border-color:var(--warn-line)}
.verdict.info{background:var(--brand-50);border-color:var(--brand-100)}
.verdict.info .vtitle,.verdict.info .vmark{color:var(--brand-deep)}
.verdict.info .vmark{border-color:var(--brand-100)}

/* Section labels inside a result, inset to the same 20px as the tables and rows
   they head — a heading flush against the card edge does not line up with the
   thing it heads. */
.shead{
  display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-8) var(--sp-9) var(--sp-4);
  font-size:var(--fs-300);font-weight:700;letter-spacing:.03em;color:var(--ink-3);
  border-top:1px solid var(--line);margin-top:var(--sp-1);
}
.shead:first-child{border-top:0}
.shead svg{flex:none}

/* Label, icon and outcome on one line. A table was doing this and gave the three
   probes the weight of arbitrary data; they are the evidence for the headline
   above and read better as a short list. */
.probes{list-style:none;margin:0;padding:0}
.probe{
  display:flex;align-items:flex-start;gap:var(--sp-6);
  padding:var(--sp-6) var(--sp-9);border-top:1px solid var(--line-soft);
  font-size:var(--fs-500);line-height:1.7;
}
.probe:first-child{border-top:0}
.probe .picon{
  flex:none;width:28px;height:28px;border-radius:var(--r-2);margin-top:var(--sp-1);
  display:grid;place-items:center;background:var(--n-100);color:var(--ink-3);
}
.probe.is-ok .picon{background:var(--ok-soft);color:var(--ok)}
.probe.is-bad .picon{background:var(--bad-soft);color:var(--bad)}
.probe .pname{flex:none;min-width:132px;color:var(--ink-3);font-size:var(--fs-400);padding-top:var(--sp-2)}
.probe .pval{flex:1;min-width:0;padding-top:var(--sp-2);color:var(--ink-2)}
.probe .pval b{font-weight:600;color:var(--ink)}

/* Two places, one comparison. This is the whole product of the filter check, so
   it gets its own treatment rather than another anonymous table. */
.vantages{display:flex;flex-wrap:wrap;gap:0}
.vantage{
  flex:1 1 50%;min-width:200px;
  display:flex;align-items:center;gap:var(--sp-6);
  padding:var(--sp-7) var(--sp-9);border-top:1px solid var(--line);border-inline-start:1px solid var(--line);
}
.vantage:first-child{border-inline-start:0}
.vantage .vflag{
  flex:none;font-size:var(--fs-1000);line-height:1;
  /* The emoji face, not Vazirmatn — and never the mono stack. */
  font-family:"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif;
}
.vantage .vwhere{font-size:var(--fs-400);color:var(--ink-3);margin:0}
.vantage .vres{font-size:var(--fs-600);font-weight:700;margin:var(--sp-1) 0 0;color:var(--ink)}
.vantage.yes .vres{color:var(--ok)}
.vantage.no .vres{color:var(--bad)}

/* Smaller than the body on purpose: it qualifies the finding rather than
   competing with it. */
.qual{
  padding:var(--sp-6) var(--sp-9);font-size:var(--fs-400);line-height:1.8;color:var(--ink-3);
  border-top:1px solid var(--line);background:var(--surface);
}
.qual svg{vertical-align:-3px;margin-inline-end:var(--sp-3);color:var(--ink-4)}

/* ======================================================== date and time ==== */
.split{display:grid;grid-template-columns:1fr 1.15fr;gap:var(--sp-8);align-items:start}
@media (max-width:860px){ .split{grid-template-columns:1fr} }

.clockcard{padding:var(--sp-10) var(--sp-9);text-align:center}
.clocklabel{font-size:var(--fs-400);color:var(--ink-3);margin:0 0 var(--sp-5);font-weight:500}
.clock{
  direction:ltr;font-weight:700;font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;font-size:var(--fs-clock);
  line-height:1.1;letter-spacing:-.03em;color:var(--ink);
}
.clockdate{margin-top:var(--sp-5);font-size:var(--fs-500);color:var(--ink-3)}
.bigdate{font-size:var(--fs-900);font-weight:700;color:var(--ink);margin-top:var(--sp-3)}

.cal{padding:var(--sp-8) var(--sp-8) var(--sp-9)}
.calhead{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-5);margin-bottom:var(--sp-7);flex-wrap:wrap}
.calmonth{font-size:var(--fs-900);font-weight:700;color:var(--ink);letter-spacing:-.015em}
.calnav{display:flex;gap:var(--sp-3)}
.calnav button{
  border:1px solid var(--line);background:var(--surface);color:var(--ink-3);
  width:var(--h-ctl);height:var(--h-ctl);border-radius:var(--r-2);
  font-size:var(--fs-600);line-height:1;transition:.15s;
}
.calnav button.today{width:auto;padding:0 var(--sp-7);font-size:var(--fs-400)}
.calnav button:hover{border-color:var(--line-strong);color:var(--ink);background:var(--surface-2)}

.dow,.days{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--sp-3)}
.dow span{text-align:center;font-size:var(--fs-300);color:var(--ink-3);padding-bottom:var(--sp-3)}
.day{
  position:relative;aspect-ratio:1;border:1px solid var(--line);border-radius:var(--r-2);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  font-size:var(--fs-600);font-weight:600;color:var(--ink-2);background:var(--surface);
}
.day small{position:absolute;top:5px;inset-inline-end:7px;font-size:var(--fs-100);font-weight:400;color:var(--ink-3)}
.day.out{opacity:.45}
.day.fri{color:var(--bad)}
.day.today{border-color:var(--brand);background:var(--brand-50);color:var(--brand-deep);box-shadow:inset 0 0 0 1px var(--brand)}
/* a dot under a day that carries an occasion */
.day .marks{position:absolute;bottom:5px;display:flex;gap:var(--sp-2)}
.day .marks i{width:4px;height:4px;border-radius:50%;background:var(--brand);display:block}
.day .marks i.h{background:var(--bad)}
.day.holiday{color:var(--bad)}
.day.today.holiday{color:var(--brand-deep)}

.times{
  display:flex;flex-wrap:wrap;
  margin-block-start:calc(-1 * var(--sp-1));margin-inline-start:-1px;width:calc(100% + 1px);
}
.time{
  flex:1 1 50%;min-width:0;
  padding:var(--sp-6) var(--sp-9);display:flex;justify-content:space-between;align-items:baseline;gap:var(--sp-5);
  border-top:1px solid var(--line);border-inline-start:1px solid var(--line);
}
.time b{direction:ltr;font-variant-numeric:tabular-nums;font-size:var(--fs-800);font-weight:700;color:var(--ink)}
.time span{color:var(--ink-3);font-size:var(--fs-500)}
/* The glyph repeats what the label says, so it is aria-hidden and the gap is the
   only thing it costs a screen reader. */
.time .tlabel{display:inline-flex;align-items:center;gap:var(--sp-4)}
.time .tlabel svg{flex:none;color:var(--ink-4)}
.until{
  padding:var(--sp-6) var(--sp-9);border-top:1px solid var(--line);background:var(--brand-50);
  color:var(--brand-deep);font-size:var(--fs-500);font-weight:600;text-align:center;
}

.occ{display:flex;align-items:flex-start;gap:var(--sp-6);padding:var(--sp-6) var(--sp-9);border-top:1px solid var(--line-soft)}
.occ:first-child{border-top:0}
.occ .n{
  flex:none;width:24px;height:24px;border-radius:50%;
  background:var(--brand-50);color:var(--brand-deep);
  display:flex;align-items:center;justify-content:center;font-size:var(--fs-300);font-weight:700;margin-top:var(--sp-1);
}
.occ p{margin:0;font-size:var(--fs-600);line-height:1.8;color:var(--ink-2)}
.occ.holiday .n{background:var(--bad-soft);color:var(--bad)}
.occ .badge{
  display:inline-block;margin-inline-start:var(--sp-4);font-size:var(--fs-200);font-weight:700;
  color:var(--bad);background:var(--bad-soft);border:1px solid var(--bad-line);
  border-radius:var(--r-1);padding:var(--sp-1) var(--sp-4);vertical-align:middle;
}
.occ.none{color:var(--ink-3);font-size:var(--fs-500);padding:var(--sp-8) var(--sp-9)}

/* =============================================================== prose ==== */
.prose{padding:var(--sp-10) var(--sp-9) var(--sp-10);max-width:none}
.prose h1{font-size:var(--fs-1000);font-weight:700;color:var(--ink);margin:0 0 var(--sp-2);letter-spacing:-.02em;line-height:1.35}
.prose .tag{color:var(--ink-3);font-size:var(--fs-500);margin:0 0 var(--sp-9)}
.prose h2{font-size:var(--fs-800);font-weight:700;color:var(--ink);margin:var(--sp-9) 0 var(--sp-3)}
.prose p{margin:0 0 var(--sp-6);line-height:1.95;font-size:var(--fs-700);color:var(--ink-2)}
.prose ul{margin:0 0 var(--sp-6);padding-inline-start:var(--sp-9);line-height:1.95;font-size:var(--fs-700);color:var(--ink-2)}
.prose li{margin-bottom:var(--sp-2)}
.prose b{color:var(--ink);font-weight:600}
.prose a{color:var(--brand-deep);text-decoration:none;font-weight:600}
.prose a:hover{text-decoration:underline}
.prose code{
  font-family:var(--mono);font-size:var(--fs-400);background:var(--n-100);color:var(--ink-2);
  padding:var(--sp-1) var(--sp-3);border-radius:var(--r-1);direction:ltr;display:inline-block;
}

.faq{padding:var(--sp-9) var(--sp-9) var(--sp-9)}
.faq .lead{margin:0 0 var(--sp-2);font-size:var(--fs-700);line-height:1.95;color:var(--ink-2)}
.faq h3{margin:var(--sp-9) 0 var(--sp-3);font-size:var(--fs-700);font-weight:700;color:var(--ink);letter-spacing:-.01em}
.faq p{margin:0;font-size:var(--fs-600);line-height:1.95;color:var(--ink-3)}
.faq .num{font-variant-numeric:tabular-nums}

/* ================================================================= 404 ==== */
.errpage{padding:var(--sp-12) var(--sp-9) var(--sp-10);text-align:center}
.errcode{
  font-size:var(--fs-numeral);font-weight:800;line-height:1;letter-spacing:-.04em;
  /* Present enough to read as deliberate, quiet enough not to compete with the
     sentence that helps. aria-hidden in the markup is what licenses it. */
  color:var(--brand-100);
}
.errpage h1{font-size:var(--fs-1000);font-weight:700;color:var(--ink);margin:var(--sp-5) 0 var(--sp-4);letter-spacing:-.02em}
.errpage p{margin:0 auto;max-width:52ch;font-size:var(--fs-600);line-height:1.95;color:var(--ink-3)}
.errpage code{
  font-family:var(--mono);font-size:var(--fs-400);background:var(--n-100);color:var(--ink-2);
  padding:var(--sp-1) var(--sp-4);border-radius:var(--r-1);display:inline-block;
}
/* Not the toolkit's grid: with four links that layout gave the first one a
   full-width row of its own and left the rest hanging beside a gap. */
.errpage .quick{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--sp-4);margin-top:var(--sp-10);padding:0}
.errpage .qlink{padding:var(--sp-5) var(--sp-8)}
.errpage .qlink.main{grid-column:auto}

/* ============================================================== footer ==== */
footer{margin-top:var(--sp-12);padding:0 0 var(--sp-12);color:var(--ink-3);font-size:var(--fs-400)}
footer b{color:var(--ink);font-weight:600}
footer p{margin:0 0 var(--sp-4)}
footer p:last-child{margin:0}
.notebox{padding:var(--sp-8) var(--sp-9)}
.about{font-size:var(--fs-500);line-height:1.9;color:var(--ink-2);margin-bottom:var(--sp-4)}
.sub{color:var(--ink-3);font-size:var(--fs-500);line-height:1.9}
.sub a{color:var(--brand-deep);text-decoration:none;font-weight:600}
.sub a:hover{text-decoration:underline}

/* ---------------------------------------------------- the site's own index ---
   Twenty-five tool pages, linked from every page of the site. This is not
   decoration: before it existed, the picker on /tools was the only route to any
   of them and the picker is drawn by script, so in the markup those pages were
   unreachable — which is exactly how a search engine found them (listed in the
   sitemap, never once crawled).

   Set small and quiet on purpose. A footer index is for the reader who has
   reached the bottom looking for something else, and for anything reading the
   page without eyes; it should not compete with the page above it. */
.footlinks{padding:var(--sp-10) var(--sp-9) var(--sp-3)}
.footlinks h2{font-size:var(--fs-300);font-weight:700;color:var(--ink-3);letter-spacing:.03em;margin:0 0 var(--sp-6)}
/* Columns, not a grid. A grid lays 25 items across 4 tracks as six full rows and
   one link sitting alone at the end; columns fill downwards and balance, so the
   same 25 come out 7/6/6/6 with no stranded last row. */
.flgrid{column-count:4;column-gap:var(--sp-8)}
@media (max-width:860px){ .flgrid{column-count:3} }
@media (max-width:620px){ .flgrid{column-count:2} }
@media (max-width:400px){ .flgrid{column-count:1} }
.flgrid a{break-inside:avoid}
.flgrid a,.flmain a{
  /* --ink-3 on the page's own canvas, which is where this block sits: 5.64:1,
     against 5.89 on white. Both clear AA — the margin is why the ramp separates
     secondary text from the decorative tone above it. */
  color:var(--ink-3);text-decoration:none;font-size:var(--fs-400);line-height:1.6;
  /* WCAG 2.5.8 exempts a link inside a block of text; these are a list, not a
     sentence, so they get the height rather than the exception. */
  display:block;padding:var(--sp-2) 0;min-height:24px;
}
.flgrid a:hover,.flmain a:hover{color:var(--brand-deep);text-decoration:underline;text-underline-offset:3px}
.flmain{
  display:flex;flex-wrap:wrap;gap:var(--sp-2) var(--sp-8);
  margin-top:var(--sp-8);padding-top:var(--sp-7);border-top:1px solid var(--divider);
}
.flmain a{font-weight:600;color:var(--ink-2)}

/* ============================================================= helpers ====
   Small utilities so no markup needs a style attribute — the CSP forbids them. */
.mt-2{margin-top:var(--sp-7)}
.stack{display:flex;flex-direction:column;gap:var(--sp-8)}
.num{direction:ltr;font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

/* ============================================================== mobile ==== */
@media (max-width:620px){
  .wrap{padding:0 var(--sp-8)}

  /* Measured on 320 / 360 / 390 / 430: the menu wrapped to two ragged rows at
     every width. One deliberate row that scrolls if it has to. */
  .nav{flex-direction:column;align-items:stretch;gap:var(--sp-3);padding-block-start:var(--sp-5)}
  .brand{flex-direction:row;flex-wrap:wrap;justify-content:center;align-items:baseline;gap:var(--sp-1) var(--sp-4)}
  .wordmark{flex:0 0 100%;text-align:center;font-size:var(--fs-1000);line-height:1}
  /* The separator has to land between the two items, and .ver is direction:ltr,
     so its inline-start is the outer (left) edge — a ::before there floats off
     the end of the line. ::after puts the dot at .ver's right, which in this RTL
     row is exactly the gap facing the byline. */
  .ver::after{content:"·";margin-inline-start:var(--sp-4);color:var(--ink-4)}
  .byline{white-space:nowrap;font-size:var(--fs-100);line-height:1.4}
  .menu{
    display:flex;flex-wrap:nowrap;gap:var(--sp-1);width:100%;
    border-top:1px solid var(--line);padding-top:var(--sp-2);
    overflow-x:auto;scrollbar-width:none;
  }
  .menu::-webkit-scrollbar{display:none}
  .menu a{flex:1 1 0;text-align:center;white-space:nowrap;font-size:var(--fs-400);padding:var(--sp-5) var(--sp-3);border-radius:var(--r-2);line-height:1.6}

  main.wrap>.hero,main.wrap>section{margin-top:var(--sp-10)}
  main.wrap>.hero:first-child,main.wrap>section:first-child{margin-top:var(--sp-8)}
  footer{margin-top:var(--sp-10);padding-bottom:var(--sp-11)}

  .sechead{font-size:var(--fs-800)}
  .sechead.big{font-size:var(--fs-900)}

  /* The address is the page, so on a phone it fills the card rather than floating
     in it — centred content in a full-width card read as an empty box with a big
     button under it. */
  .iphero{padding:var(--sp-8)}
  .ipmain{gap:var(--sp-7)}
  .ipcol{width:100%;align-items:center;text-align:center}
  .ip{font-size:var(--fs-ip-sm);width:100%;justify-content:center}
  .ip.long{font-size:var(--fs-ip-long-sm)}
  .btn.primary{width:100%}
  .kicker{font-size:var(--fs-300);padding:var(--sp-2) var(--sp-6)}

  .head{padding:var(--sp-6) var(--sp-8)}
  .head h2,.head h3{font-size:var(--fs-600)}
  /* Only the header that carries the button cluster — every other .head is a
     title and a short hint, which share one row comfortably at this width. At
     390px this one is a title plus three buttons on a nowrap row, and the two
     fought over the same 356px. Selected by #outsec rather than :has(.headtools):
     an unsupported :has drops the whole rule silently. */
  #outsec .head{flex-wrap:wrap}
  #outsec .head #outtitle{flex:1 1 100%}
  #outsec .headtools{width:100%;flex:0 0 auto;justify-content:flex-start}

  /* density: the label/value pairs do not need 1.8 line spacing on a phone */
  .cell{padding:var(--sp-6) var(--sp-8)}
  .cell dt{font-size:var(--fs-300);line-height:1.6}
  .cell dd,.cell dd.ltr,.cell dd.num{font-size:var(--fs-500);line-height:1.6}
  .cell.wide dd.ltr,.cell.wide dd.num{font-size:var(--fs-300);line-height:1.65}
  .uaraw{margin-top:var(--sp-3)}

  .note,.banner,.qual,.foot,.subhead{padding-inline:var(--sp-8)}
  .note{line-height:1.75}
  .notebox{padding:var(--sp-8)}
  .about{font-size:var(--fs-500)}
  .intro p{padding:var(--sp-7) var(--sp-8);font-size:var(--fs-600)}

  .lookupbox{padding:var(--sp-8)}
  .lform{flex-direction:column}
  .reshead{padding:var(--sp-8) var(--sp-8)}
  .reshead .resolved{margin:var(--sp-7) calc(-1 * var(--sp-8)) calc(-1 * var(--sp-8))}
  .reshead .resolved:not(:last-child){margin-bottom:0}
  .reshead .note{margin:0 calc(-1 * var(--sp-8)) calc(-1 * var(--sp-8))}
  .pad{padding:var(--sp-8)}

  .toolcard{padding:var(--sp-8)}
  .hicon{width:38px;height:38px}
  .htop{flex-wrap:wrap}
  .htop h2{font-size:var(--fs-800)}
  .pill{order:3}
  .picker{padding:var(--sp-2) var(--sp-8) var(--sp-7)}
  .picker-foot{padding:0 var(--sp-8) var(--sp-8)}
  .runner .btn{flex:1 1 auto}
  .quick{grid-template-columns:repeat(auto-fit,minmax(104px,1fr));padding:var(--sp-7) var(--sp-8);gap:var(--sp-3)}
  .qlink{padding:var(--sp-5) var(--sp-4);font-size:var(--fs-400)}

  .tabs{padding:var(--sp-3) var(--sp-3)}
  .tab{padding:var(--sp-4) var(--sp-6);font-size:var(--fs-400)}
  pre{padding:var(--sp-7) var(--sp-8);font-size:var(--fs-400)}
  .ep{padding:var(--sp-6) var(--sp-8)}
  .rtable th,.rtable td{padding-inline:var(--sp-8)}
  #out pre.raw{margin-inline:var(--sp-8)}

  .verdict{margin:var(--sp-7) var(--sp-8);padding:var(--sp-7)}
  .verdict .vtitle{font-size:var(--fs-800)}
  .probe,.vantage,.shead{padding-inline:var(--sp-8)}
  /* Icon and label share a line; the value goes underneath, indented to line up
     with the label rather than with the icon. Letting the label take the full row
     put the icon, the label and the value on three lines and turned three short
     measurements into most of a screen. */
  .probe{flex-wrap:wrap;row-gap:var(--sp-1)}
  .probe .pname{flex:1 1 auto;min-width:0;padding-top:var(--sp-3)}
  .probe .pval{flex:1 1 100%;padding-inline-start:var(--sp-12)}
  .vantage{flex-basis:100%;border-inline-start:0}

  .clockcard{padding:var(--sp-9) var(--sp-8)}
  .cal{padding:var(--sp-7) var(--sp-7) var(--sp-8)}
  .dow,.days{gap:var(--sp-2)}
  .day{border-radius:var(--r-1);font-size:var(--fs-500)}
  .day small{font-size:var(--fs-100);top:3px;inset-inline-end:4px}
  .day .marks{bottom:3px}
  .day .marks i{width:3px;height:3px}
  .time{padding:var(--sp-6) var(--sp-8)}
  .occ{padding-inline:var(--sp-8)}

  .prose{padding:var(--sp-9) var(--sp-8) var(--sp-9)}
  .prose h1{font-size:var(--fs-900)}
  .faq{padding:var(--sp-8) var(--sp-8) var(--sp-9)}
  .faq .lead{font-size:var(--fs-600)}
  .faq h3{margin-top:var(--sp-8);font-size:var(--fs-600)}
  .faq p{font-size:var(--fs-500)}
  .errpage{padding:var(--sp-11) var(--sp-8) var(--sp-10)}
  .errcode{font-size:var(--fs-numeral-sm)}
  .errpage h1{font-size:var(--fs-900)}
  /* Four links centred on a phone wrap 3 + 1, and the orphan reads as a mistake
     rather than a choice. Half-width basis makes it 2 x 2 at every phone size. */
  .errpage .qlink{flex:1 1 calc(50% - 8px);padding:var(--sp-6) var(--sp-5)}
  .footlinks{padding:var(--sp-9) var(--sp-8) var(--sp-3)}
}

/* very narrow phones: the menu can scroll rather than squeeze */
@media (max-width:400px){
  .menu a{flex:0 0 auto;padding:var(--sp-5) var(--sp-5)}
  .wordmark{font-size:var(--fs-900)}
}

/* ======================================================= touch targets ====
   On a touch screen every control needs a finger-sized hit area. Several here
   are sized for a mouse. Rather than inflating them for everyone, raise the
   minimum only where there is no pointer, so the desktop density survives.

   hover:none rather than a width query — the question is whether the pointer is
   a finger, and a small window on a laptop is still a mouse. */
@media (hover:none){
  .btn,.tgl,.tab,.ccode,.chip-btn,.qlink,.menu a{
    min-height:var(--h-ctl-lg);display:inline-flex;align-items:center;
  }
  .qlink,.menu a{display:flex;justify-content:center}
  .iconbtn,.cmini,.calnav button,.calnav button.today{
    min-width:var(--h-ctl-lg);min-height:var(--h-ctl-lg);
  }
  /* The wordmark is 21px of text and the byline 9.5px; the tap area is padded
     out around them rather than the logo being redrawn larger. */
  .brand .wordmark,.brand .byline{display:inline-flex;align-items:center;min-height:40px}
  /* A link inside a sentence keeps WCAG 2.5.8's own exception — padding it to
     44px would overlap the lines above and below. The footer index is a list,
     not a sentence, so it takes the height. */
  .foot a,.sub a{display:inline-block;padding-block:var(--sp-5)}
  .flgrid a,.flmain a{min-height:40px;display:flex;align-items:center}
  /* The share URL is a link that is its own row, not a link in a sentence, so it
     takes the height rather than the exception. line-height rather than a flex
     box: the ellipsis that truncates a long URL needs a block box to work in,
     and a flex container turns its own text into an anonymous item where
     text-overflow has nothing to clip. */
  .sharebar .surl{min-height:40px;line-height:40px}
}

@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}
