/*
 * The Odds Converter (OddsConverter.js) — the calculators' first screen, over
 * the SureTOOLS tab.
 *
 * The shell is the Lineup Builder's, which is the player page's: a fixed page
 * that fades while its sheet rises, at z-index 70 — over the tab panes, under
 * the fixture page's 80 and the player page's 98. It is restated here rather
 * than shared because those rules are named for that page; if a third tool
 * page lands, the three want one `.tool-page` between them and this is the
 * copy to fold in. The motion scale the sheet and the toasts read is declared
 * on this root by slip-controls.css, beside the slip's own.
 *
 * The one structural difference from the Lineup Builder, and it decides the
 * layout: the sheet is two parts rather than one — a scrolling body and a
 * keypad pinned under it. A calculator whose keys can be scrolled away is a
 * calculator you fight, so the keys never move and everything that reads back
 * scrolls past them.
 *
 * Separation is tonal, as everywhere else in this corner of the app: white
 * cards on the off-white page, the sunken grey inside them, and nothing casts
 * a shadow.
 */

/* --- Shell -------------------------------------------------------------------- */

.odds-converter {
  --enter-y: 12px;
  /* The keypad's own metrics, in one place: the key row, and the gutter the
     pad keeps to the screen's edges. */
  --oc-key-height: 52px;
  --oc-pad-gutter: var(--space-2);

  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  max-width: var(--app-max-width);
  margin-inline: auto;
  background: var(--bg);
  opacity: 0;
  transition: opacity var(--duration) var(--easing);
}

.odds-converter[hidden] {
  display: none;
}

.odds-converter [hidden] {
  display: none !important;
}

.odds-converter[data-open="true"] {
  --enter-y: 0px;

  opacity: 1;
}

.odds-converter__sheet {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding-top: var(--safe-top);
  transform: translateY(var(--enter-y));
  transition: transform var(--duration) var(--easing);
}

/* The page's own scroller, so the tab pane under it keeps its place. */
.odds-converter__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  -webkit-overflow-scrolling: touch;
}

.oc {
  display: flex;
  flex-direction: column;
  padding-bottom: var(--space-3);
}

/* --- Top row and title ----------------------------------------------------------- */

.oc-top {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-3) 0;
}

/* Nothing in the middle: the page's name is the display title below, where
   the Lineup Builder puts the lineup's. */
.oc-top__gap {
  flex: 1;
}

.oc-title {
  margin: var(--space-3) var(--space-4) 0;
  color: var(--text);
  font-size: var(--text-2xl);
  font-weight: 800;
  letter-spacing: -0.5px;
  line-height: 1.1;
}

/* --- Format segments ---------------------------------------------------------------- */

/* Four abreast rather than a scroller: the whole choice has to be visible, or
   the format you are not in stops being an option you know you have. */
.oc-formats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-2);
  margin: var(--space-4) var(--space-4) 0;
}

.oc-seg {
  height: 40px;
  padding: 0 var(--space-1);
  border-radius: 13px;
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition:
    background-color var(--sd-fade) var(--se-out),
    color var(--sd-fade) var(--se-out),
    transform var(--spring-duration) var(--spring);
}

.oc-seg[aria-checked="true"] {
  background: var(--accent-tint);
  color: var(--accent);
}

/* --- The entry ------------------------------------------------------------------------- */

/*
 * The entry rides at the top of the scroller. On a tall phone nothing scrolls
 * at all and this does nothing; on a short one the conversions start below the
 * fold, and pinning the field you are typing in is what keeps reaching them a
 * scroll rather than a loss. The wrapper carries the page's own ground so the
 * title and the segments pass behind it rather than through it.
 */
.oc-sticky {
  position: sticky;
  top: 0;
  z-index: 1;
  padding-bottom: var(--space-1);
  background: var(--bg);
}

.oc-entry {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: var(--space-3) var(--space-4) 0;
  padding: var(--space-4);
  border-radius: var(--radius-xl);
  background: var(--surface);
}

.oc-entry__eyebrow {
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.oc-entry__value {
  display: flex;
  align-items: baseline;
  gap: 2px;
  min-height: 44px;
}

.oc-entry__text {
  color: var(--text);
  font-size: 40px;
  font-weight: 800;
  letter-spacing: -1px;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}

/* Before anything is typed the field shows the format's own example, greyed —
   a placeholder that teaches the shape of the answer rather than an empty box. */
.oc-entry[data-ghost="true"] .oc-entry__text {
  color: var(--text-disabled);
}

.oc-entry__unit {
  color: var(--text-muted);
  font-size: 24px;
  font-weight: var(--weight-bold);
}

/*
 * The caret. There is no focus ring on this card and no system keyboard behind
 * it, so this is the only thing saying where a keypress lands — which is why it
 * blinks even though nothing here is focused.
 */
.oc-entry__caret {
  align-self: stretch;
  width: 2px;
  margin: 8px 0 10px 4px;
  border-radius: 1px;
  background: var(--accent);
  animation: oc-caret 1.1s steps(1, end) infinite;
}

@keyframes oc-caret {
  0%,
  45% {
    opacity: 1;
  }
  55%,
  100% {
    opacity: 0;
  }
}

/*
 * One line under the price, always saying something: what the price means once
 * there is one, and the format's own rule until then — so the rule arrives at
 * the moment it is needed rather than in a help screen nobody opens. The error
 * tone is amber rather than red: a half-written price is not a failure.
 */
.oc-entry__hint {
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.35;
}

.oc-entry[data-state="error"] .oc-entry__hint {
  color: var(--warning-strong);
}

/* --- Section labels ----------------------------------------------------------------------- */

.oc-label {
  margin: var(--space-4) var(--space-4) var(--space-2);
  color: var(--text);
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
}

/* --- The conversions ------------------------------------------------------------------------ */

.oc-rows {
  margin: 0 var(--space-4);
  border-radius: var(--radius-xl);
  background: var(--surface);
  overflow: hidden;
}

.oc-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 52px;
  padding: 0 var(--space-4);
  text-align: left;
  transition: transform var(--spring-duration) var(--spring);
}

.oc-row + .oc-row {
  border-top: 1px solid var(--border);
}

/* Touch-down darkens the fill a few percent, as every control in this corner
   of the app does. */
.oc-row[data-pressed="true"] {
  box-shadow: inset 0 0 0 999px rgb(var(--text-rgb) / 0.04);
}

.oc-row:disabled {
  opacity: 0.45;
}

.oc-row__label {
  flex: 1;
  min-width: 0;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.oc-row__value {
  color: var(--text);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.oc-row__unit {
  margin-left: 1px;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

.oc-row__copy {
  flex: none;
  display: grid;
  place-items: center;
  color: var(--text-muted);
  opacity: 0.65;
}

/* --- The chance --------------------------------------------------------------------------------- */

/* The last row of the conversions card rather than a card of its own: the
   meter is the Implied Chance above it drawn as a picture, and a heading
   between the two would be claiming a second subject where there is one. */
.oc-chance {
  padding: var(--space-3) var(--space-4) var(--space-4);
  border-top: 1px solid var(--border);
}

/*
 * One accent colour rather than the odds slider's red-to-green gradient, and
 * deliberately: a chance is a magnitude, not a verdict. 40% is exactly right
 * at 2.50 and exactly wrong at 3.00, and a bar that went amber at it would be
 * making a call this tool does not make. The length is the whole message.
 */
.oc-meter {
  position: relative;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--surface-sunken);
  overflow: hidden;
}

.oc-meter__fill {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--accent);
  clip-path: inset(0 calc(100% - var(--fill, 0%)) 0 0);
  transition: clip-path var(--sd-spring) var(--se-out);
}

.oc-chance__note {
  margin-top: var(--space-2);
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.35;
}

/* --- The pad ------------------------------------------------------------------------------------- */

/*
 * Pinned under the scroller, and the page's only white ground that runs edge
 * to edge: the keys are furniture rather than another card, so the hairline
 * is what separates them from what they are editing.
 */
.oc-pad {
  position: relative;
  flex: none;
  padding: var(--space-2) var(--oc-pad-gutter)
    calc(var(--space-2) + max(var(--safe-bottom), var(--tg-chrome-inset, 0px)));
  background: var(--surface);
  border-top: 1px solid var(--border);
}

/* The toasts belong to the page, not the pad, but the pad owns the foot of the
   screen — so they rise from its top edge rather than from the nav they cannot
   see. `.slip-toasts` is fixed to the viewport by default; here it is not. */
.odds-converter .slip-toasts {
  position: absolute;
  bottom: 100%;
  padding-bottom: var(--space-3);
}

/* --- Common prices ---------------------------------------------------------------------------------- */

.oc-common {
  margin: 0 calc(var(--oc-pad-gutter) * -1) var(--space-2);
}

.oc-common__track {
  display: flex;
  gap: var(--space-2);
  padding: 0 var(--space-3);
}

.oc-chip {
  --press-scale: 0.96;

  flex: none;
  height: 32px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-full);
  background: var(--surface-sunken);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  transition: transform var(--spring-duration) var(--spring);
}

/* --- Keys --------------------------------------------------------------------------------------------- */

.oc-keys {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-1);
}

.oc-key {
  display: grid;
  place-items: center;
  height: var(--oc-key-height);
  border-radius: var(--radius-md);
  color: var(--text);
  transition:
    background-color var(--sd-fade) var(--se-out),
    color var(--sd-fade) var(--se-out),
    transform var(--spring-duration) var(--spring);
}

/* A key is the one control here that is not on a card, so touch-down fills it
   rather than darkening it. */
.oc-key[data-pressed="true"] {
  background: var(--surface-sunken);
}

.oc-key__glyph {
  font-size: 24px;
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* The two keys that are not digits read a step quieter than the ten that are. */
.oc-key[data-key="pad"],
.oc-key[data-key="delete"] {
  color: var(--text-secondary);
}

/* A full stop is a speck at a digit's size and "+/-" is three characters
   wide at it, so the fourth key is sized for whichever it is drawing. */
/* A full stop sits on the baseline, which in a centred line box is a quarter
   of an em below the middle — so it is lifted back to it. */
.oc-key__glyph[data-pad="dot"] {
  font-size: 30px;
  transform: translateY(-0.22em);
}

.oc-key__glyph[data-pad="slash"] {
  font-size: 24px;
}

.oc-key__glyph[data-pad="sign"] {
  font-size: 17px;
}

.oc-key[data-key="delete"][data-empty="true"] {
  color: var(--text-disabled);
}

/* --- The About sheet ---------------------------------------------------------------------------------- */

/* The Slip Builder's sheet at this page's full size, not its 0.75 — the same
   three overrides the Lineup Builder makes, for the same reason. */
.odds-converter .slip-sheet__panel {
  max-height: min(84dvh, 760px);
}

.odds-converter .slip-sheet__title {
  padding: var(--space-1) var(--space-4) var(--space-3);
  font-size: var(--text-lg);
}

.odds-converter .slip-sheet__body {
  padding: 0 var(--space-4) var(--space-4);
}

.oc-about {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.oc-about__row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.oc-about__name {
  color: var(--text);
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
}

.oc-about__text {
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.45;
}

.oc-about__foot {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.45;
}

/* --- Short screens ------------------------------------------------------------------------------------- */

/*
 * Under about 700pt the display title and the big field together cost more
 * than the answers below them are worth. Everything keeps its role and gives
 * up a few points; nothing is taken away, because a control that exists on one
 * phone and not on another is a worse surprise than a smaller one.
 */
@media (max-height: 700px) {
  .oc-title {
    font-size: var(--text-xl);
  }

  .oc-formats {
    margin-top: var(--space-3);
  }

  .oc-entry__value {
    min-height: 40px;
  }

  .oc-entry__text {
    font-size: 34px;
  }

  .odds-converter {
    --oc-key-height: 46px;
  }
}

/* --- Motion ------------------------------------------------------------------------------------------- */

/*
 * A value that arrived by conversion rather than by typing rises through its
 * fade — the risk word's swap, on the two places a number can change without
 * anybody having pressed it. A digit the user just pressed is not animated:
 * they know where it came from.
 */
.oc-entry__text[data-anim="swap"],
.oc-row__value[data-anim="swap"] {
  animation: oc-swap var(--sd-pop) var(--se-out);
}

@keyframes oc-swap {
  0% {
    transform: translateY(4px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}

/* --- Reduced motion ------------------------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .odds-converter {
    --sd-fade: 100ms;
    --sd-pop: 0ms;
    --sd-spring: 0ms;
    --se-spring: ease-out;
  }

  .odds-converter__sheet {
    transform: none;
  }

  .odds-converter [data-anim] {
    animation: none !important;
  }

  /* A blinking bar is the one piece of motion here that never stops, which is
     exactly what this setting is asking not to have. It stays put and stays on. */
  .oc-entry__caret {
    animation: none;
    opacity: 1;
  }
}
