/* ==========================================================================
   EasyCalculatorSmart - CALCULATOR DESIGN SYSTEM
   ==========================================================================

   One design language for every individual calculator page, and not one
   line of it per page.

   WHAT LOADS THIS, AND WHAT CAN NEVER SEE IT
   -----------------------------------------------------------------------
   header.php links this file only when the ROUTE is 'calc'. A tool page
   carries body.is-tool and never requests the bytes; the homepage, both
   directories, the category hubs, search and the legal pages never
   request them either. On top of that every selector below is scoped to
   body.is-calc, so even if the link were added to the wrong page by
   accident, nothing here could reach a design that is already signed
   off. Two independent locks, because the /tools/ UI must not move by a
   pixel.

   RELATIONSHIP TO SECTION 35 OF main.css
   -----------------------------------------------------------------------
   Section 35 gives a calculator or a tool its page: the wash, the head,
   the working surface, the article column, the rail. This file is the
   layer above that, and only for calculators: the mode cards, the
   calculation flow, the diagrams, the amplified result, the band meter,
   the worked-steps card, the preset chips. It loads after main.css and
   is allowed to win, and it changes PRESENTATION ONLY -- no rule here
   renames a control, reorders a field, touches a formula or edits a word
   of an article.

   WHY THERE ARE ALMOST NO NEW STRINGS
   -----------------------------------------------------------------------
   Fifty-two calculators are published in five languages from one
   template each. A component that needs a new sentence needs it in every
   one of those languages or a Russian page ships an English label, so
   the components here are built out of what the page already says: a
   mode card carries the radio's own translated label, a flow step
   carries a symbol, a diagram carries numbers. Icons and geometry are
   language-neutral by construction.

   NAMESPACE
   -----------------------------------------------------------------------
   Every new class starts cs- (calculator system). Existing classes are
   only ever restyled, never renamed: .result, .stat, .step-list,
   .segmented, .chip, .meter and .disclosure keep working exactly as
   they did for the calculators that have not been through the upgrade
   yet, which is what makes this safe to roll out page by page.
   ========================================================================== */

/* --------------------------------------------------------------------
   1. SCOPE AND LOCAL TOKENS

   --cs-accent-2 is the calculator-family accent: a second hue, used
   only for a diagram stroke, a meter's far end and a mode-card icon
   tint. It defaults to the brand teal, so a calculator that says
   nothing looks exactly like the rest of the site; a category may shift
   it a few degrees to give a family its own quiet identity. Nothing
   here ever repaints a button, a link or a body of text with it.
   ------------------------------------------------------------------ */

body.is-calc {
  --cs-accent-2:      var(--accent);
  --cs-accent-2-soft: var(--accent-soft);
  --cs-accent-2-line: var(--accent-line);

  /* Geometry, so every component in the family rounds and spaces the
     same way without repeating the numbers. */
  --cs-card-r:  14px;
  --cs-tile-r:  11px;

  /* The diagram ink. A drawing has to hold up on both themes, and on
     the light one a hairline at --line is too faint to read as a
     measurement. */
  --cs-ink:      var(--text-soft);
  --cs-ink-soft: var(--line-strong);
}

/* Category accents. Set from the registry's own category by
   header.php, so a page cannot opt into the wrong one and a new
   calculator inherits its family the day it ships.

   These are deliberately small moves: relationships warms towards rose,
   health cools towards a clinical blue-green, career and money take the
   deeper teal, games borrow the platform violet at low strength. The
   page is still a teal calculator on the navy ground section 37 gives it.

   ONE SET OF VALUES, NOT TWO, AND WHY
   ---------------------------------------------------------------------
   These were first written as a light pair and a dark pair behind
   html[data-theme="dark"], which is the normal shape for a themed
   token. It is the wrong shape HERE: main.css section 37 makes a post
   page navy in BOTH themes on purpose -- it restates the whole dark
   role set on body.is-post and says so -- so --surface under these
   rules is #0c0f1c whichever theme the visitor picked, and the theme
   attribute says nothing about what this ink sits on.

   The light pair therefore painted a near-white carton face (#eef2f8)
   and a dark slate edge (#4b6b93) onto a navy card for every visitor
   whose theme was light. These values are the ones tuned for navy and
   they now apply unconditionally, because the surface does.

   The rule this leaves behind: inside body.is-calc, pick a colour
   against --surface, never against the theme. */
body.is-calc.cs-fam-relationships {
  --cs-accent-2:      #f0a0bf;
  --cs-accent-2-soft: #33202a;
  --cs-accent-2-line: #4d2f3c;
}
body.is-calc.cs-fam-health {
  --cs-accent-2:      #7fc6de;
  --cs-accent-2-soft: #162a33;
  --cs-accent-2-line: #23414e;
}
body.is-calc.cs-fam-career {
  --cs-accent-2:      #5ecfc2;
  --cs-accent-2-soft: #12302e;
  --cs-accent-2-line: #1d4a46;
}
body.is-calc.cs-fam-games {
  --cs-accent-2:      #b0a0f6;
  --cs-accent-2-soft: #241f3d;
  --cs-accent-2-line: #372f5c;
}
body.is-calc.cs-fam-materials,
body.is-calc.cs-fam-shipping {
  --cs-accent-2:      #9ab6d8;
  --cs-accent-2-soft: #1b2430;
  --cs-accent-2-line: #2b3a4c;
}

/* --------------------------------------------------------------------
   2. MODE CARDS

   The visual answer to "what can this calculator do?".

   Built on the native radio group the page already had. The input is
   the control -- checked state, keyboard arrows, form semantics and the
   calculator's own change listener are all the browser's, unchanged --
   and the label is the card. That is the whole reason this is markup and
   CSS rather than JavaScript: nothing to initialise, nothing to break,
   and it works on a page whose script failed to load.

   A card is a label, an optional icon tile and an optional one-line
   hint. Every one of those strings is one the page already had.
   ------------------------------------------------------------------ */

body.is-calc .cs-modes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: var(--s3);
  margin-block-end: var(--s5);
  padding: 0;
  border: 0;
  background: none;
}

/* Two modes get a straight half-and-half rather than auto-fit, which
   would strand the second card on its own row at some widths. */
body.is-calc .cs-modes-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

body.is-calc .cs-modes > input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

body.is-calc .cs-modes > label {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 2px var(--s3);
  min-block-size: 62px;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--cs-card-r);
  background: var(--surface);
  cursor: pointer;
  text-align: start;
  transition: border-color var(--dur-fast), background-color var(--dur-fast),
              box-shadow var(--dur), transform var(--dur);
}

/* The icon tile. Quiet until the mode is the live one, which is the
   single clearest way a card can say "you are here" without colouring
   the whole card in. */
body.is-calc .cs-mode-ic {
  grid-row: 1 / span 2;
  display: grid;
  place-items: center;
  inline-size: 38px;
  block-size: 38px;
  border-radius: var(--cs-tile-r);
  border: 1px solid var(--line);
  background: var(--surface-sunk);
  color: var(--text-faint);
  transition: background-color var(--dur), color var(--dur),
              border-color var(--dur);
}
body.is-calc .cs-mode-ic svg { inline-size: 19px; block-size: 19px; }

body.is-calc .cs-mode-tx {
  grid-column: 2;
  align-self: end;
  font-size: 0.94rem;
  font-weight: 640;
  line-height: 1.32;
  color: var(--text);
  text-wrap: balance;
}

/* The hint. Optional, and only ever a string the page already carried. */
body.is-calc .cs-mode-sub {
  grid-column: 2;
  align-self: start;
  font-size: 0.79rem;
  line-height: 1.4;
  color: var(--text-faint);
}

/* With no hint the label centres itself against the tile instead of
   sitting on the baseline a missing second row left behind. */
body.is-calc .cs-modes > label .cs-mode-tx:only-of-type { align-self: center; }

body.is-calc .cs-modes > label:hover {
  border-color: var(--line-strong);
  background: var(--surface-alt);
  box-shadow: var(--shadow-sm);
  transform: translateY(-1px);
}
body.is-calc .cs-modes > label:hover .cs-mode-ic {
  color: var(--accent);
  border-color: var(--accent-line);
}

body.is-calc .cs-modes > input:checked + label {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: var(--shadow-sm);
}
body.is-calc .cs-modes > input:checked + label .cs-mode-ic {
  background-image: var(--grad-calc);
  border-color: transparent;
  color: var(--on-tile);
}
body.is-calc .cs-modes > input:checked + label .cs-mode-tx { color: var(--accent-strong); }

/* The live card carries a rule along its top edge, drawn from the
   centre out. It is the one piece of motion in the component and it
   runs once, on selection. */
body.is-calc .cs-modes > label::after {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline: 12px;
  block-size: 3px;
  border-radius: var(--r-full);
  background: var(--grad-calc);
  transform: scaleX(0);
  transition: transform var(--dur) var(--ease-out);
}
body.is-calc .cs-modes > input:checked + label::after { transform: scaleX(1); }

body.is-calc .cs-modes > input:focus-visible + label {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* Cards that drive a <select> rather than a radio group.

   A handful of calculators switch mode with a menu because their script
   reads select.value, and rewriting that script to read a radio would
   mean editing working logic to change how a page looks. So those cards
   are buttons in a radiogroup, calc-ui.js keeps them in step with the
   menu, and the menu itself is visually hidden while they are live.

   Everything below is the same treatment as the radio version, keyed on
   aria-checked instead of :checked -- one component, two controls behind
   it. */
body.is-calc .cs-modes > [role="radio"] {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 2px var(--s3);
  min-block-size: 62px;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--cs-card-r);
  background: var(--surface);
  cursor: pointer;
  text-align: start;
  font: inherit;
  transition: border-color var(--dur-fast), background-color var(--dur-fast),
              box-shadow var(--dur), transform var(--dur);
}
body.is-calc .cs-modes > [role="radio"]:hover {
  border-color: var(--line-strong);
  background: var(--surface-alt);
  box-shadow: var(--shadow-sm);
  transform: translateY(-1px);
}
body.is-calc .cs-modes > [role="radio"]:hover .cs-mode-ic {
  color: var(--accent);
  border-color: var(--accent-line);
}
body.is-calc .cs-modes > [role="radio"][aria-checked="true"] {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: var(--shadow-sm);
}
body.is-calc .cs-modes > [role="radio"][aria-checked="true"] .cs-mode-ic {
  background-image: var(--grad-calc);
  border-color: transparent;
  color: var(--on-tile);
}
body.is-calc .cs-modes > [role="radio"][aria-checked="true"] .cs-mode-tx {
  color: var(--accent-strong);
}
body.is-calc .cs-modes > [role="radio"]::after {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline: 12px;
  block-size: 3px;
  border-radius: var(--r-full);
  background: var(--grad-calc);
  transform: scaleX(0);
  transition: transform var(--dur) var(--ease-out);
}
body.is-calc .cs-modes > [role="radio"][aria-checked="true"]::after { transform: scaleX(1); }
body.is-calc .cs-modes > [role="radio"]:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* The menu the cards took over from. Hidden from sight but still in the
   accessibility tree and still the element the calculator's script reads
   and writes, so nothing about the page's logic changes. It comes back
   the moment the cards are not there to replace it. */
body.is-calc .field.cs-native-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* A block that has to break out of the grid it is sitting in.
   A .field-row lays its children out in columns, and a set of mode
   cards belongs across the whole row rather than in one column of it.
   Two pages needed this and one of them had grown a local class for it
   (.gg-span); this is the same rule, named for the system. */
body.is-calc .cs-span {
  grid-column: 1 / -1;
  margin-block-start: 0;
}

/* The group's own heading, where the page already had a label for the
   control. Not a new string: the same element, restyled. */
body.is-calc .cs-modes-label {
  display: block;
  margin-block-end: var(--s3);
  font-size: 0.88rem;
  font-weight: 650;
  color: var(--text-soft);
}

/* --------------------------------------------------------------------
   3. CALCULATION FLOW

   INPUT -> CALCULATION -> RESULT, in the page's own symbols.

   Deliberately arithmetic rather than prose: "L x W x H" then "m3" is
   the same in every language this site publishes in, which is why the
   component can exist at all on a page translated five ways. Where a
   flow would say nothing a reader does not already know, the calculator
   simply does not get one.
   ------------------------------------------------------------------ */

body.is-calc .cs-flow {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  justify-content: center;
  gap: var(--s2);
  margin-block: var(--s5);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--cs-card-r);
  background: var(--surface-sunk);
}

body.is-calc .cs-flow-step {
  display: grid;
  gap: 2px;
  flex: 0 1 auto;
  min-inline-size: 0;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--cs-tile-r);
  background: var(--surface);
  text-align: center;
}

body.is-calc .cs-flow-k {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

body.is-calc .cs-flow-v {
  font-family: var(--font-mono);
  font-size: 0.97rem;
  font-weight: 620;
  color: var(--text);
  white-space: nowrap;
}

/* The final step is the answer, so it is the one that is allowed to
   carry the accent. */
body.is-calc .cs-flow-step-out {
  border-color: var(--accent-line);
  background: var(--accent-soft);
}
body.is-calc .cs-flow-step-out .cs-flow-v { color: var(--accent-strong); }

/* The connector. A chevron rather than a full arrow: at this size an
   arrowhead plus shaft turns to mush, and the chevron mirrors correctly
   in RTL from one rule in rtl.css. */
body.is-calc .cs-flow-arrow {
  display: grid;
  place-items: center;
  color: var(--text-faint);
  opacity: .75;
}
body.is-calc .cs-flow-arrow svg { inline-size: 18px; block-size: 18px; }

/* --------------------------------------------------------------------
   4. DIAGRAM FRAME

   Custom SVG, drawn for the calculator it sits on -- a carton with its
   three dimensions, a glass pane on edge, a tax ladder, a timeline.
   Never a stock photograph, and never decoration: if a reader learns
   nothing from the drawing, the calculator does not get one.

   The frame is here; the drawings are in the templates, where they can
   read the page's own values.
   ------------------------------------------------------------------ */

body.is-calc .cs-diagram {
  margin-block: var(--s5);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--cs-card-r);
  background:
    radial-gradient(70% 80% at 50% 0%, var(--cs-accent-2-soft) 0%, transparent 72%),
    var(--surface-sunk);
}

body.is-calc .cs-diagram > svg {
  display: block;
  inline-size: 100%;
  max-inline-size: 460px;
  block-size: auto;
  margin-inline: auto;
}

/* A wide drawing -- a ladder, a timeline -- gets the full column. */
body.is-calc .cs-diagram-wide > svg { max-inline-size: 100%; }

body.is-calc .cs-diagram-cap {
  margin-block: var(--s3) 0;
  font-size: 0.82rem;
  line-height: 1.5;
  text-align: center;
  color: var(--text-faint);
}

/* Shared drawing conventions, so every diagram on the site reads as
   the same hand. Templates use these class names on SVG elements
   instead of inline colours, which is also what keeps a drawing legible
   when the theme flips. */
body.is-calc .cs-d-face   { fill: var(--cs-accent-2-soft); }
body.is-calc .cs-d-face-2 { fill: var(--cs-accent-2-line); }
body.is-calc .cs-d-edge   { fill: none; stroke: var(--cs-accent-2); stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round; }
body.is-calc .cs-d-edge-soft { fill: none; stroke: var(--cs-ink-soft); stroke-width: 1.2; }
body.is-calc .cs-d-dim    { fill: none; stroke: var(--cs-ink); stroke-width: 1.1; stroke-linecap: round; }
body.is-calc .cs-d-dim-dash { fill: none; stroke: var(--cs-ink-soft); stroke-width: 1.1; stroke-dasharray: 4 4; }
body.is-calc .cs-d-label {
  fill: var(--text);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
}
body.is-calc .cs-d-label-soft {
  fill: var(--text-faint);
  font-family: var(--font-sans);
  font-size: 10.5px;
  font-weight: 600;
}
body.is-calc .cs-d-accent { fill: var(--cs-accent-2); }
body.is-calc .cs-d-hi     { fill: var(--accent); }

/* --------------------------------------------------------------------
   5. THE RESULT

   The answer is why the visitor is here, so it is the loudest thing on
   the page -- and it arrives, rather than appearing.
   ------------------------------------------------------------------ */

body.is-calc .result {
  border-color: var(--accent-line);
  background:
    linear-gradient(180deg, var(--accent-soft) 0%, transparent 180px),
    var(--surface);
  box-shadow: var(--shadow-md);
}

body.is-calc .result-primary {
  position: relative;
  padding-block: var(--s6) var(--s5);
  text-align: center;
}

body.is-calc .result-label {
  display: block;
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--text-faint);
}

body.is-calc .result-value {
  display: block;
  margin-block-start: var(--s2);
  font-size: clamp(2.2rem, 1.6rem + 3.2vw, 3.4rem);
  font-weight: 720;
  line-height: 1.06;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  overflow-wrap: anywhere;
}

body.is-calc .result-primary .result-sub {
  max-inline-size: 52ch;
  margin-block-start: var(--s3);
  margin-inline: auto;
  font-size: 0.97rem;
  line-height: 1.55;
  color: var(--text-soft);
}

/* The entrance. One run, on the frame the panel is unhidden, and
   nothing loops afterwards. calc-ui.js adds the class and takes it off
   when the animation ends, so a second calculation animates again. */
@keyframes cs-result-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes cs-value-in {
  from { opacity: 0; transform: translateY(6px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

body.is-calc .result.cs-in { animation: cs-result-in var(--dur-slow) var(--ease-out) both; }
body.is-calc .result.cs-in .result-value { animation: cs-value-in var(--dur-reveal) var(--ease-out) both; }

/* Supporting result cards.

   .stat and .stats are the site's own components (section 9) and every
   calculator that has secondary figures already renders them, which is
   why this is a restyle and not a new component: those pages gain the
   treatment without one of them being edited.

   The accent rule along the leading edge is what turns a row of grey
   boxes into a set of readings. */
body.is-calc .stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: var(--s3);
}

body.is-calc .stat {
  position: relative;
  padding: var(--s4);
  padding-inline-start: calc(var(--s4) + 3px);
  border: 1px solid var(--line);
  border-radius: var(--cs-card-r);
  background: var(--surface-sunk);
  overflow: hidden;
  transition: border-color var(--dur), background-color var(--dur);
}
body.is-calc .stat::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 3px;
  background: var(--grad-calc);
  opacity: .55;
}
body.is-calc .stat:hover { border-color: var(--accent-line); background: var(--surface); }
body.is-calc .stat:hover::before { opacity: 1; }

body.is-calc .stat-label {
  font-size: 0.78rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  color: var(--text-faint);
}
body.is-calc .stat-value {
  display: block;
  margin-block-start: 2px;
  font-size: 1.4rem;
  font-weight: 700;
  line-height: 1.16;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
  color: var(--text);
}
body.is-calc .stat-sub {
  display: block;
  margin-block-start: 2px;
  font-size: 0.79rem;
  line-height: 1.45;
  color: var(--text-faint);
}

/* A stat that IS the headline of its group -- a take-home figure, a
   chargeable weight -- may say so. */
body.is-calc .stat-lead {
  border-color: var(--accent-line);
  background: var(--accent-soft);
}
body.is-calc .stat-lead .stat-value { color: var(--accent-strong); }
body.is-calc .stat-lead::before { opacity: 1; }

/* The waiting area, before the first calculation. */
body.is-calc .result-empty {
  display: grid;
  justify-items: center;
  gap: var(--s3);
  padding-block: var(--s7);
  text-align: center;
}
body.is-calc .result-empty svg {
  inline-size: 34px;
  block-size: 34px;
  color: var(--text-faint);
  opacity: .8;
}
body.is-calc .result-empty p {
  max-inline-size: 42ch;
  margin: 0;
  font-size: 0.95rem;
  color: var(--text-faint);
}

/* --------------------------------------------------------------------
   6. SHOW YOUR WORK

   Most calculators already print their steps into an .ol.step-list
   inside the result panel, written by their own script. This frames
   that list as the worked answer it is -- a formula card with the
   arithmetic in monospace -- without any page changing a line of its
   markup or a word of its steps.
   ------------------------------------------------------------------ */

body.is-calc .step-list {
  margin: 0;
  padding: var(--s4);
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--accent);
  border-radius: var(--cs-card-r);
  background: var(--surface-sunk);
  list-style: none;
  counter-reset: cs-step;
}

body.is-calc .step-list > li {
  position: relative;
  margin: 0;
  padding-block: var(--s2);
  padding-inline-start: var(--s6);
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--text-soft);
  counter-increment: cs-step;
}
body.is-calc .step-list > li + li { border-block-start: 1px dashed var(--line); }

body.is-calc .step-list > li::before {
  content: counter(cs-step);
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: calc(var(--s2) + 2px);
  display: grid;
  place-items: center;
  inline-size: 22px;
  block-size: 22px;
  border-radius: var(--r-full);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--accent-strong);
}

/* The arithmetic inside a step. Scripts emit the numbers in <code> or
   <strong>; both should read as arithmetic rather than as prose. */
body.is-calc .step-list code,
body.is-calc .step-list .num {
  font-family: var(--font-mono);
  font-size: 0.93em;
  color: var(--text);
}

/* A standalone formula card, where a calculator wants the rule stated
   rather than the steps walked. */
body.is-calc .cs-work {
  margin-block: var(--s4);
  padding: var(--s4) var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--cs-card-r);
  background: var(--surface-sunk);
}
body.is-calc .cs-work-k {
  display: block;
  margin-block-end: var(--s2);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
body.is-calc .cs-work-f {
  display: block;
  font-family: var(--font-mono);
  font-size: 1.02rem;
  font-weight: 620;
  line-height: 1.7;
  color: var(--text);
  overflow-x: auto;
}
body.is-calc .cs-work-out {
  display: block;
  margin-block-start: var(--s2);
  font-family: var(--font-mono);
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--accent-strong);
}

/* --------------------------------------------------------------------
   7. BAND METER

   For a number that belongs to a range and means something different
   in each part of it: a BMI, a body-fat percentage, an attendance
   figure, a grade, a compatibility score.

   Rules this component keeps:
     - the bands are labelled, so colour is never the only signal;
     - the marker carries the value as text;
     - it is only ever used where the scale has a published or stated
       meaning, never to dress up an arbitrary number.
   ------------------------------------------------------------------ */

body.is-calc .cs-meter { margin-block: var(--s4); }

body.is-calc .cs-meter-track {
  position: relative;
  display: flex;
  block-size: 14px;
  border-radius: var(--r-full);
  overflow: hidden;
  background: var(--surface-sunk);
  border: 1px solid var(--line);
}

body.is-calc .cs-meter-seg { block-size: 100%; }
/* Band colours, unconditional for the same reason the category accents
   are: section 37 makes this page navy in both themes, so the theme
   attribute says nothing about the ground these sit on. Picked against
   --surface. */
body.is-calc .cs-meter-seg-1 { background: #2b4258; }
body.is-calc .cs-meter-seg-2 { background: #235142; }
body.is-calc .cs-meter-seg-3 { background: #59491f; }
body.is-calc .cs-meter-seg-4 { background: #603a22; }
body.is-calc .cs-meter-seg-5 { background: #5d2b2b; }

/* The marker. inset-inline-start is set by the calculator's script as a
   percentage, which is also why it is a custom property: the script
   writes one value and the transition is this file's business. */
body.is-calc .cs-meter-marker {
  position: absolute;
  inset-block: -3px;
  inset-inline-start: var(--cs-at, 0%);
  inline-size: 3px;
  margin-inline-start: -1.5px;
  border-radius: var(--r-full);
  background: var(--text);
  box-shadow: 0 0 0 2px var(--surface);
  transition: inset-inline-start var(--dur-slow) var(--ease-out);
}

body.is-calc .cs-meter-scale {
  display: flex;
  margin-block-start: var(--s2);
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
  color: var(--text-faint);
}
body.is-calc .cs-meter-scale > span {
  flex: 1 1 0;
  text-align: center;
  padding-inline: 2px;
  line-height: 1.3;
}
body.is-calc .cs-meter-scale > span:first-child { text-align: start; }
body.is-calc .cs-meter-scale > span:last-child { text-align: end; }

body.is-calc .cs-meter-read {
  margin-block-start: var(--s3);
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text-soft);
}
body.is-calc .cs-meter-read strong { color: var(--text); }

/* A single-value fill, for a progress-style reading -- attendance
   against a target, a percentage of a whole. */
body.is-calc .cs-fill-track {
  position: relative;
  block-size: 12px;
  border-radius: var(--r-full);
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  overflow: hidden;
}
body.is-calc .cs-fill {
  /* The fill is a <span>, so it has to be blockified before a width or
     a height means anything to it. Without this the bar is a correctly
     calculated zero-by-zero box: the value was right and nothing was
     drawn. */
  display: block;
  block-size: 100%;
  inline-size: var(--cs-at, 0%);
  border-radius: var(--r-full);
  background: linear-gradient(90deg, var(--meter-from), var(--meter-to));
  transition: inline-size var(--dur-slow) var(--ease-out);
}
/* The threshold the fill is measured against: the attendance rule, the
   pass mark. Drawn as a line across the track rather than a colour
   change, because the number it marks is the reader's own and the bar
   must not look like it has an opinion about where it should be. */
body.is-calc .cs-fill-goal {
  position: absolute;
  inset-block: -4px;
  inset-inline-start: var(--cs-goal, 100%);
  inline-size: 2px;
  margin-inline-start: -1px;
  border-radius: var(--r-full);
  background: var(--text);
  box-shadow: 0 0 0 2px var(--surface);
  transition: inset-inline-start var(--dur-slow) var(--ease-out);
}

body.is-calc .cs-fill-ok   { background: linear-gradient(90deg, #3fa877, #2f8a5f); }
body.is-calc .cs-fill-warn { background: linear-gradient(90deg, #d8a13c, #b9812a); }
body.is-calc .cs-fill-bad  { background: linear-gradient(90deg, #cf6b62, #ad4c45); }

/* A ring, where the figure is a share of one whole and the page has
   room for it. Conic gradient rather than an SVG so there is no markup
   to keep in step; --cs-at is the one value a script sets. */
body.is-calc .cs-ring {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 128px;
  block-size: 128px;
  margin-inline: auto;
  border-radius: 50%;
  background:
    conic-gradient(var(--accent) calc(var(--cs-at, 0%) * 1), var(--surface-sunk) 0);
  transition: background var(--dur-slow) var(--ease-out);
}
body.is-calc .cs-ring::before {
  content: "";
  position: absolute;
  inset: 11px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--line);
}
body.is-calc .cs-ring-v {
  position: relative;
  font-size: 1.6rem;
  font-weight: 720;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  color: var(--text);
}

/* --------------------------------------------------------------------
   8. EXAMPLE PRESETS

   A chip that fills the form with a worked example. The label is the
   arithmetic itself -- "15% of 80", "40 x 30 x 25 cm" -- which is the
   same string in every language the site publishes, so the component
   needs no translation and cannot ship an English word onto a Russian
   page.

   Every preset on the site is a set of values whose answer is checked
   in the test suite. A chip that filled the form with numbers nobody
   had verified would be worse than no chip.
   ------------------------------------------------------------------ */

body.is-calc .cs-presets {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
  margin-block-end: var(--s4);
}

body.is-calc .cs-presets-k {
  font-size: 0.78rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  color: var(--text-faint);
}

/* The preset rows that predate this component.
   Three calculators grew their own example chips before there was a
   shared one -- the polynomial examples, the shipment presets, the
   attendance thresholds -- and they do exactly what .cs-preset does.
   Matching them on the attribute that makes them presets gives the
   family one look without editing a template or renaming a hook their
   scripts already listen to. */
body.is-calc .chip[data-example],
body.is-calc .chip[data-preset],
body.is-calc .cs-preset {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-block-size: 34px;
  padding: 4px var(--s3);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-full);
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: 0.83rem;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  transition: border-color var(--dur-fast), color var(--dur-fast),
              background-color var(--dur-fast), transform var(--dur-fast);
}
body.is-calc .chip[data-example]:hover,
body.is-calc .chip[data-preset]:hover,
body.is-calc .cs-preset:hover {
  border-style: solid;
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-strong);
  transform: translateY(-1px);
}
body.is-calc .chip[data-example]:active,
body.is-calc .chip[data-preset]:active,
body.is-calc .cs-preset:active { transform: none; }
body.is-calc .chip[data-example]:focus-visible,
body.is-calc .chip[data-preset]:focus-visible,
body.is-calc .cs-preset:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------
   9. INPUTS

   The field is where the work happens, so it gets the clearest live
   state on the page. Values only: every control keeps its type, its
   name, its label and its behaviour.
   ------------------------------------------------------------------ */

body.is-calc .input:focus,
body.is-calc .select:focus,
body.is-calc .textarea:focus {
  box-shadow: 0 0 0 3px var(--accent-soft), 0 1px 2px rgba(13, 17, 22, .06);
}

/* A field that has been answered reads as done without shouting. */
body.is-calc .input:not(:placeholder-shown):not(:focus):not([aria-invalid="true"]) {
  border-color: var(--line-strong);
}

/* An invalid field, and its message. The message slides rather than
   jumping, because a validation line appearing under a control is the
   one place on the page where a jump costs the reader their place. */
body.is-calc .input[aria-invalid="true"],
body.is-calc .select[aria-invalid="true"] {
  box-shadow: 0 0 0 3px rgba(173, 76, 69, .12);
}

body.is-calc .error-msg.is-visible {
  animation: cs-err-in var(--dur) var(--ease-out) both;
}
@keyframes cs-err-in {
  from { opacity: 0; transform: translateY(-3px); }
  to   { opacity: 1; transform: none; }
}

/* A unit sitting inside the field's own row: "100 [kg]". The select
   keeps its label -- visually hidden where the number's label already
   names the quantity -- so the pair is still two labelled controls. */
body.is-calc .cs-unit {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--s2);
  align-items: start;
}
body.is-calc .cs-unit > .select {
  inline-size: auto;
  min-inline-size: 92px;
}

/* A helper tooltip beside a label. Native title text is unreadable on
   a phone, so the explanation is a <details> the reader can open and
   the important part is never ONLY in here. */
body.is-calc .cs-tip {
  display: inline-block;
  margin-inline-start: 6px;
  vertical-align: middle;
}
body.is-calc .cs-tip > summary {
  display: inline-grid;
  place-items: center;
  inline-size: 18px;
  block-size: 18px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--surface-sunk);
  color: var(--text-faint);
  font-size: 0.7rem;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}
body.is-calc .cs-tip > summary::-webkit-details-marker { display: none; }
body.is-calc .cs-tip > summary:hover {
  border-color: var(--accent);
  color: var(--accent);
}
body.is-calc .cs-tip > summary:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}
body.is-calc .cs-tip-body {
  margin-block-start: var(--s2);
  padding: var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
  font-size: 0.84rem;
  font-weight: 400;
  line-height: 1.55;
  color: var(--text-soft);
}

/* --------------------------------------------------------------------
   10. ADVANCED OPTIONS

   Progressive disclosure, so the basic calculator stays three to five
   fields and the optional ones are one tap away rather than in the way.
   The element is the site's own .disclosure; this gives it the shape of
   a panel rather than a row.
   ------------------------------------------------------------------ */

body.is-calc form > .disclosure,
body.is-calc form .cs-adv {
  margin-block: var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--cs-card-r);
  background: var(--surface-sunk);
}

body.is-calc form > .disclosure > summary,
body.is-calc form .cs-adv > summary {
  padding: var(--s3) var(--s4);
  font-size: 0.9rem;
  font-weight: 650;
  color: var(--text-soft);
}
body.is-calc form > .disclosure[open] > summary,
body.is-calc form .cs-adv[open] > summary {
  border-block-end: 1px solid var(--line);
  color: var(--text);
}
body.is-calc form > .disclosure > .disclosure-body,
body.is-calc form .cs-adv > .disclosure-body { padding: var(--s4); }

@keyframes cs-adv-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
body.is-calc form > .disclosure[open] > .disclosure-body,
body.is-calc form .cs-adv[open] > .disclosure-body {
  animation: cs-adv-in var(--dur) var(--ease-out) both;
}

/* --------------------------------------------------------------------
   11. MULTI-ROW ENTRY

   Several cartons, several subjects, several pieces. The generic
   version of the row builders the shipping and grade pages grew their
   own copies of; a row is a grid so the columns line up down the list,
   and its index is drawn rather than written so the component needs no
   word in any language.
   ------------------------------------------------------------------ */

body.is-calc .cs-rows { display: grid; gap: var(--s3); }

body.is-calc .cs-row {
  display: grid;
  gap: var(--s3);
  align-items: end;
  padding: var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--cs-tile-r);
  background: var(--surface);
}

@keyframes cs-row-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
body.is-calc .cs-row.cs-in { animation: cs-row-in var(--dur) var(--ease-out) both; }

body.is-calc .cs-row-n {
  display: grid;
  place-items: center;
  inline-size: 24px;
  block-size: 24px;
  border-radius: var(--r-full);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  font-size: 0.75rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent-strong);
}

body.is-calc .cs-row-sum {
  padding-inline: var(--s2);
  font-family: var(--font-mono);
  font-size: 0.86rem;
  font-weight: 650;
  color: var(--accent-strong);
  white-space: nowrap;
}

/* --------------------------------------------------------------------
   12. COMPARISON

   Two methods, two years, two scenarios, side by side. Only where the
   comparison is a real one: a calculator with a single correct answer
   does not get a second column to argue with itself.
   ------------------------------------------------------------------ */

body.is-calc .cs-compare {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--s3);
  margin-block: var(--s4);
}

body.is-calc .cs-compare-col {
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--cs-card-r);
  background: var(--surface-sunk);
}
body.is-calc .cs-compare-k {
  display: block;
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
body.is-calc .cs-compare-v {
  display: block;
  margin-block-start: 4px;
  font-size: 1.32rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
body.is-calc .cs-compare-sub {
  display: block;
  margin-block-start: 4px;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--text-faint);
}
body.is-calc .cs-compare-col-lead {
  border-color: var(--accent-line);
  background: var(--accent-soft);
}
body.is-calc .cs-compare-col-lead .cs-compare-v { color: var(--accent-strong); }

/* --------------------------------------------------------------------
   13. TABLES INSIDE A CALCULATOR

   A slab table, a grade scale, a breakdown by row. The base table
   styles (section 10) already handle the article; these are for a table
   that is part of the working surface, where the figures matter more
   than the prose and a phone must still be able to read them.
   ------------------------------------------------------------------ */

body.is-calc .result table,
body.is-calc .cs-table {
  inline-size: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

body.is-calc .result table th,
body.is-calc .cs-table th {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
}

body.is-calc .result table td,
body.is-calc .cs-table td { font-size: 0.93rem; }

/* The row the answer fell into. */
body.is-calc .cs-table tr.cs-hit td {
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-weight: 650;
}

/* --------------------------------------------------------------------
   14. ACTION BUTTONS

   Feedback on press, and a copy button that says it copied. Both are
   the site's own buttons; nothing here adds a control, and no control
   on a calculator page does nothing.
   ------------------------------------------------------------------ */

body.is-calc .btn-primary:active { transform: translateY(1px); }

body.is-calc .btn.cs-done {
  border-color: var(--ok-line);
  background: var(--ok-bg);
  color: var(--ok-fg);
}

/* --------------------------------------------------------------------
   15. NARROW SCREENS

   320, 375 and 768 are the widths this is checked at. The layout
   reflows rather than shrinking: cards go to one column, the answer
   keeps its weight, nothing scrolls sideways.
   ------------------------------------------------------------------ */

@media (max-width: 600px) {
  body.is-calc .cs-modes,
  body.is-calc .cs-modes-2 { grid-template-columns: 1fr; gap: var(--s2); }

  body.is-calc .cs-modes > label,
  body.is-calc .cs-modes > [role="radio"] { min-block-size: 56px; padding: var(--s3); }
  body.is-calc .cs-mode-ic { inline-size: 34px; block-size: 34px; }
  body.is-calc .cs-mode-ic svg { inline-size: 17px; block-size: 17px; }

  body.is-calc .cs-flow { padding: var(--s3); gap: 6px; }
  body.is-calc .cs-flow-step { padding: var(--s2) var(--s3); }
  body.is-calc .cs-flow-v { font-size: 0.88rem; }

  body.is-calc .stats { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: var(--s2); }
  body.is-calc .stat { padding: var(--s3); padding-inline-start: calc(var(--s3) + 3px); }
  body.is-calc .stat-value { font-size: 1.22rem; }

  body.is-calc .result-primary { padding-block: var(--s5) var(--s4); }
  body.is-calc .step-list { padding: var(--s3); }
  body.is-calc .step-list > li { padding-inline-start: var(--s5); font-size: 0.91rem; }

  body.is-calc .cs-ring { inline-size: 108px; block-size: 108px; }
  body.is-calc .cs-ring-v { font-size: 1.35rem; }
}

/* The narrowest supported phone. The mode hint is the first thing to
   go: at this width the label alone is the useful part, and three
   wrapped lines of explanation push the fields off the screen. */
@media (max-width: 379px) {
  body.is-calc .cs-mode-sub { display: none; }
  body.is-calc .cs-presets-k { flex-basis: 100%; }
  body.is-calc .cs-meter-scale { font-size: 0.66rem; }
}

/* A calculator that has earned a second column gets one, and only
   where the page asked for it: .cs-split is opt-in per template,
   because which calculators read better side by side is a judgement
   about the calculator and not about the width of the screen. */
@media (min-width: 900px) {
  body.is-calc .cs-split {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: var(--s6);
    align-items: start;
  }
  body.is-calc .cs-split > .cs-split-out { position: sticky; inset-block-start: var(--s5); }
}

/* --------------------------------------------------------------------
   16. RIGHT-TO-LEFT

   The layout is written in logical properties throughout, so Arabic
   needs almost nothing here. What it does need is the two places where
   a glyph or a number has a direction of its own: the flow chevron
   points the other way, and an arithmetic expression stays left to
   right inside an otherwise right-to-left line.
   ------------------------------------------------------------------ */

[dir="rtl"] body.is-calc .cs-flow-arrow svg { transform: scaleX(-1); }

[dir="rtl"] body.is-calc .cs-work-f,
[dir="rtl"] body.is-calc .cs-flow-v,
[dir="rtl"] body.is-calc .cs-preset,
[dir="rtl"] body.is-calc .cs-row-sum {
  direction: ltr;
  text-align: start;
}

/* A drawing is a drawing: mirroring it would move the dimension
   labels off the edges they measure. Numbers inside one stay LTR. */
[dir="rtl"] body.is-calc .cs-diagram > svg { direction: ltr; }

/* --------------------------------------------------------------------
   17. PRINT

   A printed calculation is a record of an answer: the answer, its
   breakdown and its working, without the furniture that only makes
   sense on a screen.
   ------------------------------------------------------------------ */

@media print {
  body.is-calc .cs-presets,
  body.is-calc .cs-tip { display: none; }

  body.is-calc .result,
  body.is-calc .stat,
  body.is-calc .step-list,
  body.is-calc .cs-work {
    border-color: #bbb;
    background: #fff;
    box-shadow: none;
  }
  body.is-calc .result-value { color: #000; }
  body.is-calc .cs-modes > label { box-shadow: none; }
  body.is-calc .cs-modes > input:checked + label { border-color: #666; }
}

/* --------------------------------------------------------------------
   18. REDUCED MOTION

   Every animation in this file is cancelled here, and every transition
   with it. A visitor who has asked for less motion still gets the
   selected mode card, the filled meter and the revealed result -- they
   simply get them immediately.
   ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  body.is-calc .result.cs-in,
  body.is-calc .result.cs-in .result-value,
  body.is-calc .error-msg.is-visible,
  body.is-calc form > .disclosure[open] > .disclosure-body,
  body.is-calc form .cs-adv[open] > .disclosure-body,
  body.is-calc .cs-row.cs-in {
    animation: none;
  }

  body.is-calc .cs-modes > label,
  body.is-calc .cs-modes > label::after,
  body.is-calc .cs-modes > [role="radio"],
  body.is-calc .cs-modes > [role="radio"]::after,
  body.is-calc .cs-mode-ic,
  body.is-calc .chip[data-example],
  body.is-calc .chip[data-preset],
  body.is-calc .cs-preset,
  body.is-calc .stat,
  body.is-calc .cs-meter-marker,
  body.is-calc .cs-fill,
  body.is-calc .cs-ring,
  body.is-calc .input,
  body.is-calc .select,
  body.is-calc .textarea {
    transition: none;
  }

  /* !important because the resting rules these cancel are no less
     specific than this block, and because tests/motioncheck.php reads
     the flag as the proof that a hover transform is genuinely
     reachable by someone who asked for less movement. */
  body.is-calc .cs-modes > label:hover,
  body.is-calc .cs-modes > [role="radio"]:hover,
  body.is-calc .chip[data-example]:hover,
  body.is-calc .chip[data-preset]:hover,
  body.is-calc .cs-preset:hover,
  body.is-calc .cs-preset:active,
  body.is-calc .btn-primary:active { transform: none !important; }
}
