/* Kaamko shared utility layer. Lines separate real controls and data groups. */
.page-tools .twrap--prose {
  width: min(1020px, 100% - 2rem);
}

.tbar__wordmark b {
  letter-spacing: -.035em;
}

.tbar__wordmark span {
  color: var(--ice-color-text-muted);
  font-size: .62rem;
  font-weight: 750;
  letter-spacing: .035em;
}

.page-tools .tool-panel,
.page-tools .tool-unitgroup,
.page-tools .tool-scroll,
.page-tools .tool-copybar,
.page-tools .tool-mode-note,
.page-tools .tool-preeti-preview {
  border-color: var(--ice-color-on-surface);
}

.page-tools .tool-panel__head {
  border-bottom: 2px solid var(--ice-color-on-surface);
}

.page-tools .tool-panel__body:has(> form + .tool-result) {
  display: grid;
  grid-template-columns: minmax(250px, .82fr) minmax(0, 1.18fr);
  padding: 0;
}

.page-tools .tool-panel__body:has(> form + .tool-result) > form {
  min-width: 0;
  padding: .85rem;
  border-right: 2px solid var(--ice-color-on-surface);
  background: var(--ice-color-surface-muted);
}

.page-tools .tool-panel__body:has(> form + .tool-result) > .tool-result {
  min-width: 0;
  margin: 0;
  padding: .85rem;
  border-top: 0;
}

.page-tools .tool-panel__body:has(> form + .tool-result) > .tool-note {
  grid-column: 1 / -1;
  margin: 0;
  border-top: 2px solid var(--ice-color-on-surface);
  border-right: 0;
  border-bottom: 0;
  border-left: 0;
  border-radius: 0;
}

/* A tool whose provenance line has to survive the loading state keeps it as a
   sibling of the form rather than inside the result. Without this it takes the
   first grid cell, pushing the form into the result's column and the result
   into a half-width one. Provenance nested inside .tool-result is unaffected. */
.page-tools .tool-panel__body:has(> form + .tool-result) > .tool-provenance {
  grid-column: 1 / -1;
  margin: 0;
  padding: .85rem;
  border-top: 0;
  border-bottom: 2px solid var(--ice-color-on-surface);
}

/* Interchangeable converters are one compound control, so their input row
   keeps the full panel width and the complete result grid follows below. */
.page-tools .tool-panel__body:has(> form .tool-converter) {
  grid-template-columns: 1fr;
}

.page-tools .tool-panel__body:has(> form .tool-converter) > form {
  border-right: 0;
  border-bottom: 2px solid var(--ice-color-on-surface);
}

/* A long amortisation schedule needs the panel width. Keeping it beside the
   loan form makes every currency column wrap and leaves no stable scroll head. */
.page-tools .tool-panel__body:has(#schedule) {
  grid-template-columns: 1fr;
}

.page-tools .tool-panel__body:has(#schedule) > form {
  border-right: 0;
  border-bottom: 2px solid var(--ice-color-on-surface);
}

/* Preeti modes are three distinct tools. The active cell must read as state,
   not as a slightly different label inside a pale container. */
.page-tools .tool-panel__head:has(.tool-modes--three) {
  display: grid;
  grid-template-columns: minmax(180px, .48fr) minmax(0, 1.52fr);
  align-items: stretch;
  padding: 0;
}

.page-tools .tool-panel__head:has(.tool-modes--three) .tool-panel__title {
  display: flex;
  align-items: center;
  padding: .7rem .85rem;
  border-right: 2px solid var(--ice-color-on-surface);
}

.page-tools .tool-modes--three {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  width: 100%;
  gap: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--ice-color-surface);
}

.page-tools .tool-modes--three button {
  min-width: 0;
  min-height: 56px;
  padding: .55rem .65rem;
  border-left: 2px solid var(--ice-color-on-surface);
  border-radius: 0;
  background: var(--ice-color-surface);
  color: var(--ice-color-on-surface-muted);
  line-height: 1.25;
}

.page-tools .tool-modes--three button:first-child {
  border-left: 0;
}

.page-tools .tool-modes--three button:hover:not([aria-pressed='true']) {
  background: var(--ice-color-surface-muted);
  color: var(--ice-color-on-surface);
}

.page-tools .tool-modes--three button[aria-pressed='true'] {
  background: var(--ice-color-on-surface);
  color: var(--ice-color-surface);
  box-shadow: inset 0 -4px 0 var(--ice-color-text-action);
}
.page-tools .tool-fieldset {
  padding: .7rem;
  border: 2px solid var(--ice-color-border-strong);
  background: var(--ice-color-surface);
}

.page-tools .tool-fieldset + .tool-fieldset {
  margin-top: .65rem;
}

.page-tools .tool-fieldset > legend {
  width: auto;
  padding: 0 .35rem;
  color: var(--ice-color-on-surface);
  background: var(--ice-color-surface);
  font-size: .7rem;
  font-weight: 800;
}

.page-tools .tool-headline {
  font-size: clamp(1.35rem, 1.2rem + .75vw, 1.8rem);
}

.page-tools .tool-headline__sub {
  margin-top: .35rem;
  font-size: .78rem;
  line-height: 1.4;
}

/* ── Cheque lines (rupees in words) ───────────────────────────────── */

/* Two amount lines, English and Nepali, each with its own copy control. The
   button sits beside its line rather than under both, so it is unambiguous
   which wording is being taken to the cheque. */
.page-tools .words-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--ice-space-4);
}

.page-tools .words-line + .words-line {
  margin-top: .6rem;
  padding-top: .6rem;
  border-top: 2px solid var(--ice-color-on-surface);
}

/* Two headlines stacked need less scale than one did on its own. */
.page-tools .words-line .tool-headline {
  font-size: clamp(1.05rem, .95rem + .5vw, 1.35rem);
  line-height: 1.35;
}

/* Devanagari sits lower and needs a touch more room than Latin at the same
   nominal size, or the matras collide with the line above. */
.page-tools .tool-headline--np {
  line-height: 1.55;
}

.page-tools .words-copy {
  align-self: center;
  padding: .38rem .6rem;
  font-size: .72rem;
  white-space: nowrap;
}

@media (max-width: 620px) {
  .page-tools .words-line {
    grid-template-columns: 1fr;
    gap: .45rem;
  }

  .page-tools .words-copy { justify-self: start; }
}

.page-tools .tool-units {
  gap: 0;
  border-top: 2px solid var(--ice-color-on-surface);
  border-left: 2px solid var(--ice-color-on-surface);
}

.page-tools .tool-unitgroup {
  padding: .65rem;
  border-width: 0 2px 2px 0;
  border-radius: 0;
}

.page-tools .tool-unitgroup h3 {
  margin-bottom: .4rem;
}

.page-tools .tool-readout th,
.page-tools .tool-readout td {
  padding-block: .46rem;
  border-bottom: 2px solid var(--ice-color-border-strong);
  font-size: .82rem;
}

.page-tools .tool-readout td {
  border-left: 2px solid var(--ice-color-border-strong);
  padding-left: .55rem;
}

.page-tools .tool-readout tr:last-child th,
.page-tools .tool-readout tr:last-child td {
  border-bottom: 0;
}

.page-tools .tool-scroll {
  border-width: 2px;
  border-radius: 0;
}

/* EMI result and schedule */
.page-tools #emi-form + .tool-result .tool-unitgroup {
  display: grid;
  grid-template-rows: auto 1fr;
}

.page-tools #emi-form + .tool-result .tool-unitgroup h3 {
  min-height: 2.35em;
}

.page-tools #emi-form + .tool-result .tool-unitgroup .tool-readout td,
.page-tools #schedule th,
.page-tools #schedule td {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.page-tools #schedule {
  max-height: 380px;
  overflow: auto;
  border-color: var(--ice-color-on-surface);
  background: var(--ice-color-surface);
  scrollbar-gutter: stable;
}

.page-tools #schedule .tool-readout {
  width: 100%;
  min-width: 680px;
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
}

.page-tools #schedule thead th {
  position: sticky;
  z-index: 3;
  top: 0;
  height: 42px;
  padding: .6rem .75rem;
  border-bottom: 2px solid var(--ice-color-on-surface);
  background: var(--ice-color-surface-muted);
  box-shadow: 0 2px 0 var(--ice-color-on-surface);
}

.page-tools #schedule thead th:first-child {
  width: 72px;
}

.page-tools #schedule tbody th,
.page-tools #schedule tbody td {
  padding: .52rem .75rem;
}

.page-tools #schedule tbody tr:nth-child(even) {
  background: color-mix(in srgb, var(--ice-color-surface-muted) 58%, transparent);
}

.page-tools #schedule tbody tr:hover {
  background: var(--ice-color-surface-muted);
}

/* Unit results are one conversion matrix, not two unrelated half-tables. */
.page-tools .unit-matrix {
  display: block;
  margin-top: 0;
}

.page-tools .unit-matrix caption {
  display: block;
  width: 100%;
  padding: .65rem .75rem;
  border: 2px solid var(--ice-color-on-surface);
  border-bottom: 0;
  background: var(--ice-color-surface-muted);
  color: var(--ice-color-on-surface-muted);
}

.page-tools .unit-matrix tbody {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  border-top: 2px solid var(--ice-color-on-surface);
  border-left: 2px solid var(--ice-color-on-surface);
}

.page-tools .unit-matrix tr {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(118px, .58fr);
  align-items: stretch;
  border-right: 2px solid var(--ice-color-on-surface);
  border-bottom: 2px solid var(--ice-color-on-surface);
  background: var(--ice-color-surface);
}

.page-tools .unit-matrix th,
.page-tools .unit-matrix td {
  display: flex;
  align-items: center;
  min-width: 0;
  width: auto;
  min-height: 46px;
  padding: .58rem .75rem;
  border-bottom: 0;
}

.page-tools .unit-matrix th {
  color: var(--ice-color-on-surface-muted);
  font-weight: 650;
}

.page-tools .unit-matrix td {
  justify-content: flex-end;
  border-left: 2px solid var(--ice-color-on-surface);
  background: color-mix(in srgb, var(--ice-color-surface-muted) 56%, transparent);
  font-weight: 800;
  white-space: nowrap;
}

.page-tools .unit-matrix + .tool-actions {
  display: flex;
  align-items: center;
  min-height: 58px;
  margin-top: 0;
  padding: .55rem .65rem;
  border: 2px solid var(--ice-color-on-surface);
  border-top: 0;
  background: var(--ice-color-surface-muted);
}

.page-tools .unit-matrix + .tool-actions .tool-status {
  margin: 0 0 0 auto;
  font-size: .78rem;
}

/* Explanatory copy becomes a compact editorial grid instead of a long column. */
.page-tools .tool-explainer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  padding-block: 1.4rem .7rem;
}

.page-tools .tool-explainer > * {
  min-width: 0;
  margin: 0 !important;
  padding: .8rem;
  border-right: 2px solid var(--ice-color-on-surface);
  border-bottom: 2px solid var(--ice-color-on-surface);
}

.page-tools .tool-explainer > :first-child {
  border-top: 2px solid var(--ice-color-on-surface);
}

.page-tools .tool-explainer > h2 {
  grid-column: 1 / -1;
  border-left: 2px solid var(--ice-color-on-surface);
  background: var(--ice-color-surface);
  font-size: clamp(1.2rem, 1.05rem + .65vw, 1.55rem);
}

.page-tools .tool-explainer > :nth-child(even) {
  border-left: 2px solid var(--ice-color-on-surface);
}

.page-tools .tool-explainer > h3 {
  color: var(--ice-color-on-surface-muted);
  background: var(--ice-color-surface-muted);
  font-size: .82rem;
  line-height: 1.35;
}

/* A topic heading and its answer must never be split into unrelated columns. */
.page-tools .tool-explainer > h3,
.page-tools .tool-explainer > h3 ~ *,
.page-tools .tool-explainer > h2 + p:has(+ h3) {
  grid-column: 1 / -1;
  border-left: 2px solid var(--ice-color-on-surface);
}
.page-tools .tool-explainer > p,
.page-tools .tool-explainer > ul,
.page-tools .tool-explainer > ol {
  font-size: .82rem;
  line-height: 1.5;
}

.page-tools .tool-explainer > .tool-facts {
  max-width: none;
  font-size: .84rem;
  line-height: 1.35;
  letter-spacing: 0;
}

.page-tools .tool-related {
  padding-block: .7rem 1.5rem;
  border-top: 2px solid var(--ice-color-on-canvas);
}

.page-tools .tool-related h2 {
  margin-bottom: .55rem;
}

.calendar-selected,
.calendar-facts,
.calendar-copy {
  padding: .72rem .8rem;
}

.calendar-selected strong {
  margin-top: .3rem;
  font-size: 1.02rem;
}

.calendar-selected p {
  margin-top: .25rem;
  font-size: .72rem;
}

.calendar-facts {
  align-content: center;
  gap: .5rem;
  background: var(--ice-color-surface-muted);
}

.page-tools .calendar-facts > div {
  align-items: center;
  min-height: 42px;
  padding: .5rem .58rem;
  border: 2px solid var(--ice-color-on-surface);
  background: var(--ice-color-surface);
}

/* The leading calendar is a mode, not a preference hint. Match the converter
   tabs so the active system is obvious before the user reads the month. */
.page-tools .calendar-controls .tool-modes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  padding: 0;
  border: 2px solid var(--ice-color-on-surface);
  border-radius: 3px;
  overflow: hidden;
  background: var(--ice-color-surface);
}

.page-tools .calendar-controls .tool-modes button {
  min-width: 74px;
  border-left: 2px solid var(--ice-color-on-surface);
  border-radius: 0;
  background: var(--ice-color-surface);
  color: var(--ice-color-on-surface-muted);
}

.page-tools .calendar-controls .tool-modes button:first-child {
  border-left: 0;
}

/* Every segmented tool switch uses the same unmistakable selected state.
   aria-pressed is updated by each tool, so the dark marker follows the
   user's current mode without adding page-specific classes. */
.page-tools .tool-modes button[aria-pressed='true'] {
  background: var(--ice-color-on-surface);
  color: var(--ice-color-surface);
  box-shadow: inset 0 -4px 0 var(--ice-color-text-action);
}

.calendar-copy output {
  min-height: 1.5em;
}

/* Today is a quiet filled state, in green. Selection remains a separate dark
   focus treatment for any other day, and the weekend columns keep the accent:
   red on this grid means a day off, so today cannot also be red. */
.page-tools .calendar-grid td.is-today,
.page-tools .calendar-grid td.is-today .calendar-day,
.page-tools .calendar-grid td.is-today .calendar-day[aria-pressed='true'],
.page-tools .calendar-grid td.is-today .calendar-day:hover {
  background-color: color-mix(in srgb, var(--ice-color-text-today) 20%, var(--ice-color-surface));
  box-shadow: none;
}

/*
 * The fill alone was not enough and the owner said so: at 14% over a dark card
 * it is a 1.3:1 step, which is a tint you find once you know where to look
 * rather than a mark that finds you. This grid draws SELECTION as the ring, so
 * today cannot have one without the two states colliding again. A solid bar on
 * the foot of the cell is the mark instead — full strength green, no contrast
 * ceiling, and it survives at 390px where the badge is hidden.
 */
.page-tools .calendar-grid td.is-today .calendar-day,
.page-tools .calendar-grid td.is-today .calendar-day:hover,
.page-tools .calendar-grid td.is-today .calendar-day[aria-pressed='true'] {
  background-image: linear-gradient(to top, var(--ice-color-text-today) 4px, transparent 4px);
}

/* A filled chip, not bare words. This rule used to clear the badge back to
   transparent text, which left it legible only because it happened to sit over
   the green bar below it — move the bar and the label disappears into the
   tint. Stating the fill and its ink makes it hold on its own. */
.page-tools .calendar-grid td.is-today .calendar-day::after {
  padding: .12rem .3rem;
  border: 0;
  background: var(--ice-color-text-today);
  color: var(--ice-color-surface);
}

/* Keep selected facts compact, then give every copy format the full width. */
.page-tools .calendar-inspector {
  grid-template-columns: minmax(0, 1.2fr) minmax(230px, .8fr);
}

.page-tools .calendar-copy {
  display: block;
  grid-column: 1 / -1;
  padding: .72rem;
  border-top: 2px solid var(--ice-color-on-surface);
  background: var(--ice-color-surface-muted);
}

/* The section marker is the 5px keyline and the 2px box, not the wash behind
   the words. A 16% tint fading out over 72% of the width had neither enough
   colour to read as a highlight nor enough restraint to read as paper — in
   dark mode it landed as a smudge across the heading. The gradient now stops
   at 40% and starts strong enough to be a deliberate mark. */
.calendar-copy__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  margin-bottom: .65rem;
  padding: .55rem .7rem .55rem .85rem;
  border: 2px solid var(--ice-color-on-surface);
  background-color: color-mix(in srgb, var(--ice-color-on-surface) 12%, var(--ice-color-surface));
  background-image: linear-gradient(
    90deg,
    color-mix(in srgb, var(--ice-color-text-action) 30%, var(--ice-color-surface)) 0%,
    transparent 40%
  );
  box-shadow: inset 5px 0 0 var(--ice-color-text-action);
}

.calendar-copy__head span {
  color: var(--ice-color-on-surface-muted);
  font-size: .68rem;
  font-weight: 850;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.calendar-copy__head small {
  color: var(--ice-color-text-muted);
  font-size: .68rem;
}

.calendar-copy-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: .58rem;
}

.calendar-copy-option {
  min-width: 0;
  min-height: 82px;
  padding: 0;
  border: 2px solid var(--ice-color-on-surface);
  border-radius: 3px;
  background: var(--ice-color-surface);
  color: var(--ice-color-on-surface);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: transform 120ms ease, background-color 120ms ease, box-shadow 120ms ease;
}

/* A card's label is structure, so it gets the muted surface and the 2px rule
   the rest of this grid uses. It was a 7% crimson tint, which is below the
   threshold where a colour reads as chosen: on the dark theme eight of these
   strips looked like a dirty wash rather than eight captions. Crimson still
   appears on this card, on the one state that means something — the underline
   that says which format was copied. */
.calendar-copy-option > span {
  display: block;
  min-height: 34px;
  padding: .48rem .58rem;
  border-bottom: 2px solid var(--ice-color-on-surface);
  background: color-mix(in srgb, var(--ice-color-on-surface) 12%, var(--ice-color-surface));
  color: var(--ice-color-on-surface-muted);
  font-size: .64rem;
  font-weight: 800;
  letter-spacing: .035em;
  text-transform: uppercase;
}

.calendar-copy-option output {
  display: block;
  min-height: 0;
  padding: .58rem .62rem .65rem;
  color: var(--ice-color-on-surface);
  font-size: .72rem;
  font-weight: 700;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

/* Hover and focus are a lift, not a tint. The same 8% crimson that made the
   resting labels look washed made a hovered card look barely different from
   an unhovered one, which is the wrong end to be subtle at. */
.calendar-copy-option:hover,
.calendar-copy-option:focus-visible {
  background: var(--ice-color-surface-field);
}

.calendar-copy-option[data-copy-state='copied'] {
  background: color-mix(in srgb, var(--ice-color-text-action) 14%, var(--ice-color-surface));
}

.calendar-copy-option:hover {
  transform: translateY(-2px);
  box-shadow: 3px 3px 0 color-mix(in srgb, var(--ice-color-on-surface) 20%, transparent);
}

.calendar-copy-option:active {
  transform: translateY(1px);
  box-shadow: none;
}

.calendar-copy-option:focus-visible {
  outline: 3px solid var(--ice-color-text-action);
  outline-offset: -3px;
}

.calendar-copy-option[data-copy-state='copied'] {
  box-shadow: inset 0 -4px 0 var(--ice-color-text-action);
}

.page-tools .calendar-copy > .tool-status {
  min-height: 0;
  margin: .5rem 0 0;
  padding: 0 .1rem;
  font-size: .7rem;
}

.page-tools .tool-fields,
.page-tools .tool-textpair {
  gap: 0;
  border-top: 2px solid var(--ice-color-on-surface);
  border-left: 2px solid var(--ice-color-on-surface);
}

.page-tools .tool-fields > .tool-field,
.page-tools .tool-textpair > .tool-field {
  padding: .58rem;
  border-right: 2px solid var(--ice-color-on-surface);
  border-bottom: 2px solid var(--ice-color-on-surface);
  background: var(--ice-color-surface);
}

.page-tools .tool-textpair textarea {
  min-height: 180px;
}
/* Copy bars live inside narrow form columns on split result panels. Keep the
   preview on its own row so no result can collapse into vertical letters. */
.page-tools .tool-copybar {
  grid-template-columns: minmax(0, 1fr) auto;
  gap: .5rem;
  margin-top: .75rem;
  padding: .7rem;
}

.page-tools .tool-copybar label {
  grid-column: 1 / -1;
}

.page-tools .tool-copybar select {
  grid-column: 1;
  grid-row: 2;
  min-width: 0;
}

.page-tools .tool-copybar .tool-action {
  grid-column: 2;
  grid-row: 2;
}

.page-tools .tool-copybar output {
  grid-column: 1 / -1;
  grid-row: 3;
  width: 100%;
  min-width: 0;
  min-height: 2.2rem;
  padding: .45rem .5rem;
  border: 2px solid var(--ice-color-border-strong);
  background: var(--ice-color-surface);
  overflow-wrap: anywhere;
}
/* Result values announce their copy behavior only when approached. */
.tool-quickcopy {
  position: relative;
  cursor: copy;
  outline: 0;
  transition: background-color .12s ease, box-shadow .12s ease;
}

.tool-readout td.tool-quickcopy {
  padding-right: 3rem;
}

.tool-quickcopy::after {
  content: 'Copy';
  position: absolute;
  top: .25rem;
  right: .25rem;
  padding: .17rem .28rem;
  border: 1px solid currentColor;
  background: var(--ice-color-surface);
  color: var(--ice-color-text-action);
  font: 800 .56rem/1 var(--ice-font-primary);
  letter-spacing: .045em;
  text-transform: uppercase;
  opacity: 0;
  pointer-events: none;
}

.tool-quickcopy:hover,
.tool-quickcopy:focus-visible {
  background: color-mix(in srgb, var(--ice-color-text-action) 8%, var(--ice-color-surface));
  box-shadow: inset 0 0 0 2px var(--ice-color-text-action);
}

.tool-quickcopy:hover::after,
.tool-quickcopy:focus-visible::after,
.tool-quickcopy[data-copy-state='copied']::after {
  opacity: 1;
}

.tool-quickcopy[data-copy-state='copied']::after {
  content: 'Copied';
  color: var(--ice-color-on-action);
  border-color: var(--ice-color-action);
  background: var(--ice-color-action);
}

.tool-copy-toast {
  position: fixed;
  right: .75rem;
  bottom: .75rem;
  z-index: 20;
  padding: .6rem .75rem;
  border: 2px solid var(--ice-color-on-surface);
  background: var(--ice-color-surface);
  color: var(--ice-color-on-surface);
  font-size: .75rem;
  font-weight: 800;
  opacity: 0;
  transform: translateY(.3rem);
  pointer-events: none;
  transition: opacity .12s ease, transform .12s ease;
}

.tool-copy-toast[data-visible='true'] {
  opacity: 1;
  transform: translateY(0);
}

@media (max-width: 760px) {
  .page-tools .tool-panel__body:has(> form + .tool-result) {
    grid-template-columns: 1fr;
  }

  .page-tools .tool-panel__body:has(> form + .tool-result) > form {
    padding: .7rem;
    border-right: 0;
    border-bottom: 2px solid var(--ice-color-on-surface);
  }

  .page-tools .tool-panel__body:has(> form + .tool-result) > .tool-result {
    padding: .7rem;
  }

  .page-tools .tool-panel__head:has(.tool-modes--three) {
    grid-template-columns: 1fr;
  }

  .page-tools .tool-panel__head:has(.tool-modes--three) .tool-panel__title {
    min-height: 42px;
    padding: .55rem .7rem;
    border-right: 0;
    border-bottom: 2px solid var(--ice-color-on-surface);
  }

  .page-tools .tool-modes--three {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .page-tools .tool-modes--three button {
    min-height: 54px;
    padding: .45rem .35rem;
    font-size: .72rem;
  }

  .page-tools .tool-explainer {
    grid-template-columns: 1fr;
    padding-top: .9rem;
  }

  .page-tools .tool-explainer > * {
    grid-column: 1;
    border-left: 2px solid var(--ice-color-on-surface);
    padding: .68rem;
  }

  .page-tools .unit-matrix tbody {
    grid-template-columns: 1fr;
  }

  .page-tools .unit-matrix tr {
    grid-template-columns: minmax(0, 1fr) minmax(105px, .65fr);
  }

  .page-tools .calendar-inspector {
    grid-template-columns: 1fr;
  }

  .calendar-copy-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .calendar-selected,
  .calendar-facts,
  .calendar-copy {
    padding: .62rem .7rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tool-quickcopy,
  .tool-copy-toast {
    transition: none;
  }
}

/* ── Wave 1 tools: share, age, GPA, rebar ─────────────────────────── */

/* A component that sets its own `display` outranks the `hidden` attribute, so
   `node.hidden = true` leaves it on screen and every test still passes. That
   trap has now shipped here four separate times (the /apply stepper, the fee
   result actions, six instances on /staff, and .tool-units below), each fixed
   one selector at a time. This closes the class for the whole section: any
   element the tools mark hidden is hidden, whatever else styles it. */
.page-tools [hidden] { display: none !important; }

/* Repeated buy rows on the share calculator, and course rows on the GPA
   calculator. Both are the same shape — a short numeric pair that has to stay
   legible in the panel's narrow left column — so they share a rule. */
.page-tools .share-lot,
.page-tools .gpa-course {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: .5rem;
}

.page-tools .share-lot + .share-lot,
.page-tools .gpa-course + .gpa-course {
  margin-top: .5rem;
  padding-top: .5rem;
  border-top: 2px solid var(--ice-color-border-strong);
}

/* The subject grid is single-column in the narrow form column and doubles up
   as soon as the panel stacks, where there is width to spare. */
.page-tools .gpa-rows {
  display: grid;
  gap: .5rem;
}

@media (min-width: 620px) {
  .page-tools .gpa-rows:not(.gpa-rows--credit) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* The rebar schedule is an input table: eight diameters against two numeric
   columns. Cells carry the same field styling as a standalone control so the
   table does not read as a different kind of form. */
.page-tools .rebar-input-table th,
.page-tools .rebar-input-table td {
  padding: .35rem .4rem;
  vertical-align: middle;
}

.page-tools .rebar-input-table input {
  width: 100%;
  min-width: 0;
  padding: .45rem .5rem;
  font: inherit;
  font-size: .95rem;
  font-variant-numeric: tabular-nums;
  color: var(--ice-color-on-surface-field);
  background: var(--ice-color-surface-field);
  border: 2px solid var(--ice-color-border-strong);
  border-radius: var(--ice-radius-control);
}

.page-tools .rebar-input-table input:focus-visible {
  outline: 2px solid var(--ice-color-text-action);
  outline-offset: 2px;
}

/* .tool-scroll caps at 340px, which is right for a result someone scrolls and
   wrong for a form: it cut the 20, 25 and 32 mm rows off mid-table, so three
   diameters could only be reached by scrolling inside a fieldset that gave no
   sign there was more. Inputs are never hidden. */
.page-tools .tool-scroll--full {
  max-height: none;
  overflow: visible;
}

/* Eight rows of inputs plus a six-column result table need the panel width,
   the same argument the amortisation schedule is already given above. */
.page-tools .tool-panel__body:has(#rebar-form) {
  grid-template-columns: 1fr;
}

.page-tools .tool-panel__body:has(#rebar-form) > form {
  border-right: 0;
  border-bottom: 2px solid var(--ice-color-on-surface);
}

/* Drawn marks reuse the sprite's box so the nav and hub size them identically,
   but must not also paint the sprite behind themselves. */
.tool-pictogram--drawn {
  background-image: none;
  overflow: visible;
}

/* ── The bar stopped listing every tool ───────────────────────────── */

/* Three shapes in three weeks, and the third is the one that scales.
 *
 * One row held ten tools. Wrapping to two held seventeen, bought out of link
 * height. Twenty-four needed a third row and landed 2px inside the 120px
 * ceiling the visual contract pins — which is to say the flat list had run out
 * of road, with a hundred candidates still in `docs/17` and a PDF wave asked
 * for on top.
 *
 * The bar is now two tiers: the five groups, then the tools inside the group
 * the current page belongs to. It is *shorter* than the flat two-row version
 * was, and — the part that matters — its height no longer moves when a tool is
 * added, only when a group is. Nothing hides behind a toggle: both tiers are
 * plain links, and the hub is one click away from every page.
 *
 * No wrap rule any more. Each tier is at most seven links, so it fits one
 * desktop line at every width in the contract; below 981px both tiers scroll
 * sideways exactly as the single row used to. */
@media (min-width: 981px) {
  .tbar__nav { overflow-x: visible; }
}

/* ── Live-feed tools: fuel and Kalimati ───────────────────────────── */

/* A remove control inside a table row. It has to stay a real 44px target
   without making every basket row twice as tall as a rates row. */
.page-tools .tool-action--inline {
  min-height: 44px;
  padding: .3rem .6rem;
  font-size: .78rem;
  white-space: nowrap;
}

/* The rates list is long by nature — 103 commodities — so it keeps the shared
   scroll ceiling rather than pushing the basket off the screen. */
.page-tools .kalimati-rates {
  max-height: 320px;
  margin-top: .6rem;
}

/* Both live-feed pages put a search or a rate column switch above a long
   table; the three-way rate switch reads as one control, not three buttons. */
.page-tools .kalimati-modes button { min-width: 5.5rem; }

/* A segmented switch is state, not decoration, and the shared colour fade means
   the selected marker is still arriving after the click returns. For anyone who
   asked for less motion the state should simply land. (This does not help the
   test suite — Playwright's reducedMotion setting does not reach the page here,
   which the visual contract now handles on its own side.) */
@media (prefers-reduced-motion: reduce) {
  .page-tools .tool-modes button {
    transition: none;
  }
}

/* An empty-state or "no match" row spans the table, so it is a sentence rather
   than a value: the shared right-alignment for numeric cells strands it against
   the far edge. */
.page-tools .tool-readout td[colspan] {
  text-align: left;
}

/* .tool-units is a two-column grid, so a group on its own takes half the panel
   and leaves the other half empty — which is how the Kalimati rates table ended
   up narrower after being moved out of the pair to give it more room. A lone
   group spans. */
.page-tools .tool-units:has(> .tool-unitgroup:only-child) {
  grid-template-columns: 1fr;
}

/* The trend sparkline is drawn by our own code into an inline SVG — this repo
   does not add a chart library for one line, and the brand inks do not work as
   chart marks (see the dashboard palette note). One line, one baseline, no
   axes: it is a shape, and the numbers beside it carry the reading. */
.page-tools .kalimati-spark {
  margin: .6rem 0 .8rem;
  border: 2px solid var(--ice-color-border-strong);
  background: var(--ice-color-surface-field);
}

.page-tools .kalimati-spark svg {
  display: block;
  width: 100%;
  height: 72px;
}

.page-tools .tool-headline--compact {
  font-size: clamp(1.1rem, 1rem + .5vw, 1.35rem);
  margin-top: .2rem;
}

/* A sticky header with `z-index: auto` is painted in DOM order, so the rows
   that scroll under it paint OVER it — the Kalimati rates table showed its
   own prices sitting on top of "MIN (RS) AVG (RS) MAX (RS)" in production.
   The EMI schedule already carried `z-index: 3` as a one-page fix; every other
   scrollable table in the section had the defect and nothing asserted it. */
.page-tools .tool-scroll thead th {
  z-index: 3;
}

/* Rates and their day-on-day move are amounts, not prose: breaking
   "Rs 3,04,100" across two lines in a narrow column makes a table of numbers
   read as a paragraph. */
.page-tools [data-role="rate-table"] td {
  white-space: nowrap;
}

/* ── The anchor grid on /tools/write-on-pdf ───────────────────────── */

/* A PDF measures from the bottom-left corner and every document is a different
   size, so position is one of nine anchors plus a millimetre offset. The grid
   is the page in miniature: nine cells in the proportions of a portrait sheet,
   so "bottom right" is a place you point at rather than a phrase you parse. */
.page-tools .pdf-anchors {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3px;
  width: min(190px, 100%);
  aspect-ratio: 1 / 1.414;
  margin-top: .4rem;
  padding: 3px;
  border: 2px solid var(--ice-color-on-surface);
  background: var(--ice-color-surface-field);
}

.page-tools .pdf-anchor {
  appearance: none;
  min-height: 0;
  padding: 0;
  border: 1px dashed color-mix(in srgb, var(--ice-color-on-surface) 35%, transparent);
  border-radius: 2px;
  background: transparent;
  cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease;
}

.page-tools .pdf-anchor:hover {
  background: color-mix(in srgb, var(--ice-color-text-accent) 18%, transparent);
}

.page-tools .pdf-anchor[aria-pressed='true'] {
  border-style: solid;
  border-color: var(--ice-color-on-surface);
  background: var(--ice-color-text-accent);
}

.page-tools .pdf-anchor:focus-visible {
  outline: 2px solid var(--ice-color-text-accent);
  outline-offset: 2px;
}

/* ── IOE rank predictor verdicts ──────────────────────────────────── */

/* Three states on one long table, and the middle one carries the most
   meaning: "borderline" exists because these are first-list ranks and later
   lists reach further out. Colour is a second channel here, never the only
   one — the verdict is spelled out in its own column. */
.page-tools [data-verdict='inside'] th,
.page-tools [data-verdict='inside'] td {
  background: color-mix(in srgb, #4caf50 14%, transparent);
}

.page-tools [data-verdict='borderline'] th,
.page-tools [data-verdict='borderline'] td {
  background: color-mix(in srgb, var(--ice-color-text-action) 16%, transparent);
}

.page-tools [data-verdict='outside'] th,
.page-tools [data-verdict='outside'] td {
  color: var(--ice-color-text-muted);
}

/* Four verdict states, not three: "reached by the third list" is its own thing,
   and it is the one most students land in. */
.page-tools [data-verdict='later-list'] th,
.page-tools [data-verdict='later-list'] td {
  background: color-mix(in srgb, #4caf50 8%, transparent);
}

/* A row header sitting on a tinted verdict row cannot stay muted.
   `.tool-readout th` is var(--ice-color-text-muted) — #666a71 — which is fine on
   the plain surface it was designed against, but on the borderline tint
   (var(--ice-color-text-action) at 16%, resolving to #f6dbdf) it measures
   **4.16:1** and fails WCAG AA for body text. axe flagged exactly one node:
   `tr[data-verdict="borderline"] > th[scope="row"]`, "Paschimanchal Campus (WRC)".

   Found 2026-08-21 by `npm run audit:tools` (247 passed, this one failed). It is
   not caused by the tint being wrong — the tint is the second channel that makes
   the verdict scannable, and the verdict is also spelled out in words in its own
   column. The defect is only that the campus name stayed muted once it had a
   coloured ground under it. Giving those headers the body colour lifts it clear
   with the tint intact.

   `[data-verdict='outside']` is deliberately excluded: it sets muted text on
   purpose and carries NO tint, so it sits on the plain surface and passes. */
.page-tools [data-verdict='inside'] th[scope='row'],
.page-tools [data-verdict='borderline'] th[scope='row'],
.page-tools [data-verdict='later-list'] th[scope='row'] {
  color: var(--ice-color-text);
}
