/* Shared shell and design tokens for every lens. */

/* Archivo carries everything; numbers use its tabular figures. */
@font-face{font-family:"Archivo";src:url("/fonts/archivo-var.woff2") format("woff2-variations");font-weight:100 900;font-display:swap}

/* The dirham sign, U+20C3. The Central Bank unveiled it in 2025 and Unicode
   accepted it for 18.0, but no shipping font draws it yet — measured against a
   known-missing glyph, Archivo, Noto and system-ui all render a box.

   So it is drawn here, in Archivo, by scripts/build-dirham.py: the mark is a D
   with two strokes, and Archivo already draws a barred D for Đ, so the bowl and
   the bar weight are the typeface's own. The official 40%/60% bar placement is
   kept. Two weights, so the sign tracks the weight of the text it sits in.
   Under half a kilobyte each, and unicode-range means a page with no dirham on
   it never asks for either. */
@font-face{font-family:"Dirham";src:url("/fonts/dirham-archivo-400.woff2") format("woff2");
  font-weight:400;font-display:swap;unicode-range:U+20C3}
@font-face{font-family:"Dirham";src:url("/fonts/dirham-archivo-600.woff2") format("woff2");
  font-weight:600;font-display:swap;unicode-range:U+20C3}

/* Arabic. Archivo draws no Arabic, so the Arabic pages need a second face —
   Noto Sans Arabic, variable across the same 100–900 axis so weights match.
   The unicode-range is the point: only a page that actually contains Arabic
   codepoints fetches it, so an English visitor never pays for 162K they
   cannot read. */
@font-face{font-family:"Noto Sans Arabic";src:url("/fonts/noto-arabic-var.woff2") format("woff2-variations");
  font-weight:100 900;font-display:swap;
  unicode-range:U+0600-06FF,U+0750-077F,U+0870-088E,U+0890-0891,U+08A0-08FF,U+200C-200E,U+FB50-FDFF,U+FE70-FEFF}


:root{
  /* ============================ TOKENS ============================
     Every value the interface is allowed to use. Nothing below this block
     should introduce a raw hex, radius or size — if something new is needed,
     add a token here first. See DESIGN-SYSTEM.md for what each one is for. */

  /* -- colour ------------------------------------------------------
     The field is a whisker off white and the panels are white, so the canvas
     reads clean and the metal is the only thing in the page with colour.
     Measured on this field: ink 17.9:1, --soft 6.8:1, --faint 4.8:1. */
  --bg:#FEFEFE;            /* the page */
  --panel:#FFFFFF;         /* anything raised off it */
  --ink:#14151A;           /* primary text, the mark */
  --soft:#575A63;          /* secondary text, body prose */
  --faint:#6E717A;         /* tertiary: captions, column heads, units */
  --hair:#E6E8EE;          /* every 1px line in the interface */
  --fill:#F1F3F7;          /* resting fill on a control */
  --fill-hi:#E8EBF1;       /* the same control, hovered */
  --panel-tint:#FCFCFD;    /* the faintest wash off panel, for a long gradient */
  --ink-lit:#4A4E58;       /* ink catching light: the bead specular */
  --bench-bg:#F8F6F1;      /* the bench note's ground: warm, and only ever this */
  --alloy-ink:#6E727B;     /* set live per alloy, never authored */
  --warn-ink:#8A5A00;      /* stale prices */
  --warn-bg:#FDF3DC;
  --alert-ink:#8A4B12;     /* prices failed to load */
  --sh:16,20,28;           /* one hue for every shadow on the site */

  /* -- radius ------------------------------------------------------
     Three steps, and two absolutes that are shapes rather than steps. If a new
     thing needs a corner, it takes one of these. */
  --r-sm:8px;              /* things inside things: rows, inputs, tooltips */
  --r-md:14px;             /* standalone blocks: nav items, equations, dialogs */
  --r-lg:24px;             /* surfaces: the tool panel, the cards */
  --r-pill:999px;          /* pills, chips, tabs */
  --r-circle:50%;          /* beads, the (i) */

  /* -- elevation ---------------------------------------------------
     A panel is --lit plus --e-1 plus one ambient. Never invent a shadow. */
  --lit:     inset 0 1px 0 rgba(255,255,255,.9);
  --e-1:     0 1px 2px rgba(var(--sh),.04);
  --e-2:     0 10px 30px -24px rgba(var(--sh),.18);
  --e-3:     0 20px 46px -24px rgba(var(--sh),.26);
  --e-panel: 0 18px 44px -26px rgba(var(--sh),.22);
  --ring-hair:inset 0 0 0 1px var(--hair);
  --ring-ink: 0 0 0 1px rgba(var(--sh),.16);

  /* -- type --------------------------------------------------------
     Archivo for everything; tabular figures keep columns steady.
     Six body steps; display sizes are fluid and named by their job. */
  --sans:"Dirham","Archivo",system-ui,sans-serif;
  --display:"Dirham","Archivo",system-ui,sans-serif;
  --t-label:12.5px;        /* mono: section labels, column heads, chips, tabs */
  --t-sm:15px;             /* controls, table data, nav, footer, meta */
  --t-md:17px;             /* prose, ledes, the wordmark */
  --d-md:clamp(24px,2.6vw,34px);   /* card titles, explainer h2, typed numbers */
  --d-lg:clamp(28px,3.2vw,42px);   /* a page h1, and a number you type */
  --d-xl:clamp(34px,5.4vw,76px);   /* the landing h1 */
  --d-answer:clamp(48px,6vw,80px); /* the one answer a tool exists to give */
  --track-display:-.03em;  /* tight at size — the biggest moderniser */
  --track-body:-.006em;
  --leading:1.4;

  /* -- motion ------------------------------------------------------ */
  --ease:cubic-bezier(.23,1,.32,1);   /* UI: quick out */
  --slow:cubic-bezier(.33,0,.2,1);    /* material: unhurried */
  --dur-fast:150ms; --dur-mid:260ms; --dur-slow:460ms;

  /* -- metrics ----------------------------------------------------- */
  --rail:208px;
  --cell:11px;             /* side padding inside table cells */
}
/* Only an Arabic page names the Arabic family. unicode-range alone was not
   enough: the language picker lists endonyms, so "العربية" appears on every
   page, and that was enough to pull 162K onto an English one. Elsewhere the
   handful of Arabic characters in that menu fall back to the system's own
   Arabic face, which every OS ships. */
:root[lang^="ar"]{--sans:"Dirham","Archivo","Noto Sans Arabic",system-ui,sans-serif;
  --display:"Dirham","Archivo","Noto Sans Arabic",system-ui,sans-serif}

/* Numbers must not jitter as they tween, and columns must line up. */
.n,.c,.rate b,.k,.chip,.tip,td,th,input,.entry input,.big{font-variant-numeric:tabular-nums}

*{box-sizing:border-box;margin:0}
body{font-family:var(--sans);background:var(--bg);color:var(--ink);line-height:var(--leading);
  letter-spacing:var(--track-body);-webkit-font-smoothing:antialiased}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;padding:0}
a{color:inherit;text-decoration:none}
[hidden]{display:none!important}
:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(var(--sh),.12), 0 0 0 1.5px var(--ink);border-radius:var(--r-pill)}
/* The ring above sets border-radius:999px on whatever it lands on. That suits
   this site, where nearly everything focusable is a pill — but outline follows
   border-radius, so the two square things that take focus wore a lozenge. The
   radius has to be reset here, not just the shadow.

   The number is not in a box, it sits on a rule, so focus thickens the rule and
   tints the field rather than drawing a frame around a 40px numeral. The
   padding gives back the pixel the thicker rule takes, so nothing shifts. */
/* At rest the number sits on a rule. Focused, the rule gives way and the number
   sits in a field instead — one state or the other, never both. Trying to keep
   the rule and add a tint put a 7px halo across a line 6px below it, and they
   collided. The room comes from a shadow spread in the fill's own colour, so
   the input's box never changes and nothing beside it moves. */
.entry input:focus-visible{outline:none;border-radius:var(--r-sm);background:var(--fill);
  box-shadow:0 0 0 8px var(--fill), 0 0 0 9.5px rgba(var(--sh),.16)}
.entry:has(input:focus-visible){border-bottom-color:transparent}
/* A table row is square, so its ring is too — drawn inside the cell so it does
   not overlap the rows above and below. */
td:focus-visible{box-shadow:none;outline:2px solid var(--ink);outline-offset:-2px;border-radius:var(--r-sm)}
@media(prefers-reduced-motion:reduce){*{transition:none!important}}

/* ---- shell ---- */
.app{display:grid;grid-template-columns:var(--rail) minmax(0,1fr);min-height:100vh}
.app>*{min-width:0}
/* No divider: the rail sits on the field and the panels are what read as edges. */
.rail{padding:22px 14px;position:sticky;top:0;height:100vh;
  display:flex;flex-direction:column;gap:26px}
/* Wordmark: the bench vice, then the word. No TLD, so it survives a move to
   another domain.

   The ratios come from the mark's own spec. Mark height is .723em because that
   is the ascender ink of b/h/l in Archivo 600, so the vice tops out level with
   the word instead of floating under it. Alignment is baseline, not centre:
   centring parks the mark against a line box carrying descender space that
   "benchtools" never uses. The vice is 85x60, so width follows from aspect
   ratio or the jaws squash. Never below 14px, per the spec's floor. */
.brand{display:flex;align-items:baseline;gap:calc(.723em * .30);padding:0 11px;color:var(--ink);
  font-family:var(--display);font-weight:600;font-size:var(--t-md);letter-spacing:-.038em}
.brand .mk{height:max(14px, .723em);aspect-ratio:1.4167;width:auto;flex:none;color:var(--ink)}
.brand .bn{white-space:nowrap}
.brand .bn b{font-weight:500;color:var(--soft)}
/* Wipes open from the mark's side. clip-path costs no layout, so the rail is
   still while the word arrives, and the letters uncover rather than slide. */
@keyframes bnOpen{
  from{clip-path:inset(0 100% 0 0);opacity:0}
  40%{opacity:1}
  to{clip-path:inset(0 0 0 0);opacity:1}
}
.from-home .brand .bn{animation:bnOpen 780ms cubic-bezier(.33,0,.2,1) 120ms both}
@media(prefers-reduced-motion:reduce){.from-home .brand .bn{animation:none}}
@media(hover:hover){.brand:hover .bn b{color:var(--ink)}}
.nav{display:flex;flex-direction:column;gap:2px}
.nav .grp{font-size:var(--t-label);font-weight:500;
  color:var(--faint);padding:0 8px 8px}
.nav a{display:flex;align-items:center;gap:10px;padding:10px 11px;border-radius:var(--r-md);font-size:var(--t-sm);color:var(--soft);
  transition:background 150ms var(--ease),color 150ms var(--ease)}
/* Solid objects, so they hold their own colour. Slightly under full strength
   at rest so the selected row still reads first. */
.nav a img{width:22px;height:22px;flex:none;object-fit:contain}
.nav a svg{width:21px;height:21px;flex:none;opacity:.82;
  transition:opacity 150ms var(--ease),transform 150ms var(--ease)}
.nav a[aria-current="page"] svg{opacity:1}
.nav a[aria-current="page"]{background:var(--panel);color:var(--ink);font-weight:500;
  box-shadow:inset 0 0 0 1px var(--hair)}

@media(hover:hover){.nav a:hover{color:var(--ink)}.nav a:hover svg{opacity:1;transform:translateY(-1px)}}
.rail .foot{margin-top:auto;display:flex;flex-direction:column;gap:6px}
.rail .foot .grp{display:flex;align-items:center;gap:6px;position:relative;padding:0 8px 2px}
/* (i) holds the fetch time. Detail on demand, so the rail stays three clean rows. */
.info{width:15px;height:15px;flex:none;border-radius:var(--r-circle);font-size:var(--t-label);line-height:15px;
  position:relative;color:var(--soft);background:var(--fill-hi);
  text-align:center;cursor:pointer;transition:color 150ms var(--ease),background 150ms var(--ease)}
/* the drawn circle stays 15px; the touch target does not (WCAG 2.5.8 wants 24) */
.info::after{content:"";position:absolute;inset:-5px}
.info:hover,.info:focus-visible{color:var(--ink);background:var(--hair)}
.tip{position:absolute;inset-inline-start:0;bottom:calc(100% + 6px);z-index:30;width:max-content;
  max-width:min(180px, calc(100vw - 24px));
  padding:7px 9px;border-radius:var(--r-sm);background:var(--ink);color:#fff;
  font-size:var(--t-label);line-height:1.4;
  opacity:0;visibility:hidden;pointer-events:none;
  /* visibility is stepped, not interpolated: fade out first, then hide */
  transition:opacity 150ms var(--ease),visibility 0s linear 150ms}
.info:hover+.tip,.info:focus-visible+.tip,.info[aria-expanded="true"]+.tip{
  opacity:1;visibility:visible;transition:opacity 150ms var(--ease),visibility 0s}
.chip.warn{color:var(--warn-ink);background:var(--warn-bg);box-shadow:none}

.main{min-width:0;padding:0 clamp(16px,3vw,40px) 26px}
.rate{display:flex;justify-content:space-between;align-items:baseline;gap:10px;padding:0 8px;
  font-size:var(--t-sm);color:var(--soft)}
.rate b{font-size:var(--t-sm);color:var(--ink);font-weight:500}
h1{font-family:var(--display);font-weight:600;font-size:var(--d-lg);letter-spacing:var(--track-display);
  line-height:1;padding:26px 0 10px}
/* one plain line saying what the page is for, before any controls appear */
.lede{font-size:var(--t-md);line-height:1.5;color:var(--soft);max-width:62ch;margin:0 0 22px}

@media(max-width:980px){
  .app{grid-template-columns:1fr}
  .rail{position:sticky;top:0;z-index:20;background:var(--bg);height:auto;
    border-bottom:1px solid var(--hair);flex-direction:row;align-items:center;gap:12px;padding:10px 12px}
  .brand .bn{display:none}
  .nav{flex-direction:row;gap:4px;overflow-x:auto;scrollbar-width:none;padding-bottom:2px;min-width:0;flex:1}
  .nav::-webkit-scrollbar{display:none}
  .nav{scrollbar-width:none}                        /* the standard property; Firefox reads only this */
  .nav .grp,.rail .foot{display:none}
  .nav a{white-space:nowrap;padding:8px 12px}
  /* Fade the edge a tool has scrolled behind. Both properties live in one rule:
     an unrecognised *property* is dropped on its own, unlike an unrecognised
     selector, which takes the whole rule with it — so Firefox reads mask-image
     here and Safari before 15.4 reads the -webkit- copy. */
  .nav[data-edge="start"]{-webkit-mask-image:linear-gradient(90deg,transparent,#000 20px);
    mask-image:linear-gradient(90deg,transparent,#000 20px)}
  .nav[data-edge="end"]{-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 20px),transparent);
    mask-image:linear-gradient(90deg,#000 calc(100% - 20px),transparent)}
  .nav[data-edge="both"]{-webkit-mask-image:linear-gradient(90deg,transparent,#000 20px,#000 calc(100% - 20px),transparent);
    mask-image:linear-gradient(90deg,transparent,#000 20px,#000 calc(100% - 20px),transparent)}
  h1{padding:18px 0 12px}
  .foot .chip{white-space:normal}   /* long notes wrap rather than push the page wide */
}

/* ---- shared atoms ---- */
.chip{display:inline-flex;align-items:center;gap:6px;border:0;border-radius:var(--r-pill);
  padding:7px 14px;font-size:var(--t-label);color:var(--soft);
  background:var(--fill);white-space:nowrap;max-width:100%}
/* In the rail a chip has 208px and cannot have nowrap: "Möglicherweise nicht
   mehr aktuell" is 288px against the English 180px and broke straight out of
   the column. Any language long enough would have done it. */
.rail .chip{white-space:normal;text-align:start;border-radius:var(--r-md);line-height:1.35}
.chip b{color:var(--ink);font-weight:500}
.k{font-size:var(--t-label);font-weight:500;color:var(--soft)}

.tool{background:var(--panel);border:1px solid var(--hair);border-radius:var(--r-lg);overflow:hidden;
  box-shadow:var(--lit), 0 1px 2px rgba(var(--sh),.04), 0 18px 44px -26px rgba(var(--sh),.22)}
/* the spine: input, then output. Everything else ranks below. */
.work{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr)}
.zone{padding:clamp(20px,3vw,32px);min-width:0}
.zone+.zone{border-inline-start:1px solid var(--hair)}
.zone.out{background:linear-gradient(180deg,var(--panel-tint),var(--panel) 240px)}
@media(max-width:1040px){
  .work{grid-template-columns:1fr}
  .zone+.zone{border-inline-start:0;border-top:1px solid var(--hair)}
  .zone.out{order:-1;border-top:0;border-bottom:1px solid var(--hair)}  /* answer first on small screens */
}
.split{height:1px;background:var(--hair);margin:20px 0}
.block{margin-top:24px}
.compare{border-top:1px solid var(--hair);padding:clamp(18px,2.4vw,26px) clamp(20px,3vw,32px)}
.bars{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(320px,100%),1fr));gap:0 32px;margin-top:10px}

/* controls */
.pills{display:flex;gap:6px;flex-wrap:wrap;margin-top:12px}
.pill{position:relative;font-size:var(--t-sm);padding:10px 18px;border:0;border-radius:var(--r-pill);color:var(--soft);
  background:var(--fill);
  transition:background 150ms var(--ease),color 150ms var(--ease),box-shadow 160ms var(--ease),transform 90ms var(--ease)}
.pill[aria-pressed="true"]{background:var(--panel);color:var(--ink);font-weight:500;
  box-shadow:0 0 0 1px rgba(var(--sh),.16), 0 1px 2px rgba(var(--sh),.05)}
@media(hover:hover){.pill:hover:not([aria-pressed="true"]){background:var(--fill-hi);color:var(--ink)}}
.pill:active{transform:scale(.97);transition-duration:50ms}

.alloys{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}
.alloy{position:relative;display:flex;align-items:center;gap:9px;border:0;border-radius:var(--r-pill);
  background:var(--fill);padding:8px 15px 8px 9px;
  transition:background 150ms var(--ease),box-shadow 160ms var(--ease),transform 90ms var(--ease)}
.alloy .f{font-size:var(--t-sm);color:var(--soft)}
.alloy[aria-pressed="true"]{background:var(--panel);
  box-shadow:0 0 0 1px rgba(var(--sh),.16), 0 1px 2px rgba(var(--sh),.05)}
.alloy[aria-pressed="true"] .f{color:var(--ink);font-weight:500}
@media(hover:hover){.alloy:hover:not([aria-pressed="true"]){background:var(--fill-hi)}}
.alloy:active{transform:scale(.97);transition-duration:50ms}

/* A bead is a small sphere of metal: rim light top-left, shadow bottom-right,
   one specular dot. Same light source as everything else. */
.bead{position:relative;width:16px;height:16px;border-radius:var(--r-circle);flex:none;
  box-shadow:inset 0 -1.5px 2.5px rgba(var(--sh),.30), inset 0 1px 1px rgba(255,255,255,.55),
             0 1px 1.5px rgba(var(--sh),.16)}
/* Physical on purpose: every object on the site is lit from the upper left,
   including the baked 3D webp icons. A highlight that flipped with text
   direction would light the beads from the opposite side to the artwork. */
.bead::after{content:"";position:absolute;left:26%;top:18%;width:26%;height:22%;border-radius:var(--r-circle);
  background:rgba(255,255,255,.85);filter:blur(.5px)}

.entry{display:flex;align-items:flex-end;gap:12px;border-bottom:1px solid var(--ink);padding-bottom:6px;margin-top:12px}
.entry input{font-family:var(--display);font-weight:600;font-size:var(--d-lg);letter-spacing:var(--track-display);
  width:4.4ch;border:0;background:transparent;color:var(--ink);outline:none;padding:0}
.entry input::-webkit-outer-spin-button,.entry input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.entry input[type=number]{appearance:textfield;-moz-appearance:textfield}   /* Firefox keeps its spinners otherwise */
.entry .u{font-size:var(--t-sm);color:var(--faint);padding-bottom:12px}
select{font-family:var(--sans);font-size:var(--t-sm);padding:10px 38px 10px 15px;border:0;
  border-radius:var(--r-pill);color:var(--ink);margin-top:14px;appearance:none;cursor:pointer;
  /* our own chevron, tucked in where it belongs — the native one floats loose */
  background:var(--fill) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="10" height="6" viewBox="0 0 10 6"><path d="M1 1l4 4 4-4" fill="none" stroke="%23575A63" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>') no-repeat right 14px center}
/* Padding and the chevron both follow the reading direction. `right 14px` and
   a physical padding shorthand do not: in Arabic they left the chevron on the
   reading-start side and the 38px gutter under the text. */
select{padding-inline:15px 38px}
[dir="rtl"] select{background-position:left 14px center}
/* A currency pill is a Latin symbol and a Latin code, so it is one LTR run.
   Without this, six of eight reordered to "GBP £" while A$ and C$ did not,
   because they happen to begin with a strong Latin letter. */
[dir="rtl"] .ptab{unicode-bidi:isolate;direction:ltr}

.dims{display:grid;gap:16px;margin-top:12px}
.dimhead{display:flex;justify-content:space-between;align-items:baseline;gap:8px;margin-bottom:4px}
.dim label{font-size:var(--t-sm);color:var(--soft)}
.dim .v{font-family:var(--display);font-weight:500;font-size:var(--t-md);color:var(--ink)}
/* The readout is also the input. It has to keep looking like the readout it
   replaced, so the only affordance is a hairline that solidifies on hover and
   focus — enough to say "type here", not enough to turn a row of figures into
   a row of form fields. */
.dim .v.edit{display:inline-flex;align-items:baseline;gap:3px;cursor:text;
  /* The field itself is ~25px tall, well under a 44px touch target. The
     padding grows the tappable area and the negative margin gives the space
     back, so the row does not move and the hairline stays under the digits
     rather than floating below them. */
  padding-block:10px;margin-block:-10px}
.dim .v.edit input{width:4.2ch;text-align:end;font:inherit;color:inherit;letter-spacing:inherit;
  background:none;border:0;border-bottom:1px dashed var(--hair);padding:0 1px;
  font-variant-numeric:tabular-nums}
.dim .v.edit input:hover{border-bottom-color:var(--soft)}
.dim .v.edit input:focus-visible{outline:none;border-bottom:1px solid var(--ink);background:var(--fill)}
.dim .v.edit .u{font-size:var(--t-sm);color:var(--faint)}
input[type=range]{-webkit-appearance:none;width:100%;height:24px;background:transparent;cursor:pointer;display:block}
input[type=range]::-webkit-slider-runnable-track{height:2px;background:var(--hair)}
/* The thumb is a stone in a bezel. The dark bead already read as onyx, so the
   ring is set the way a real one is: a band of metal with the light caught on
   the upper left and the far side in shadow, not a flat grey outline. Two
   backgrounds — the stone clipped to the padding box, the metal to the border
   box — so the border itself carries the gradient. */
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;box-sizing:border-box;
  width:20px;height:20px;border-radius:var(--r-circle);border:2px solid transparent;
  background:radial-gradient(circle at 34% 28%, var(--ink-lit), var(--ink) 62%) padding-box,
             linear-gradient(148deg, #F2F5F8 0%, #C3CDD8 28%, #8B97A5 54%, #AFBAC6 74%, #E1E7ED 100%) border-box;
  box-shadow:0 0 0 .5px rgba(var(--sh),.28), 0 1px 2px rgba(var(--sh),.22), 0 3px 8px -2px rgba(var(--sh),.28);
  margin-top:-9px;transition:transform 140ms var(--ease),box-shadow 140ms var(--ease)}
input[type=range]:active::-webkit-slider-thumb{transform:scale(.94);box-shadow:0 1px 2px rgba(var(--sh),.3)}
/* Firefox names these differently and will not accept them in the same rule as
   the -webkit- ones: one unrecognised selector drops the whole block, so the
   bezel has to be written out twice. Until now there was no -moz- rule at all
   and Firefox showed its default slider on every tool. */
input[type=range]::-moz-range-track{height:2px;background:var(--hair);border:none}
input[type=range]::-moz-range-thumb{box-sizing:border-box;
  width:20px;height:20px;border-radius:var(--r-circle);border:2px solid transparent;
  background:radial-gradient(circle at 34% 28%, var(--ink-lit), var(--ink) 62%) padding-box,
             linear-gradient(148deg, #F2F5F8 0%, #C3CDD8 28%, #8B97A5 54%, #AFBAC6 74%, #E1E7ED 100%) border-box;
  box-shadow:0 0 0 .5px rgba(var(--sh),.28), 0 1px 2px rgba(var(--sh),.22), 0 3px 8px -2px rgba(var(--sh),.28);
  transition:transform 140ms var(--ease),box-shadow 140ms var(--ease)}
input[type=range]:active::-moz-range-thumb{transform:scale(.94);box-shadow:0 1px 2px rgba(var(--sh),.3)}

/* the one answer */
.big{margin-top:8px}
.big .n{font-family:var(--display);font-weight:500;font-size:var(--d-answer);letter-spacing:-.04em;
  line-height:.92;color:var(--ink)}
.sub{font-size:var(--t-md);color:var(--soft);margin-top:14px}
.sub b{font-family:var(--display);font-weight:500;font-size:var(--t-md);color:var(--ink)}
.sub .mat{color:var(--alloy-ink);font-weight:500;transition:color 400ms var(--ease)}
/* the other two states, kept subordinate to the answer */
.also{display:flex;gap:18px;flex-wrap:wrap;margin-top:16px;
  font-size:var(--t-label);color:var(--faint)}
.also b{color:var(--soft);font-weight:500;margin-inline-start:5px}

/* the piece, drawn inside the output */
.obj{display:block;width:100%;height:auto}
.objwrap{margin:2px 0 18px}

/* comparison bars */
.bar{display:grid;grid-template-columns:130px 1fr 88px;gap:14px;align-items:center;padding:9px 0;width:100%;text-align:start}
.bar .nm{font-size:var(--t-sm);color:var(--soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bar .track{height:18px;border-radius:var(--r-pill);background:var(--fill);overflow:hidden;position:relative}
.bar .fill{position:absolute;inset:0 auto 0 0;border-radius:var(--r-pill);transition:width 480ms var(--ease)}
.bar .amt{font-size:var(--t-sm);text-align:end;color:var(--soft)}
.bar.on .nm{color:var(--ink);font-weight:600}
.bar.on .amt{color:var(--ink)}
@media(hover:hover){.bar:hover .nm{color:var(--ink)}}

/* data table */
/* Cells carry their side padding at rest, and the table is pulled out by the
   same amount, so the columns still line up with everything above while a lit
   row extends past its text instead of stopping dead on the first letter.
   Doing it this way also means selecting a row cannot shift the text: the old
   rule added the padding only when a row lit up, so the whole line jumped. */
table{width:calc(100% + 2 * var(--cell));margin:0 calc(-1 * var(--cell));
  border-collapse:collapse}
/* The table hangs out past its column by one cell-padding on each side. The
   wrapper opens up by exactly that much, or the overhang becomes a scrollbar. */
/* A wide table has to scroll inside its own box. Without this it widens the
   document instead, and in RTL that overflow lands on the reading-start edge
   where it cannot be scrolled back to — the Arabic prices table put its own
   h1 and price 77px off-screen at 375px with no way to reach them. */
/* Prices are substituted into prose at runtime, and a formatted value carries
   directional marks and a symbol that browsers treat as one unbreakable run —
   long enough to push a 375px page 109px wide with no break opportunity. */
.explain p{overflow-wrap:break-word}

/* Each table already carries a visible label above it, so the caption would
   only repeat it on screen. It is here for the machines: a chunked table row
   ("N | 17.11 | 53.8 | 6¾") is meaningless once retrieval separates it from
   its headings, and a caption travels with the rows. Clipped rather than
   display:none, which screen readers skip. */
caption{position:absolute;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap}

.tablewrap{margin:0 calc(-1 * var(--cell));padding:0 var(--cell);
  overflow-x:auto;overscroll-behavior-x:contain;
  /* A shadow on whichever edge still has table behind it. The two `local`
     layers are painted with the content and slide away as it scrolls; the two
     `scroll` layers stay put, so a shadow shows only while there is something
     to scroll to. No script, and it mirrors with direction on its own. The
     German table hides two whole columns at 375px and said nothing. */
  background:
    linear-gradient(to right, var(--panel) 40%, transparent) 0 0 / 28px 100% no-repeat local,
    linear-gradient(to left,  var(--panel) 40%, transparent) 100% 0 / 28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%,   rgba(var(--sh),.13), transparent) 0 0 / 14px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(var(--sh),.13), transparent) 100% 0 / 14px 100% no-repeat scroll}
/* A section label (.k) and a column head are the same voice, 12.5px and
   grey, stacked one above the other — two rows of the same thing reading as one
   flat block. The label keeps the caps because it titles the section; the heads
   drop to sentence case, which is a rank below and easier to read besides. */
th{font-size:var(--t-label);font-weight:500;color:var(--faint);
  font-weight:400;text-align:end;padding:0 var(--cell) 12px;border-bottom:1px solid var(--hair)}
th:first-child,td:first-child{text-align:start}
td{padding:14px var(--cell);border-bottom:1px solid var(--hair);font-size:var(--t-sm);
  color:var(--soft);text-align:end}
tr:last-child td{border-bottom:0}
/* rows in a #rows tbody are pickable — say so before the click */
#rows tr{cursor:pointer}
@media(hover:hover){
  #rows tr:not(.on):hover td{background:var(--fill)}
  #rows tr:not(.on):hover td:first-child{border-radius:var(--r-sm) 0 0 var(--r-sm)}
  #rows tr:not(.on):hover td:last-child{border-radius:0 var(--r-sm) var(--r-sm) 0}
}
tr.on td{color:var(--ink);font-weight:500;background:var(--fill)}
tr.on td:first-child{border-radius:var(--r-sm) 0 0 var(--r-sm)}
tr.on td:last-child{border-radius:0 var(--r-sm) var(--r-sm) 0}
td.uk{font-family:var(--display);font-weight:500;font-size:var(--t-md);color:var(--ink)}

.foot{margin:22px 0 0;display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap}

/* Loading. A shimmer stands in for a value that is genuinely on its way, sized
   to the value it replaces so nothing shifts when the real number lands. */
@keyframes shimmer{ from{background-position:100% 0} to{background-position:-100% 0} }
.is-loading .sk{
  color:transparent!important; border-radius:var(--r-sm); user-select:none;
  background-image:linear-gradient(90deg,var(--fill) 20%,var(--fill-hi) 42%,var(--fill) 64%);
  background-size:220% 100%; animation:shimmer 1.5s linear infinite;
}
.is-loading .sk *{visibility:hidden}
.is-loading .sk-line{display:inline-block;min-width:9ch}
@media(prefers-reduced-motion:reduce){
  .is-loading .sk{animation:none;background:var(--fill)}
}
/* prices failed rather than pending */
.pricefail{display:none;font-size:var(--t-sm);color:var(--alert-ink);margin-top:12px}
.is-failed .pricefail{display:block}

/* feedback line, directly under the tool */
/* inline tooltip trigger: the text stays in the sentence, the rail's black
   bubble (.tip) rides above it on hover or keyboard focus */
/* Anchored to the paragraph, not to the phrase. .when is an inline, so when it
   wraps across two line boxes its containing block becomes the union of its
   fragments and inset-inline-start:0 resolves to left:-180px — the tooltip lands
   outside the paragraph entirely, and being only visibility:hidden it still grows
   the scroll area. In English that overflow sits on the end edge and is harmless;
   in Arabic it lands where the RTL scroll origin is pinned, so the page opened
   with its own headline 77px off-screen and no way to scroll back. */
.explain p, .pagemeta{position:relative}
.when{text-decoration:underline dotted var(--hair);text-underline-offset:3px;cursor:help}
.when:hover>.tip,.when:focus-visible>.tip{opacity:1;visibility:visible;
  transition:opacity 150ms var(--ease),visibility 0s}
.undertool{margin:14px 4px 0;font-size:var(--t-sm);color:var(--faint);line-height:1.55}
.undertool a{color:var(--ink);text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;
  text-decoration-color:var(--hair)}
@media(hover:hover){.undertool a:hover{text-decoration-color:var(--ink)}}

/* A word from the bench, shown only when the numbers on screen call for it:
   a band wide enough to wear tight, a bezel wall too thick to push over the
   stone. The explainers below already say all of this, but nobody reads them
   at the moment they are dragging the slider. */
/* The bench note is the one thing here a calculator farm cannot copy, so it is
   not a blockquote. A quote bar says "someone said this"; the note is the
   product telling you what the metal will actually do.

   It gets the only warm ground on the site, so trade knowledge has a surface of
   its own. Warm, but deliberately NOT the yellow of .chip.warn — that cream
   already means "these prices are stale", and a bench note is not a warning.
   This one is a greige, closer to paper than to caution. */
.benchnote{margin-top:18px;max-width:46ch;padding:14px 16px;border-radius:var(--r-md);
  background:var(--bench-bg)}
/* The mark is the punch. A hallmark is a maker's stamp, so the identity is not
   decoration here — it is the thing the component is imitating. Small enough to
   read as struck rather than as a second logo competing with the rail's. */
.benchnote .bn-k{display:flex;align-items:center;gap:8px;
  font-size:var(--t-label);font-weight:500;
  color:var(--ink);margin-bottom:9px}
.benchnote .bn-mk{height:11px;aspect-ratio:1.4167;width:auto;flex:none;opacity:.9}
.benchnote .bn-b{display:block;font-size:var(--t-sm);line-height:1.55;color:var(--soft)}

/* site footer */
.sitefoot{margin-top:40px;padding-top:18px;border-top:1px solid var(--hair);display:flex;
  flex-direction:column;gap:16px;font-size:var(--t-sm);color:var(--faint)}
/* The two closing lines share one rule: the standing fact on the left, the
   credit pushed to the right margin. Stacking them left a band of white
   between two short sentences that did not need one. */
.footline{display:flex;justify-content:space-between;align-items:baseline;
  gap:10px 28px;flex-wrap:wrap}
.prefs{display:flex;align-items:center;gap:12px 22px;flex-wrap:wrap;
  padding-bottom:14px;border-bottom:1px solid var(--hair)}

.plabel{white-space:nowrap;font-size:var(--t-label);font-weight:500;color:var(--faint)}
.pgroup{display:flex;gap:4px;flex-wrap:wrap}
/* A label and the control it names are one unit. As bare siblings in a wrapping
   flex row they could separate, and did: RING SIZES stayed on the first line
   while its pills dropped to the second. */
.pset{display:flex;align-items:center;gap:10px;flex-wrap:nowrap}
/* Same box as .ptab, because it sits in the same row as .ptab. It was 28px
   against their 35px and sat 11px lower, which is what "the spacing" was. */
.plang{font-family:inherit;font-size:var(--t-sm);color:var(--soft);
  height:35px;padding:0 30px 0 13px;border:0;border-radius:var(--r-pill);cursor:pointer;
  margin:0;                    /* the global select rule adds margin-top:14px for
                                  stacked selects; this one sits inline in a row */
  background:var(--fill) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' fill='none' stroke='%23575A63' stroke-width='1.4'%3E%3Cpath d='M1 1l4 4 4-4'/%3E%3C/svg%3E") no-repeat right 10px center;
  appearance:none;-webkit-appearance:none}
.plang:hover{background-color:var(--fill-hi)}
.ptab{font-size:var(--t-sm);padding:7px 13px;border-radius:var(--r-pill);background:var(--fill);color:var(--soft);
  border:0;transition:background 150ms var(--ease),color 150ms var(--ease),box-shadow 160ms var(--ease),transform 90ms var(--ease)}
.ptab[aria-pressed="true"]{background:var(--panel);color:var(--ink);font-weight:500;
  box-shadow:0 0 0 1px rgba(var(--sh),.16), 0 1px 2px rgba(var(--sh),.05)}
@media(hover:hover){.ptab:hover:not([aria-pressed="true"]){background:var(--fill-hi);color:var(--ink)}}
.ptab:active{transform:scale(.97);transition-duration:50ms}
.madeby{font-size:var(--t-sm);color:var(--faint)}
.sitefoot a{color:var(--soft);text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;
  text-decoration-color:var(--hair);transition:color 150ms var(--ease)}
@media(hover:hover){.sitefoot a:hover{color:var(--ink)}}

/* Explainer. Prose keeps a readable measure (~68ch); the space beside it is
   given to a contents rail rather than left as a void. */
.explain{margin:56px 0 0;padding-top:34px;border-top:1px solid var(--hair);
  display:grid;grid-template-columns:minmax(0,68ch) minmax(0,1fr);gap:0 clamp(32px,6vw,90px);
  align-items:start}
.explain>*{grid-column:1}
.toc{grid-column:2;grid-row:1/999;position:sticky;top:28px;align-self:start;
  padding-inline-start:clamp(0px,2vw,20px);border-inline-start:1px solid var(--hair)}
.toc .k{margin-bottom:12px;display:block}
.toc a{display:block;font-size:var(--t-sm);line-height:1.4;color:var(--soft);padding:7px 0;
  transition:color 150ms var(--ease)}
.toc a:hover{color:var(--ink)}
.toc a.on{color:var(--ink);font-weight:500}
@media(max-width:1180px){
  .explain{grid-template-columns:minmax(0,68ch)}
  .toc{display:none}
}
/* Vertical rhythm, one source of truth.
   .explain is a grid, so margins never collapse and every gap below is exactly
   what is written. Each boundary is larger than the one it contains, so the
   hierarchy reads without needing rules or colour:
     8   an answer bound to its question
     16  one paragraph to the next
     32  one FAQ item to the next
     56  one section to the next                                              */
.explain>*{margin:0}
.explain>*+*{margin-top:16px}
.explain>*+h3{margin-top:32px}
.explain>*+h2{margin-top:56px}
.explain>h2+*{margin-top:16px}
.explain>h3+p{margin-top:8px}
.explain>.toc+*{margin-top:0}          /* the rail is a sibling; it starts nothing */

.explain h2{font-family:var(--display);font-weight:500;font-size:var(--d-md);
  letter-spacing:var(--track-display)}
.explain h3{font-family:var(--display);font-weight:500;font-size:var(--t-md);letter-spacing:-.012em}
.explain p{font-size:var(--t-md);line-height:1.62;color:var(--soft)}
.explain p strong{color:var(--ink);font-weight:500}
.explain>ul{padding-inline-start:20px}         /* indent without a margin the rhythm owns */
.explain li{font-size:var(--t-md);line-height:1.62;color:var(--soft)}
.explain li+li{margin-top:7px}
.explain .eq{font-size:var(--t-sm);color:var(--ink);background:var(--panel);
  border:1px solid var(--hair);border-radius:var(--r-md);padding:14px 18px;display:inline-block}

/* ---- consent banner (only rendered when an analytics ID is configured) ---- */
.consenting .sitefoot{padding-bottom:150px}
@media (min-width:760px){ .consenting .sitefoot{padding-bottom:96px} }
.consent{position:fixed;inset-inline-start:14px;bottom:14px;z-index:200;max-width:380px;
  display:flex;flex-direction:column;gap:12px;padding:16px 18px;border-radius:var(--r-md);
  background:var(--panel);box-shadow:var(--ring-hair),0 8px 28px rgba(var(--sh),.14)}
.consent p{font-size:var(--t-sm);line-height:1.5;color:var(--soft)}
.consent-act{display:flex;gap:8px;justify-content:flex-end}
.consent-act button{padding:8px 16px;border-radius:var(--r-pill);font-size:var(--t-sm);color:var(--soft);
  background:var(--fill);transition:background 150ms var(--ease),color 150ms var(--ease)}
.consent-act button.pri{background:var(--ink);color:#fff}
@media(hover:hover){.consent-act button:hover{background:var(--fill-hi);color:var(--ink)}
  .consent-act button.pri:hover{background:#000;color:#fff}}
@media(max-width:520px){.consent{inset-inline:10px;bottom:10px;max-width:none}}

/* ---- right-to-left ----
   Numbers, size codes and measurements are written left-to-right even on an
   Arabic page: a size is "6¾" and not "¾6", a measurement is "17.31 mm" and
   not "mm 17.31". Both break because a fraction glyph and a unit are neutral
   or Latin runs, which an RTL paragraph reorders around the digits.

   unicode-bidi:plaintext cannot fix "6¾" — it has no strong character to take
   its direction from — so these carry an explicit LTR base. An Arabic string
   inside one still renders right-to-left, because Arabic is strongly typed;
   only the neutrals change side. Alignment is restated because text-align:end
   follows the direction property and would otherwise flip back. */
/* Forced LTR is for content that is ONLY a Latin size code or a bare number —
   "6¾", "N½", "17.31" — where a fraction glyph is a neutral run with no strong
   character to take direction from, so plaintext cannot help it.

   It must not touch anything containing Arabic. Units are translated now (مم,
   جم), and Arabic is strongly typed, so Intl already orders those correctly;
   forcing LTR over them put the unit on the wrong side and rendered "5.00 مج".
   The rule that fixed "mm 17.31" became the thing breaking "5.00 جم" the moment
   the unit itself was translated. Hence .codes — the one table whose every cell
   is a bare code — rather than td, and no .n/.sub/.rate at all. */
[dir="rtl"] .codes td, [dir="rtl"] .sys .v{unicode-bidi:isolate; direction:ltr}
[dir="rtl"] .codes td{text-align:left}
[dir="rtl"] .codes td:first-child{text-align:right}
