/* ============================================================
   Tool cards — the landing page's list, the dashed "next tool"
   placeholder, and the featured card with its rotating glow.
   ============================================================ */

.tools{ padding-bottom:64px; }

.card{
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:10px;
  padding:32px;
  margin-bottom:20px;
}
.card-media{
  margin:-32px -32px 24px;
  border-bottom:1px solid var(--line);
  border-radius:10px 10px 0 0;
  overflow:hidden;
  background:var(--surface-2);
}
/* A card's cover is either a still or a silent looping clip, and the two are
   the same box: full width of the media column, height from the file's own
   ratio. render-tools.js builds whichever the entry in tools.js describes. */
.card-media img,
.card-media video{ display:block; width:100%; height:auto; margin-inline:auto; }

/* Small UI screenshots (a few hundred px native) look soft when stretched to
   fill the media column, and their near-square shape drags the card taller than
   the copy beside it. Sit them on the backdrop at a sane size instead. */
.card-media-contain{
  position:relative;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:26px;
  isolation:isolate;
}
/* Three layers, all positive z-index so nothing depends on a negative-index
   child painting above its parent's own background:
     1. .card-media-bg  — the same screenshot, blown up and blurred
     2. ::after         — a vignette over it
     3. the real shot   — crisp, on top
   The backdrop element is injected by render-tools.js for images marked
   fit:"contain"; without it the media box is just the flat surface as before. */
/* Selector has to out-specify the generic `.card-media img` rule above, which
   would otherwise force height:auto and shrink the backdrop to the shot's size. */
.card-media img.card-media-bg{
  position:absolute;
  inset:0;
  z-index:0;
  width:100%;
  height:100%;
  object-fit:cover;
  filter:blur(34px) saturate(1.8) brightness(1.1);
  transform:scale(1.3); /* pushes the blur's soft edges past the clipped box */
  opacity:0.7;
  pointer-events:none;
}
/* Vignette only — darkening the backdrop evenly just returns it to the flat
   surface colour it was replacing. Edges fall off, the centre stays lit so the
   crisp shot reads as sitting above it. */
.card-media-contain::after{
  content:"";
  position:absolute;
  inset:0;
  z-index:1;
  pointer-events:none;
  background:radial-gradient(circle at 50% 45%,
    rgba(11,13,16,0) 25%, rgba(11,13,16,0.45) 75%, rgba(11,13,16,0.7) 100%);
}
.card-media-contain img:not(.card-media-bg){
  position:relative;
  z-index:2;
  width:auto;
  max-width:100%;
  max-height:300px;
  border:1px solid var(--line);
  border-radius:8px;
  box-shadow:0 18px 40px rgba(0,0,0,0.45);
}

/* Wide screens: put the screenshot beside the copy instead of stacking it.
   Stacked, a full-width card leaves the text hugging the left of a lot of empty
   space, and stretches the cover past its native width until it goes soft. */
@media (min-width: 1080px){
  .card-with-media{
    display:grid;
    grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    column-gap:36px;
    align-items:center;
  }
  .card-with-media > .card-body{ min-width:0; }
  .card-with-media > .card-media{
    /* bleed to the card's left/top/bottom edges; the gap handles the right */
    margin:-32px 0 -32px -32px;
    border-bottom:0;
    border-right:1px solid var(--line);
    border-radius:10px 0 0 10px;
    align-self:stretch;
    display:flex;
    align-items:center;
  }

  /* A card with no screenshot has nothing to put in a second column, so split
     the copy itself: label + title on the left, description + buttons on the
     right. Otherwise the text sits in the left third of a very wide band. */
  .card:not(.card-with-media) > .card-body{
    display:grid;
    grid-template-columns:minmax(0,0.8fr) minmax(0,1.2fr);
    grid-template-areas:
      "tag  badge"
      "head desc"
      ".    acts";
    column-gap:48px;
    row-gap:22px;
    align-content:start;
  }
  .card:not(.card-with-media) .card-tag{ grid-area:tag; margin:0; }
  .card:not(.card-with-media) .card-body > h3{ grid-area:head; margin:0; }
  .card:not(.card-with-media) p.desc{ grid-area:desc; margin:0; }
  .card:not(.card-with-media) .actions{ grid-area:acts; align-self:end; }
  /* Out of the corner and into its own cell — floated, it landed on top of the
     description's first line once the copy moved into the right column. */
  .card:not(.card-with-media) .highlight-badge{
    grid-area:badge;
    position:static;
    justify-self:end;
    align-self:start;
  }
}

.card-tag{
  font-size:var(--t-mini);
  letter-spacing:0.06em;
  color:var(--muted);
  margin:0 0 14px;
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  gap:8px;
}
/* Not a separator: a state light. The tools in this list are all real and all
   installable today, which is what green says here — and it is why the ghost
   card at the foot of the list gets the same dot in amber instead of no dot
   at all. Read down the page the two are one control panel. */
.card-tag .dot{
  width:6px; height:6px; border-radius:50%;
  background:var(--role-proof);
  display:inline-block;
}
/* The card is not a link — the buttons inside it are — so it must not lift, or
   scale, or do any of the things a pressable surface does. What it may do is
   acknowledge that the pointer is inside it, and the edge coming up out of the
   background is the smallest way to say so. It is also what the project cards
   at /contributions/ already do, so the two lists answer a pointer the same
   way instead of one of them being inert.
   Gated on a real pointer: on a touch screen this fires on tap and then sticks
   until something else is tapped, which is a card that looks stuck rather than
   a card that responded. */
@media (hover: hover) and (pointer: fine){
  .card{ transition:border-color var(--dur-1) var(--ease-out); }
  .card:hover{ border-color:var(--line-hover); }
  /* The featured card starts from a lighter edge than the rest, so it needs its
     own step up — the shared rule would otherwise pull it *down* to the plain
     card's hover colour and read as the highlight switching off. */
  .card-featured:hover{ border-color:#3D4A61; }
}

.card h3{ font-size:var(--t-h3); margin:0 0 12px; }
.card p.desc{
  white-space: pre-line;
  color:var(--muted);
  max-width:68ch;
  margin:0 0 22px;
}

/* ---------- ghost "next tool" card ---------- */
.card-ghost{
  background:transparent;
  border:1px dashed var(--line);
  border-radius:10px;
  padding:28px 32px;
  color:var(--muted);
  font-size:var(--t-control);
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:20px;
}
/* The one place on the site where something is genuinely unsettled, and so the
   only place the fourth axis has a job. Amber on the note alone: the label
   beside it is a sentence and stays neutral, because two coloured halves would
   make the row an alert rather than a placeholder. */
.card-ghost .mono{ color:var(--role-pending); font-size:var(--t-mini); letter-spacing:0.06em; }

/* ---------- highlight band (one featured tool) ----------
   Must come after .card so the featured overrides win on equal specificity. */
.highlight{ padding-bottom:56px; }
.highlight-head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:16px;
  margin-bottom:20px;
}
.highlight-head .section-label{ margin:0; color:var(--role-nav); }
.highlight-note{
  font-size:var(--t-mini);
  letter-spacing:0.06em;
  color:var(--muted);
  margin:0;
}
/* Rotating glow: a blurred conic ramp of the axis colours, muted and darkened,
   sits behind the card and turns slowly — a coloured shadow rather than a border.
   Browsers without @property just get the same halo, held still.
   The ramp is X, Y, Z, W in order and back to X — the gizmo itself, turning.
   Its fourth stop used to be a purple that is in no token on the site; the
   halo was one colour short of meaning anything and made up the difference. */
@property --glow-angle{
  syntax:'<angle>';
  initial-value:0deg;
  inherits:false;
}
.card-featured{
  /* Glow tuning knobs. They inherit into ::before, so they can also be
     overridden live from the console: el.style.setProperty('--glow-speed','6s') */
  --glow-speed:4s;    /* one full turn — lower is faster */
  --glow-spread:10px; /* how far the halo reaches past the card */
  --glow-blur:18px;   /* softness */
  --glow-strength:0.5;/* opacity */

  /* No stacking context here on purpose: the ::before glow must stay behind
     the card's own background, which only happens at z-index:auto. */
  position:relative;
  border-color:#2A3140;
  background:
    linear-gradient(180deg, rgba(90,169,255,0.07), rgba(90,169,255,0) 240px),
    var(--surface);
}
.card-featured::before{
  content:"";
  position:absolute;
  inset:calc(-1 * var(--glow-spread));
  z-index:-1;
  border-radius:20px;
  background:conic-gradient(
    from var(--glow-angle),
    #8C3438, #2F6B3B, #2F5C87, #8A6224, #8C3438
  );
  filter:blur(var(--glow-blur));
  opacity:var(--glow-strength);
  animation:glow-rotate var(--glow-speed) linear infinite;
}
@keyframes glow-rotate{ to{ --glow-angle:360deg; } }
@media (prefers-reduced-motion: reduce){
  .card-featured::before{ animation:none; }
}
.card-featured h3{ font-size:var(--t-feature); }
.card-featured p.desc{ font-size:var(--t-lead); }
.highlight-badge{
  position:absolute;
  top:18px;
  right:18px;
  z-index:1;
  font-size:var(--t-micro);
  letter-spacing:0.12em;
  text-transform:uppercase;
  /* "Free & open source" is not a label on the card, it is a claim about the
     thing — and one the GitHub button directly below it proves. It belongs to
     the evidence colour with the button, not to the section label above it. */
  color:var(--role-proof);
  /* Derived rather than written out, so retuning the evidence colour reaches
     the fill and the ring with it — the badge is bound to the role now, not
     to a green that happens to be this green. */
  background:color-mix(in srgb, var(--role-proof) 10%, transparent);
  border:1px solid color-mix(in srgb, var(--role-proof) 35%, transparent);
  border-radius:999px;
  padding:4px 12px;
}
@supports not (background: color-mix(in srgb, red 10%, blue)){
  .highlight-badge{ background:rgba(70,167,88,0.10); border-color:rgba(70,167,88,0.35); }
}

/* ---------- responsive ---------- */
@media (max-width: 720px){
  .card{ padding:24px; }
  .card-media{ margin:-24px -24px 22px; }
  /* Narrow cards leave no room beside the tag, so drop the badge into flow
     above it instead of floating it over the corner. */
  .highlight-badge{
    position:static;
    display:inline-block;
    margin-bottom:14px;
  }
}
