/*
 * Watchlist cards.
 *
 * Deliberately a different object from a ranking card: no score pill, no ghost
 * watermark, no winner treatment, a lighter border and more air. A reader
 * scrolling past the ranked ten should register the change before reading a
 * word, because these products are not ranked and must not look like they are.
 *
 * --wl-caution is the one color this component adds. The palette has
 * --primary-accent for emphasis and --secondary-accent green for success, and
 * nothing that reads as "take care". Amber at this weight sits beside the cyan
 * without competing and stays legible on --bg-card.
 */

.wl-section-wrap {
    --wl-caution: #F5A524;
    max-width: var(--max-width);
    margin: 64px auto 0;
    padding: 0 20px;
}

.wl-eyebrow {
    font-family: 'Tiny5', monospace;
    font-size: var(--fs-eyebrow);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--primary-accent);
    margin: 0 0 8px;
}

.wl-heading {
    color: var(--text-heading);
    margin: 0 0 14px;
}

.wl-intro {
    font-size: var(--fs-lead);
    line-height: 1.65;
    color: var(--text-secondary);
    max-width: 68ch;
    margin: 0 0 32px;
}

/* ---------- the card ---------- */

.wl-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: 14px;
    padding: 28px 28px 20px;
    margin: 0 0 20px;
}

.wl-card-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0 0 14px;
}

.wl-card-title {
    margin: 0;
    color: var(--text-heading);
    font-size: 22px;
    line-height: 1.2;
}

.wl-card-company {
    margin: 0;
    font-size: var(--fs-cap);
    color: var(--text-secondary);
}

/* Where a ranking card carries a score. Dotted, muted and un-pill-like on
   purpose: it states an absence, so it must not read as a grade. */
.wl-card-status {
    margin: 0 0 0 auto;
    font-size: var(--fs-micro);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-secondary);
    border: 1px dashed var(--border-color);
    border-radius: 999px;
    padding: 3px 11px;
}

.wl-card-what {
    margin: 0 0 12px;
    font-size: var(--fs-lead);
    line-height: 1.6;
    color: var(--text-primary);
}

.wl-card-why {
    margin: 0 0 20px;
    font-size: var(--fs-body);
    line-height: 1.65;
    color: var(--text-secondary);
}

.wl-inline-label { color: var(--text-primary); font-weight: 600; }

/* ---------- the two editorial blocks ---------- */

.wl-block {
    border-left: 2px solid var(--border-color);
    background: rgba(255, 255, 255, 0.02);
    border-radius: 0 8px 8px 0;
    padding: 14px 18px;
    margin: 0 0 14px;
}

.wl-block--read  { border-left-color: var(--primary-accent); }
.wl-block--data  { border-left-color: var(--secondary-accent); }
.wl-block--watch { border-left-color: var(--wl-caution); }

.wl-block-label {
    margin: 0 0 6px;
    font-size: var(--fs-micro);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--primary-accent);
}

.wl-block--watch .wl-block-label { color: var(--wl-caution); }
.wl-block--data .wl-block-label  { color: var(--secondary-accent); }

/* Computed figures, so they get tabular numerals and a tighter rhythm than
   the prose blocks either side of them. */
.wl-datalist { margin: 0; padding: 0; list-style: none; font-variant-numeric: tabular-nums; }
.wl-datalist li { position: relative; padding: 0 0 0 16px; margin: 0 0 6px;
    font-size: var(--fs-sub); line-height: 1.6; color: var(--text-primary); }
.wl-datalist li:last-child { margin-bottom: 0; }
.wl-datalist li::before { content: ''; position: absolute; left: 0; top: 9px;
    width: 7px; height: 1px; background: var(--secondary-accent); opacity: .7; }

.wl-block-body {
    margin: 0;
    font-size: var(--fs-body);
    line-height: 1.7;
    color: var(--text-primary);
}

/* ---------- evidence ---------- */

.wl-section { margin: 0 0 14px; }

.wl-sub-label {
    margin: 0 0 6px;
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-secondary);
}

.wl-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.wl-list li {
    position: relative;
    padding: 0 0 0 18px;
    margin: 0 0 5px;
    font-size: var(--fs-sub);
    line-height: 1.6;
    color: var(--text-secondary);
}

/* Decorative, so it stays in CSS: a text extractor should read the bullet
   text and not a glyph we chose. */
.wl-list li::before {
    content: '';
    position: absolute;
    left: 4px;
    top: 9px;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--border-color);
}

.wl-section--why p {
    margin: 0;
    font-size: var(--fs-sub);
    line-height: 1.65;
    color: var(--text-secondary);
}

.wl-section--why strong { color: var(--text-primary); }

/* ---------- meta rows ---------- */

.wl-meta {
    display: grid;
    grid-template-columns: minmax(130px, max-content) 1fr;
    gap: 6px 18px;
    margin: 18px 0 0;
    padding: 16px 0 0;
    border-top: 1px solid var(--border-color);
    font-size: var(--fs-sub);
}

.wl-meta dt { color: var(--text-secondary); }
.wl-meta dd { margin: 0; color: var(--text-primary); }

.wl-ranking { color: var(--nav-text); text-decoration: none; border-bottom: 1px solid transparent; }
.wl-ranking:hover { border-bottom-color: currentColor; }
.wl-ranking--missing { color: var(--wl-caution); border-bottom: 1px dotted currentColor; }

/* ---------- footer ---------- */

.wl-card-foot {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 18px;
    margin: 18px 0 0;
    padding: 14px 0 0;
    border-top: 1px solid var(--border-color);
}

.wl-stamp { font-size: var(--fs-micro); color: var(--text-secondary); }

.wl-card-visit {
    margin-left: auto;
    font-size: var(--fs-cap);
    color: var(--primary-accent);
    text-decoration: none;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 7px 15px;
    transition: var(--transition);
}

.wl-card-visit::after { content: ' \2197'; }
.wl-card-visit:hover { border-color: var(--primary-accent); background: rgba(0, 217, 255, 0.07); }
.wl-card-visit:focus-visible { outline: 2px solid var(--primary-accent); outline-offset: 2px; }

@media (max-width: 640px) {
    .wl-card { padding: 22px 18px 16px; }
    .wl-card-status { margin-left: 0; }
    .wl-meta { grid-template-columns: 1fr; gap: 2px; }
    .wl-meta dd { margin: 0 0 8px; }
    .wl-card-visit { margin-left: 0; }
}

/* ============================================
   A SINGLE ENTRY AS ITS OWN PAGE

   Framed exactly like single.php, because a reader arriving here should not
   be able to tell it was built later: header 800px centred, screenshot
   1000px, body 800px, the same 24px gutters and the same 36px white h1.
   Those numbers are single-post.css's, not new ones.

   Prose stays left aligned inside the centred frame. The site centres a
   title and a meta line, never a paragraph.
   ============================================ */

.wl-single { --wl-caution: #F5A524; margin: 0; }

.wl-page-head {
    max-width: 800px;
    margin: 0 auto;
    padding: 48px 24px 0;
    text-align: center;
}

.wl-page-head .wl-eyebrow { margin-bottom: 10px; }

.wl-page-title {
    color: #fff;
    font-size: 36px;
    line-height: 1.2;
    margin: 0 0 20px;
}

.wl-page-sub {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 12px;
    margin: 0 0 20px;
    color: var(--text-secondary);
    font-size: 14px;
}

.wl-page-company { font-size: 14px; color: var(--text-secondary); }
.wl-page-sub .wl-card-status { margin: 0; }

/* The one-line definition. Centred with the header it belongs to, and the
   only centred paragraph on the page. */
.wl-page-lead {
    margin: 0 auto;
    max-width: 62ch;
    font-size: var(--fs-lead);
    line-height: 1.65;
    color: var(--text-primary);
}

.wl-page-shot {
    max-width: 1000px;
    margin: 36px auto 40px;
    padding: 0 24px;
}

.wl-page-shot img {
    width: 100%;
    height: auto;
    display: block;
    border-radius: 12px;
    border: 1px solid var(--border-color);
}

.wl-page-body {
    max-width: 800px;
    margin: 0 auto;
    padding: 0 24px;
}

.wl-h2 {
    color: #fff;
    font-size: 24px;
    line-height: 1.3;
    margin: 44px 0 14px;
}

.wl-h2:first-child { margin-top: 0; }

.wl-prose {
    margin: 0;
    font-size: var(--fs-lead);
    line-height: 1.75;
    color: var(--text-secondary);
}

.wl-prose strong { color: var(--text-primary); }

/* The blocks carry their own label, so they need more room above than a
   headed section does and less below. */
.wl-page-body .wl-block { margin: 32px 0; padding: 18px 22px; }
.wl-page-body .wl-block-body { font-size: var(--fs-lead); line-height: 1.75; }
.wl-page-body .wl-datalist li,
.wl-page-body .wl-list li { font-size: var(--fs-body); line-height: 1.7; margin-bottom: 9px; }
.wl-page-body .wl-meta { margin-top: 40px; }
.wl-page-body .wl-card-foot { margin-top: 28px; }

@media (max-width: 640px) {
    .wl-page-head { padding-top: 32px; }
    .wl-page-title { font-size: 28px; }
    .wl-h2 { font-size: 21px; margin-top: 34px; }
    .wl-page-shot { margin: 28px auto 32px; }
}

/* ============================================
   CLOSING BAND

   The same object as .toad-close on the extension pages: full width, a lit
   hairline across the top, a glow rising from the bottom edge and a faint
   grid masked to a soft ellipse. Those values are page-toad.css's, copied
   rather than imported because that sheet is not loaded here, and a reader
   moving between the two pages should not be able to tell them apart.

   .btn-primary is copied for the same reason: it is defined in page-toad.css
   and page-front.css, never globally, so a button here would otherwise be an
   unstyled link.
   ============================================ */

.wl-close {
    position: relative;
    overflow: hidden;
    background:
        radial-gradient(ellipse 80% 120% at 50% 104%, rgba(0, 217, 255, 0.19) 0%, transparent 66%),
        radial-gradient(ellipse 40% 60% at 50% 100%, rgba(57, 255, 20, 0.07) 0%, transparent 70%),
        linear-gradient(180deg, transparent 0%, var(--bg-header) 100%);
    margin: 72px 0 -40px;
    padding: 76px 24px 96px;
}

.wl-close::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent 0%, var(--primary-accent) 38%, var(--secondary-accent) 62%, transparent 100%);
    opacity: 0.8;
}

.wl-close::after {
    content: '';
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
        linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px);
    background-size: 56px 56px;
    -webkit-mask-image: radial-gradient(ellipse 66% 86% at 50% 52%, #000 0%, transparent 78%);
    mask-image: radial-gradient(ellipse 66% 86% at 50% 52%, #000 0%, transparent 78%);
    pointer-events: none;
}

.wl-close-inner {
    position: relative;
    z-index: 1;
    max-width: 720px;
    margin: 0 auto;
    text-align: center;
}

.wl-close-inner h2 {
    margin: 0 0 14px;
    color: var(--text-heading);
    font-size: 34px;
    letter-spacing: -0.01em;
    line-height: 1.2;
}

.wl-close-inner > p {
    margin: 0 auto 26px;
    line-height: 1.6;
    color: var(--text-secondary);
}

.btn-primary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--primary-accent);
    color: var(--bg-dark);
    padding: 10px 24px;
    border-radius: 6px;
    font-weight: 600;
    font-size: 14px;
    border: none;
    cursor: pointer;
    transition: var(--transition);
    text-decoration: none;
}

.btn-primary:hover {
    background: #00B8D4;
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(0, 217, 255, 0.3);
    text-decoration: none;
    color: var(--bg-dark);
}

.wl-close-points {
    list-style: none;
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 10px 30px;
    margin: 26px 0 0;
    padding: 0;
}

.wl-close-points li {
    position: relative;
    padding-left: 25px;
    font-size: 14px;
    color: var(--text-secondary);
}

/* Drawn from two borders on a rotated box: no icon file, and no glyph a text
   extractor would read as content. */
.wl-close-points li::before {
    content: '';
    position: absolute;
    left: 3px; top: 4px;
    width: 6px; height: 11px;
    border: solid var(--primary-accent);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

/* `.wl-close-inner > p` above already claims every direct-child paragraph in
   this band, and a type-plus-class selector outranks this lone class, so the
   margins here were being discarded: the link sat flush against the three
   points and read as a fourth one. Matching that specificity gives it back the
   separation, plus a little room beneath so it is not pinned to the band. */
.wl-close-inner > p.wl-close-more { margin: 30px 0 10px; font-size: var(--fs-cap); }
.wl-close-more a { color: var(--nav-text); text-decoration: none; }
.wl-close-more a:hover { text-decoration: underline; }

@media (max-width: 560px) {
    .wl-close { padding: 56px 20px 72px; }
    .wl-close-inner h2 { font-size: 26px; }
    .wl-close-points { gap: 10px 20px; }
}

/* Dates under the title, same treatment as .post-meta-dates on a post. */
.wl-page-dates {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 4px 14px;
    margin: 0 0 20px;
    color: var(--text-secondary);
    font-size: 14px;
}

.wl-page-checked::before { content: '\00B7'; margin-right: 14px; }

.wl-page-shotcap {
    margin: 10px 0 0;
    font-size: var(--fs-cap);
    color: var(--text-secondary);
    text-align: center;
}

/* ============================================
   /watchlist/ — the hub

   Framed like the entry page: 800px of centred header, then the cards in a
   column. The card was designed to be read next to others, which is what it
   finally is here.
   ============================================ */

.wl-hub { --wl-caution: #F5A524; margin: 0; }

.wl-hub-head {
    max-width: 800px;
    margin: 0 auto;
    padding: 48px 24px 0;
    text-align: center;
}

.wl-hub-title {
    color: #fff;
    font-size: 36px;
    line-height: 1.2;
    margin: 10px 0 20px;
}

.wl-hub-intro {
    margin: 0 auto;
    max-width: 62ch;
    font-size: var(--fs-lead);
    line-height: 1.65;
    color: var(--text-secondary);
}

.wl-hub-count {
    margin: 18px 0 0;
    font-size: 14px;
    color: var(--text-secondary);
}

.wl-hub-empty {
    max-width: 62ch;
    margin: 32px auto 0;
    padding: 0 24px;
    text-align: center;
    font-size: var(--fs-body);
    line-height: 1.7;
    color: var(--text-secondary);
}

.wl-hub-list {
    max-width: 860px;
    margin: 40px auto 0;
    padding: 0 24px;
}

/* On the hub the title is the way in, so it has to look like one. */
.wl-hub-list .wl-card-title a { color: inherit; text-decoration: none; }
.wl-hub-list .wl-card-title a:hover { color: var(--primary-accent); }

@media (max-width: 640px) {
    .wl-hub-head { padding-top: 32px; }
    .wl-hub-title { font-size: 28px; }
}

/* The filter hides a card without removing it, so the DOM keeps the same text
   it was served with. Matches .ranking-card's own filtered state. */
.wl-card.is-filtered-out { display: none; }

/* The hub tile is a .ranking-card, so the grid is the rankings grid: two
   across, three at 1200px. Only the badge and the one-line summary are ours. */
.wl-badge { background: rgba(245, 165, 36, 0.14); color: var(--wl-caution, #F5A524); }

.wl-tile .ranking-stat-number { font-size: 20px; }

/* ============================================
   THE WATCHING BACKGROUND

   A radar sweep over a grid, with two pings opening out of the centre. The
   metaphor is monitoring rather than surveillance: nothing here is an eye,
   and the sweep is slow enough to read as patience instead of scanning.

   Scoped to .wl-hero so the rankings hero, which shares .hero, is untouched.
   Decorative throughout: no text, aria-hidden on the container, and only
   transform and opacity animate, so it composites on the GPU and never
   triggers layout. The grid is the same 56px cell the TOAD closing band uses,
   so the two read as the same hand.
   ============================================ */

.wl-hero {
    position: relative;
    overflow: hidden;
    isolation: isolate;

    /* When the arm reaches the title, measured from page load.
       Every animation in this block runs the same 14s period and the arm
       crosses the heading at 10.6s into that period, so starting the cycle
       9.1s in puts the pass at 1.5s: late enough to be noticed as movement
       rather than missed as a static state, early enough that nobody waits
       for it. One value, applied to the arm, the title and both pings, so the
       whole composition shifts together and their relative timing is exactly
       what it was. */
    --wl-phase: -9.1s;
}

.wl-watch {
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    overflow: hidden;
    /* Fades out before the copy starts, so nothing competes with the lead. */
    -webkit-mask-image: radial-gradient(ellipse 90% 120% at 72% 42%, #000 0%, transparent 72%);
    mask-image: radial-gradient(ellipse 90% 120% at 72% 42%, #000 0%, transparent 72%);
}

.wl-watch-grid {
    position: absolute;
    inset: -10%;
    background-image:
        linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px),
        linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px);
    background-size: 56px 56px;
}

/* The arm. A conic gradient rotated about the sweep origin, which sits right
   of centre so the hero copy stays on the quiet side of the dial. */
.wl-watch-sweep {
    position: absolute;
    top: 50%;
    left: 72%;
    width: 150vmax;
    height: 150vmax;
    margin: -75vmax 0 0 -75vmax;
    border-radius: 50%;
    background: conic-gradient(
        from 0deg,
        rgba(0, 217, 255, 0.20) 0deg,
        rgba(0, 217, 255, 0.07) 18deg,
        transparent 46deg,
        transparent 360deg
    );
    animation: wl-sweep 14s linear infinite;
    animation-delay: var(--wl-phase, 0s);
    will-change: transform;
}

/* Pings open from the same origin on the sweep's period, so a ring appears to
   be left behind by the arm rather than firing on its own clock. */
.wl-watch-ping {
    position: absolute;
    top: 50%;
    left: 72%;
    width: 18vmax;
    height: 18vmax;
    margin: -9vmax 0 0 -9vmax;
    border: 1px solid rgba(0, 217, 255, 0.5);
    border-radius: 50%;
    opacity: 0;
    animation: wl-ping 14s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
    animation-delay: var(--wl-phase, 0s);
    will-change: transform, opacity;
}

.wl-watch-ping--b { animation-delay: calc(var(--wl-phase, 0s) + 7s); }

@keyframes wl-sweep {
    to { transform: rotate(360deg); }
}

/*
 * The title lights as the arm reaches it.
 *
 * Timed, not triggered: there is no way to ask CSS where a rotating gradient
 * is pointing, so the glow is a second animation of the same 14s period,
 * peaking at the moment the arm's bright edge crosses the heading. The
 * percentages below are measured, not guessed. At 1440px the sweep origin
 * sits at (1037, 264) and the title's text centres on (364, 235), which puts
 * the heading at 272.5 degrees clockwise from the arm's start, or 75.7% of a
 * revolution.
 *
 * The wedge is 46 degrees wide and brightest at its trailing edge, so the
 * heading sees a slow build as the faint front passes and a snap to dark the
 * instant the bright edge clears it. The stops mirror the conic gradient's own
 * alpha: nothing at 46 degrees out, 0.07 at 18, 0.20 at 0.
 *
 * This one animates paint rather than transform, against the rule the rest of
 * this block keeps. The alternative was a duplicate of the heading layered
 * behind it, which would either put the title in the DOM twice or hide it in
 * generated content a screen reader may still announce. One short heading
 * repainting once every fourteen seconds is the cheaper of the two.
 */
.wl-hero h1 {
    animation: wl-title-sweep 14s linear infinite;
    animation-delay: var(--wl-phase, 0s);
}

@keyframes wl-title-sweep {
    0%, 62.9%   { text-shadow: 0 0 10px rgba(0, 217, 255, 0),    0 0 26px rgba(0, 217, 255, 0),    0 0 64px rgba(0, 217, 255, 0); }
    70.7%       { text-shadow: 0 0 10px rgba(0, 217, 255, 0.22), 0 0 26px rgba(0, 217, 255, 0.20), 0 0 64px rgba(0, 217, 255, 0.11); }
    75.7%       { text-shadow: 0 0 10px rgba(0, 217, 255, 0.70), 0 0 26px rgba(0, 217, 255, 0.62), 0 0 64px rgba(0, 217, 255, 0.38); }
    77.4%, 100% { text-shadow: 0 0 10px rgba(0, 217, 255, 0),    0 0 26px rgba(0, 217, 255, 0),    0 0 64px rgba(0, 217, 255, 0); }
}

@keyframes wl-ping {
    0%   { transform: scale(0.35); opacity: 0; }
    8%   { opacity: 0.55; }
    70%  { opacity: 0; }
    100% { transform: scale(3.4); opacity: 0; }
}

/* Asked for stillness, given stillness. The arm parks at an angle so the
   composition still reads as a dial, and the pings are removed rather than
   frozen mid-flight where they would look like stray rings. */
@media (prefers-reduced-motion: reduce) {
    .wl-watch-sweep { animation: none; transform: rotate(-28deg); }
    .wl-watch-ping { display: none; }
    /* The arm has parked, so a title still pulsing would be lighting up for
       nothing. */
    .wl-hero h1 { animation: none; }
}

@media (max-width: 640px) {
    .wl-watch { opacity: 0.7; }
    .wl-watch-sweep, .wl-watch-ping { left: 60%; }
}

/* The status eyebrow is a link that does not look like one. It keeps the
   eyebrow's own colour and weight, and only declares itself on hover and
   focus, so it never competes with the title beneath it. */
.wl-eyebrow-link {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: var(--transition);
}

.wl-eyebrow-link:hover { border-bottom-color: currentColor; }

.wl-eyebrow-link:focus-visible {
    outline: 2px solid var(--primary-accent);
    outline-offset: 3px;
    border-radius: 2px;
}
