/* Ground, type, and the few components that carry the identity.
 *
 * The ground is bone paper: three very low-contrast warm fields in OKLCH plus a
 * grain layer multiplied over them, so the surface has a tooth. A flat fill
 * would read as a blank browser page, which is how a light interface dies, the
 * same way a flat black reads as a screen that is switched off.
 *
 * The organising idea is a ledger, not a dashboard. Things are separated by a
 * rule and by air. A box appears only where it means "this is an object you can
 * take": a mission on the board, a slip of paper on the desk.
 */

*, *::before, *::after { box-sizing: border-box; }

/* Several components declare their own `display` (`.field`, `.kv-list`,
 * `.verify-steps`…) at the same specificity as the browser's built-in
 * `[hidden] { display: none }` rule ; whichever is later in the cascade
 * wins, which silently un-hides an element toggled via `.hidden = true`
 * (found the hard way: create.html's token-price field stayed visible
 * regardless of currency, and a refused submission still showed its
 * verification steps underneath). `hidden` is a semantic the platform
 * gives us for exactly this ; no component style should be able to beat it. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  min-height: 100%;
}

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  font-family: var(--font-body);
  font-size: var(--size-body);
  line-height: var(--leading-body);
  color: var(--text-plain);
  background-color: var(--paper-100);
  /* Three fields, all within a hair of each other in lightness. The gold one
   * sits top-left because that is where the pool figure is; the whole page is
   * very slightly lit from the same corner as its own shadows. */
  background-image:
    radial-gradient(118% 82% at 8% -10%, oklch(0.93 0.042 78 / 0.62), transparent 58%),
    radial-gradient(84% 62% at 96% 2%, oklch(0.93 0.030 182 / 0.42), transparent 56%),
    radial-gradient(150% 128% at 50% 112%, oklch(0.90 0.020 66 / 0.70), transparent 68%);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
}

/* The tooth. Multiplied rather than overlaid: on paper the grain has to sit in
 * the fibre, not glow on top of it. Fixed and pointer-events-none so it never
 * repaints with the scroll. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--z-grain);
  opacity: 0.34;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)' opacity='0.34'/%3E%3C/svg%3E");
}

main, header, footer { position: relative; z-index: 1; }

/* ---- Type --------------------------------------------------------------- */

/* Headings are set in the mono. It is wide, so a heading that does not fit is
 * a heading that is too long, and that is the intended discipline rather than
 * a problem to solve with a smaller size. */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  color: var(--text-loud);
  margin: 0;
  text-wrap: balance;
}
h1 { font-size: clamp(23px, 5.2vw, var(--size-display)); }
h2 { font-size: clamp(18px, 3.4vw, var(--size-title)); }
h3 { font-size: clamp(15px, 2.4vw, var(--size-lead)); }

p { margin: 0; text-wrap: pretty; }

/* A label, not a decoration. Used on the page head and nowhere it would just
 * be repeating what the heading underneath already says. */
.eyebrow {
  font-family: var(--font-display);
  font-size: var(--size-micro);
  font-weight: 500;
  letter-spacing: var(--tracking-micro);
  text-transform: uppercase;
  color: var(--signal-700);
}

/* Every number on this site. Tabular by construction: a countdown that shifts
 * its own layout every second is the detail that makes a product feel cheap. */
.figure {
  font-family: var(--font-figure);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text-loud);
}

.quiet { color: var(--text-quiet); }
.faint { color: var(--text-faint); }

/* ---- Surfaces -----------------------------------------------------------
 * A slip of paper on the desk: the page's own grain shows through, the edge is
 * a hairline of ink rather than a border of grey, and the lift is small enough
 * that you read it as "this sheet is on top" and not as "this is a card". */

.panel {
  position: relative;
  z-index: var(--z-panel);
  border-radius: var(--radius-card);
  border: 1px solid var(--edge-soft);
  background-color: color-mix(in oklch, var(--paper-50) 88%, transparent);
  box-shadow: var(--lift-resting);
  padding: var(--space-5) var(--space-4);
}

/* A card lifts on hover with a spring, and the lift is small. A card that
 * jumps is a card that is asking for attention it has not earned. */
.panel--live {
  transition:
    transform var(--dur-move) var(--ease-spring),
    box-shadow var(--dur-move) var(--ease-settle),
    border-color var(--dur-move) var(--ease-settle);
}
.panel--live:hover {
  transform: translateY(-3px);
  box-shadow: var(--lift-raised);
  border-color: var(--edge-firm);
}

.panel--locked { opacity: 0.62; }

/* ---- Controls ---------------------------------------------------------- */

.action {
  position: relative;
  isolation: isolate;
  /* The travelling sheen below is parked at translateX(-120%). Without this it
   * is painted OUTSIDE the button, as a pale smear on the page next to every
   * control -- visible in the first screenshot pass, invisible in the code. */
  overflow: hidden;
  /* These controls are often anchors. Left alone, the browser underlines them
   * and a designed button reads as a default link in a shell. */
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 46px;
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-control);
  font-family: var(--font-display);
  font-size: var(--size-small);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--paper-50);
  cursor: pointer;
  /* Encre, pas or. L or de ce systeme designe l argent : un prix, un montant,
   * un solde. Le mettre aussi sous une commande lui fait dire deux choses, et
   * la case doree pleine est de toute facon le reflexe le plus use qui soit. */
  /* La couleur de fond double le degrade : elle sert de repli si l image ne
   * peint pas, et sans elle la mesure de contraste compare le texte au fond de
   * la CARTE au lieu du bouton, et rend 1:1 sur un bouton parfaitement lisible. */
  background-color: var(--ink-900);
  background-image: linear-gradient(176deg, var(--ink-800), var(--ink-950));
  box-shadow: var(--lift-raised);
  transition:
    transform var(--dur-tap) var(--ease-spring),
    box-shadow var(--dur-move) var(--ease-settle),
    filter var(--dur-tap) var(--ease-settle);
}

/* The primary action is over-layered on purpose: a gradient body, a drawn
 * inner rim, a sheen that travels on hover, a spring on press. One of these
 * alone would read as a default button. */
.action::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  /* Le rebord : une arete claire en haut, une ombre en bas. C est ce qui fait
   * qu un rectangle d encre se lit comme une touche et pas comme un aplat. */
  box-shadow: inset 0 1px 0 oklch(0.98 0.01 80 / 0.22),
              inset 0 -1px 0 oklch(0.05 0.01 60 / 0.55);
}
.action::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-image: linear-gradient(100deg, transparent 32%,
    oklch(1 0 0 / 0.20) 48%, transparent 64%);
  transform: translateX(-120%);
  transition: transform var(--dur-reveal) var(--ease-settle);
}
.action:hover::after { transform: translateX(120%); }
.action:hover { filter: brightness(1.03); }
.action:active { transform: scale(0.965); }
.action:focus-visible {
  outline: 2px solid var(--ink-900);
  outline-offset: 3px;
}
/* A disabled action is drawn, not desaturated. Filtering the gold gradient
 * left a muddy brown slab with unreadable text on it; on paper the honest
 * form of "not yet" is an empty outline. */
.action[disabled] {
  cursor: not-allowed;
  background-image: none;
  background-color: color-mix(in oklch, var(--paper-200) 80%, transparent);
  box-shadow: inset 0 0 0 1px var(--edge-soft);
  color: var(--text-faint);
}
.action[disabled]::before, .action[disabled]::after { content: none; }

/* The secondary action is drawn in ink, not filled. On paper a second filled
 * button competes with the first and the page stops having a primary. */
.action--ghost {
  color: var(--text-loud);
  background-image: none;
  background-color: color-mix(in oklch, var(--paper-50) 70%, transparent);
  box-shadow: inset 0 0 0 1px var(--edge-firm);
}
.action--ghost:focus-visible { outline-color: var(--ink-900); }
.action--ghost:hover {
  filter: none;
  background-color: var(--paper-50);
  box-shadow: inset 0 0 0 1px var(--ink-900);
}
.action--ghost::before { box-shadow: none; }

/* ---- Status marks ------------------------------------------------------
 * Set in the mono, uppercase, small. A stamp, not a pill of colour. */

.mark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 3px 11px;
  border-radius: var(--radius-pill);
  font-family: var(--font-display);
  font-size: var(--size-micro);
  font-weight: 700;
  letter-spacing: var(--tracking-micro);
  text-transform: uppercase;
}
/* "Ouvert" est l etat par defaut d une mission : il se lit, il ne se signale
 * pas. Seuls les deux verdicts portent une teinte, et tres basse. */
.mark--open {
  color: var(--text-quiet);
  background-color: color-mix(in oklch, var(--paper-200) 80%, transparent);
  box-shadow: inset 0 0 0 1px var(--edge-firm);
}
.mark--verified {
  color: var(--verified-600);
  background-color: color-mix(in oklch, var(--verified-500) 12%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--verified-600) 38%, transparent);
}
.mark--refused {
  color: var(--rust-600);
  background-color: color-mix(in oklch, var(--rust-500) 11%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--rust-600) 34%, transparent);
}

/* ---- The ledger rule ----------------------------------------------------
 * The separator this design leans on instead of a box. Not a flat hairline:
 * it fades at both ends, so it reads as ruled paper rather than as a div with
 * a border. */
.rule {
  height: 1px;
  border: 0;
  margin: var(--space-5) 0;
  background-image: linear-gradient(90deg,
    transparent, var(--edge-firm) 12%, var(--edge-firm) 88%, transparent);
}

/* ---- The mission dial --------------------------------------------------
 * A mission is two quantities draining at once: slots and time. Both live on
 * one drawn ring rather than in two progress bars, so the state of a mission is
 * a shape you recognise before you read a number. */

.dial { display: block; transform: rotate(-90deg); }
.dial__track { stroke: var(--paper-300); }
.dial__slots {
  stroke: var(--signal-500);
  stroke-linecap: round;
  transition: stroke-dashoffset var(--dur-reveal) var(--ease-settle);
}
.dial__time {
  stroke: var(--verified-600);
  stroke-linecap: round;
  opacity: 0.9;
  transition: stroke-dashoffset var(--dur-reveal) var(--ease-settle);
}

/* ---- Entry, driven by the scroll itself --------------------------------
 * Native scroll-driven animation, no library and no scroll listener. It exists
 * to answer one question: which block am I looking at. Each block lifts the
 * last few pixels as it enters, so the page reads as a sheet being fed rather
 * than as a wall that was already there. Anything the browser cannot do here
 * simply shows the block, which is the correct default. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .feed > * {
      animation: feed-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 62%;
    }
    /* The fade starts at 0.42 rather than at 0. A block that is fully
     * transparent until something scrolls is invisible to anything that does
     * not scroll: a print, a reader mode, a preview bot, a screenshot. The
     * travel is what carries the motion; the fade only seasons it. */
    @keyframes feed-in {
      from { opacity: 0.42; transform: translateY(18px); }
      to { opacity: 1; transform: none; }
    }
  }
}
