/* ============================================================ */
/* kd-trade.css · Buy-and-sell section                          */
/* ============================================================ */
/*
  The two-card "Hardware in. Hardware out." panel.

  Ported verbatim from the platform's own site_khouse stylesheet so the
  static site and the application render the same component rather than
  two lookalikes that drift. Every custom property it uses is already
  defined in kd-tokens.css here -- checked property by property, none
  had to be added -- so the cards inherit this site's theme, density,
  radius and mono toggles exactly like every other section.

  Do not restyle this file in isolation: if the panel changes, it should
  change in both places.
*/
.kd-trade {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: var(--kd-gap-grid);
    margin-top: var(--kd-s-8);
}

/* A HERO, not a bordered box. The card carries one of the site's own
 * photographs behind a gradient, and the type sits on the dark end of
 * it -- so the two cards read as the page's call to action rather than
 * as more content.
 *
 * CONTRAST IS THE CONSTRAINT, not the decoration. Type over a photograph
 * fails WCAG the moment the image changes, so the scrim is heaviest
 * where the words are and fades towards the top where nothing sits. The
 * image is darkened too, so the floor does not depend on which
 * photograph a card happens to use.
 *
 * The exact opacities are NOT taste -- they are the output of the
 * platform's e2e/test_trade_card_contrast.py, which composites the worst case
 * (a pure-white photograph under the scrim in the light theme, a
 * pure-black one in the dark theme) and asserts the result still clears
 * WCAG AA against the type colour. Lighten them further and that test
 * fails, which is the point: "a bit lighter" has a floor, and the floor
 * is machine-checked rather than eyeballed. */
.kd-trade__card {
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: var(--kd-s-4);
    align-items: flex-start;
    /* A LANDSCAPE panel, not a near-square tile. The content is bottom
     * aligned, so this floor only governs the empty head-room above it.
     * 26rem still left the card taller than it is wide at two-column
     * widths -- the operator's word was "more rectangle" -- and the
     * content needs about 19rem, so 20rem keeps a little breathing room
     * above it without the card reading as a portrait tile. */
    min-height: 20rem;
    justify-content: flex-end;
    padding: var(--kd-s-8);
    border: 0;
    /* SOFTENED, on the operator's call. This was --kd-r-0 (sharp) on the
     * reasoning that a full-bleed photographic poster reads wrong with
     * rounded corners, which holds for a poster that fills its section;
     * these sit inside a container as two cards among the site's other
     * cards, and sharp corners made them the only square things on the
     * page. --kd-r-2 (4px) is what every other bordered card on the site
     * uses, so these now match them rather than being softer than
     * everything around them -- 8px read as a lot on a card this size.
     * Still the theme's own scale, never a number invented here, and the
     * image is clipped to it by the overflow:hidden above. */
    border-radius: var(--kd-r-2);
    color: var(--kd-bg);
    /* The dark ground the gradient fades into -- also the fallback if
     * the image fails to load, which must not leave white-on-white. */
    background: var(--kd-fg);
}

.kd-trade__bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* 0.78, up from 0.55. At 0.55 the photograph was present but not
     * legible -- the card read as a dark slab that happened to have
     * texture. The scrim below carries the contrast floor, so the image
     * does not have to, and it can be bright enough to look like a
     * photograph. */
    filter: brightness(0.78) saturate(0.95);
    /* Behind the gradient and the content, never over them. */
    z-index: 0;
}

/* The scrim itself, as its own layer between the photograph and the
 * type. Three stops rather than a flat wash: the top is nearly clear so
 * the photograph is genuinely visible, and it deepens towards the
 * bottom where every word sits.
 *
 * MEASURED FROM THE BOTTOM (`to top`), so the heavy end tracks the
 * content -- which is bottom aligned -- instead of tracking the card's
 * height. A percentage from the top would drift off the type the moment
 * a card grew a line. */
.kd-trade__card::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    /* LIGHTER THAN IT WAS (0.72/0.58/0.12). The veil exists to keep the
     * text legible over a photograph, and at those values it was doing
     * more than that -- the photograph barely showed and the card read
     * as a dark slab. Lighter, but not as light as it first went: 0.62
     * at the foot dropped the lede below AA, which test_trade_card_
     * contrast caught. These are the lightest values that still clear
     * it, measured rather than guessed -- the top of the gradient, where
     * no text sits, is where most of the photograph was won back. */
    background: linear-gradient(
        to top,
        rgba(var(--kd-fg-rgb), 0.70) 0%,
        rgba(var(--kd-fg-rgb), 0.54) 80%,
        rgba(var(--kd-fg-rgb), 0.10) 100%
    );
}

/* Everything the visitor reads or touches sits above both layers. */
.kd-trade__card > *:not(.kd-trade__bg) {
    position: relative;
    z-index: 2;
}

/* The accent rail that tells the two apart at a glance, without relying
 * on the photographs to do it. */
.kd-trade__card--buy { box-shadow: inset 4px 0 0 0 var(--kd-accent); }
.kd-trade__card--sell { box-shadow: inset 4px 0 0 0 var(--kd-c-ok); }

.kd-trade__title {
    font-size: var(--kd-text-5);
    font-weight: var(--kd-w-semi);
    letter-spacing: var(--kd-track-snug);
    margin: 0;
}

.kd-trade__lede {
    /* On the dark hero the muted token is unreadable -- it is tuned for
     * the light surface. The panel's own foreground, softened. */
    color: var(--kd-bg);
    opacity: 0.85;
    margin: 0;
    max-width: 40ch;
}

/* The steps, behind a disclosure. They are genuinely useful ("what
 * happens after I press send?") and they were the thing diluting the
 * call to action: three numbered lines competing with the one input the
 * card exists for. Native <details>, so no script and no loss of
 * keyboard access. */
.kd-trade__how {
    width: 100%;
}

.kd-trade__how > summary {
    cursor: pointer;
    list-style: none;
    font-family: var(--kd-font-mono);
    font-size: var(--kd-text-0);
    letter-spacing: var(--kd-track-mono);
    text-transform: uppercase;
    color: var(--kd-bg);
    opacity: 0.75;
    padding: var(--kd-s-2) 0;
}

.kd-trade__how > summary::-webkit-details-marker { display: none; }

.kd-trade__how > summary::after {
    content: " +";
}

.kd-trade__how[open] > summary::after {
    content: " −";
}

/* Numbered, because these are steps in an order, not a feature list --
 * the counter is the point. */
.kd-trade__steps {
    list-style: none;
    counter-reset: kd-trade-step;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--kd-s-3);
    /* Pushes the button to the bottom of whichever card is taller. */
    flex: 1 0 auto;
}

.kd-trade__steps li {
    counter-increment: kd-trade-step;
    display: grid;
    grid-template-columns: 1.75rem 1fr;
    gap: var(--kd-s-3);
    align-items: baseline;
    color: var(--kd-bg);
    opacity: 0.9;
}

.kd-trade__steps li::before {
    content: counter(kd-trade-step);
    font-family: var(--kd-font-mono);
    font-size: var(--kd-text-0);
    color: var(--kd-bg);
    border: var(--kd-border-w) solid rgba(var(--kd-bg-rgb), 0.4);
    border-radius: var(--kd-r-pill);
    text-align: center;
    padding: 2px 0;
}

/* ---- The homepage cards' inline start ------------------------------- */

.kd-trade__quick {
    display: flex;
    flex-direction: column;
    gap: var(--kd-s-2);
    width: 100%;
}

.kd-trade__quicklabel {
    font-family: var(--kd-font-mono);
    font-size: var(--kd-text-0);
    letter-spacing: var(--kd-track-mono);
    text-transform: uppercase;
    color: var(--kd-bg);
    opacity: 0.85;
}

.kd-trade__quickrow {
    display: flex;
    gap: var(--kd-s-2);
    flex-wrap: wrap;
}

.kd-trade__quickrow input {
    flex: 1 1 12rem;
    padding: var(--kd-s-3);
    font-family: var(--kd-font-sans);
    /* Same 16px floor as the quote form: below it iOS Safari zooms the
     * page the moment the field is focused. */
    font-size: max(16px, var(--kd-text-1));
    min-height: 44px;
    color: var(--kd-fg);
    background: var(--kd-bg);
    border: var(--kd-border-w) solid var(--kd-border);
    border-radius: var(--kd-r-1);
}

.kd-trade__quickrow input:focus {
    outline: none;
    border-color: var(--kd-accent);
    box-shadow: 0 0 0 3px var(--kd-accent-ring);
}

/* The button never shrinks below its label; the input takes the slack. */
.kd-trade__quickrow .kd-btn {
    flex: 0 0 auto;
}

/* ---- File inputs ----------------------------------------------------
 *
 * A file input is two things the browser draws itself: a button and the
 * chosen-file text. ::file-selector-button is the standard way to style
 * the button part -- supported in every current engine, and it needs no
 * JavaScript and no hidden-input-behind-a-label trick. Those tricks cost
 * you the keyboard and screen-reader behaviour the real control already
 * has, which is a bad trade for a border radius.
 *
 * The input itself carries NO border here: the row's cell is already a
 * bounded box, and a second frame around a control that is mostly text
 * reads as a broken field.
 */


/* ============================================================ */
/* In-progress destination pages                                */
/* ============================================================ */
/*
  source-hardware.html and sell-hardware.html show the control that will
  eventually live there, dimmed, above a notice saying the page is still
  being built and that email is the way through in the meantime.

  THE PREVIEW MUST NOT BE REACHABLE. It is a picture of a future control,
  not a control -- so it carries `inert` (which removes it from the tab
  order and the accessibility tree in modern browsers) and, for anything
  older, pointer-events:none plus tabindex="-1" on the fields themselves.
  A visitor must never be able to type into a box that goes nowhere.

  The dimming is opacity, not a lighter set of colours: the point is that
  it reads as "not active yet" rather than as a differently-styled form,
  and opacity keeps the relationship to the real control obvious when it
  is eventually switched on.
*/
.kd-wip {
    border: var(--kd-border-w) solid var(--kd-border);
    border-radius: var(--kd-r-2);
    background: var(--kd-bg-alt);
    padding: var(--kd-s-6);
    margin-top: var(--kd-s-6);
    max-width: 62ch;
}

.kd-wip__badge {
    display: inline-flex;
    align-items: center;
    gap: var(--kd-s-2);
    font-family: var(--kd-font-mono);
    font-size: var(--kd-text-0);
    letter-spacing: var(--kd-track-mono);
    text-transform: uppercase;
    color: var(--kd-c-warn, var(--kd-fg-muted));
    margin-bottom: var(--kd-s-3);
}
/* A steady dot, not an animated one: this is a status, not activity, and a
   pulsing marker on a page that is doing nothing is a lie about progress. */
.kd-wip__dot {
    width: 8px; height: 8px; border-radius: var(--kd-r-pill);
    background: currentColor; flex: none;
}

.kd-wip__title { font-size: var(--kd-text-3); font-weight: var(--kd-w-semi); margin: 0 0 var(--kd-s-2); }
.kd-wip__body  { margin: 0 0 var(--kd-s-4); max-width: 56ch; }

.kd-wip__mail {
    display: inline-flex; align-items: center; gap: var(--kd-s-2);
    font-family: var(--kd-font-mono); font-size: var(--kd-text-1);
}

/* ---- the dimmed preview ---- */
.kd-wip__previewhead {
    font-family: var(--kd-font-mono);
    font-size: var(--kd-text-0);
    letter-spacing: var(--kd-track-mono);
    text-transform: uppercase;
    color: var(--kd-fg-muted);
    margin: var(--kd-s-7) 0 var(--kd-s-3);
}
.kd-wip__preview {
    /* Two effects, doing different jobs. Opacity says "not active yet" and
       keeps the relationship to the real control obvious when it is switched
       on. Grayscale removes the accent colour, so the preview cannot be
       mistaken for a live control that merely looks faded -- the buttons in
       particular stop reading as pressable once they are not accent-coloured. */
    opacity: 0.55;
    filter: grayscale(1);
    pointer-events: none;
    user-select: none;
    position: relative;
}
/* The preview is wide -- it is a nine-column table. Let it scroll inside its
   own box rather than pushing the page sideways. */
.kd-wip__preview .kd-quote__lines { overflow-x: auto; }
.kd-wip__preview .kd-trade__quicklabel { margin-bottom: var(--kd-s-2); display: block; }
.kd-wip__preview input {
    width: 100%;
    padding: var(--kd-s-3);
    border: var(--kd-border-w) solid var(--kd-border);
    border-radius: var(--kd-r-1);
    background: var(--kd-bg);
    color: var(--kd-fg);
    font: inherit;
}
.kd-wip__previewrow { display: flex; gap: var(--kd-s-3); flex-wrap: wrap; align-items: center; }
.kd-wip__previewrow > input { flex: 1 1 18ch; min-width: 0; }

/* Reduced motion is irrelevant here (nothing moves), but forced-colors is not:
   in that mode opacity is the only signal left, and it survives. */
@media (prefers-contrast: more) {
    .kd-wip__preview { opacity: 0.6; }
}

/* The status badge on a photograph.
   .kd-badge--ok is "13% green tint behind full-strength green text", which is
   readable on this site's light surfaces and is what the styleguide shows. On
   this card the surface is a dark photograph: the tint lets the image through,
   so the badge reads as green on green and its text has a contrast ratio of
   1.00 against its own fill. Here, and only here, the fill is opaque and the
   text is the deeper green. Measured, not guessed. */
.kd-trade__card .kd-badge--ok {
    background: var(--kd-c-ok-surface);
    color: var(--kd-c-ok-deep);
    border-color: transparent;
}
