/* ============================================================
   Tool shell - the shared design system for tool pages
   ============================================================

   A kit, not a restyle. Nothing in this file targets an element
   or a Bootstrap class, so loading it site-wide changes no
   existing page: it only DEFINES the homepage palette and adds
   `.ts-*` classes that a page opts into.

   That matters because there are roughly 290 tool pages built
   over years by different hands. Restyling `input` or `.btn`
   globally would "fix" a hundred pages and quietly break another
   hundred nobody looked at. A page adopts this deliberately, and
   is verified when it does.

   ------------------------------------------------------------
   THE TOKENS ARE THE POINT OF THE FIRST BLOCK

   The A-to-Z palette lives in home-atoz.css, which only the
   homepage loads - so on a tool page `var(--az-a-1)` resolved to
   nothing and every component fell back to a hard-coded hex.
   Defining them here makes the homepage colours genuinely
   available site-wide, which is what "keep the homepage colour
   combinations" actually requires.

   Values copied exactly from home-atoz.css. If that file changes
   these must change with it - which is why they are quoted with
   their original comments rather than re-picked by eye.
   ------------------------------------------------------------ */

:root {
    /* ---- palette, sampled from the homepage mockup ---- */
    --az-bg:        #fbf9f7;   /* warm off-white page */
    --az-surface:   #ffffff;
    --az-ink:       #10162b;   /* deep navy headings */
    --az-ink-2:     #454d63;   /* body */
    --az-ink-3:     #5f677d;   /* muted, and contrast-checked */
    --az-line:      #e8e6e3;   /* hairline borders */
    --az-line-2:    #f0eeeb;

    /* the A end of the journey */
    --az-a-1:       #5b8def;
    --az-a-2:       #7b5bf0;
    /* the Z end */
    --az-z-1:       #f0655f;
    --az-z-2:       #f89a4d;
    /* the middle of the arc */
    --az-mid:       #c05ad9;

    --az-mint:      #22b06b;   /* trust / success accent */

    /* pastel card grounds */
    --az-c-convert:   #eef1fd;
    --az-c-download:  #eaf7f0;
    --az-c-create:    #fdeeea;
    --az-c-calculate: #e9f2fd;

    --az-r:         14px;
    --az-r-lg:      18px;
    --az-shadow:    0 4px 16px rgba(16, 22, 43, .06);
    --az-shadow-sm: 0 1px 2px rgba(16, 22, 43, .05);

    /* Deeper than --az-z-1, which is a decorative coral: an error
       message has to clear 4.5:1 on white. */
    --az-error:     #c62f2f;
}

/* ============================================================
   The shell
   ============================================================ */

.ts {
    background: var(--az-bg);
    padding: 26px 0 34px;
    color: var(--az-ink-2);
}

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

.ts-shell { max-width: 1120px; margin: 0 auto; padding: 0 16px; }
.ts-shell-narrow { max-width: 860px; margin: 0 auto; padding: 0 16px; }

/* ---- Hero: one h1 and one line saying what the tool does ----

   The reference page leads with a centred title and a single
   plain sentence. The pages being replaced led with an oversized
   default-serif h1 and nothing else, so a visitor had to work out
   from the form what the tool was for. */

.ts-hero { text-align: center; margin-bottom: 22px; }

.ts-hero h1 {
    margin: 0 0 8px;
    font-size: clamp(1.45rem, 3.4vw, 2.05rem);
    line-height: 1.22;
    color: var(--az-ink);
    font-weight: 700;
}

.ts-lede {
    margin: 0 auto;
    max-width: 640px;
    font-size: 1rem;
    color: var(--az-ink-3);
}

/* ---- The tool card ---- */

.ts-card {
    background: var(--az-surface);
    border: 1px solid var(--az-line);
    border-radius: var(--az-r-lg);
    box-shadow: var(--az-shadow);
    padding: 20px;
}

.ts-card + .ts-card { margin-top: 18px; }

/* ---- The panel row ------------------------------------------

   The reference lays a conversion out as a row of equal panels -
   input, options, action, result - so the flow reads left to
   right and the eye never has to hunt for the button. That is
   the single biggest difference from the pages being replaced,
   where the button could be anywhere.

   Panels wrap on a narrow screen rather than scrolling. */

.ts-flow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 14px;
    align-items: stretch;
}

.ts-panel {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
    padding: 16px;
    border-radius: var(--az-r);
    background: var(--az-c-convert);
    border: 1px dashed #c9d4f5;
}

.ts-panel-plain {
    background: var(--az-line-2);
    border: 1px solid var(--az-line);
}

.ts-panel-title {
    margin: 0;
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--az-ink-3);
}

/* The action panel: the one thing on the page a visitor is
   looking for. */
.ts-panel-action {
    background: linear-gradient(135deg, var(--az-a-1), var(--az-a-2));
    border: 0;
    align-items: center;
    justify-content: center;
}

/* ---- Fields ---- */

.ts-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }

.ts-label {
    font-size: .84rem;
    font-weight: 600;
    color: var(--az-ink);
}

.ts-hint { font-size: .82rem; color: var(--az-ink-3); margin: 0; }

.ts-input,
.ts-textarea,
.ts-select {
    width: 100%;
    padding: 11px 13px;
    border: 1px solid var(--az-line);
    border-radius: var(--az-r);
    background: var(--az-surface);
    color: var(--az-ink);
    font: inherit;
    font-size: .96rem;
    line-height: 1.5;
}

.ts-textarea { min-height: 150px; resize: vertical; }
.ts-textarea-tall { min-height: 230px; }

.ts-input:focus-visible,
.ts-textarea:focus-visible,
.ts-select:focus-visible {
    outline: 3px solid var(--az-a-2);
    outline-offset: 1px;
    border-color: var(--az-a-2);
}

.ts-input::placeholder,
.ts-textarea::placeholder { color: #9aa1b4; }

/* ---- Buttons ---- */

.ts-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 46px;
    padding: 0 20px;
    border: 1px solid var(--az-line);
    border-radius: 999px;
    background: var(--az-surface);
    color: var(--az-ink-2);
    font: inherit;
    font-size: .95rem;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    transition: border-color .15s ease, color .15s ease, filter .15s ease;
}

.ts-btn:hover { border-color: var(--az-a-2); color: var(--az-ink); }

.ts-btn:focus-visible {
    outline: 3px solid var(--az-a-2);
    outline-offset: 2px;
}

.ts-btn:disabled { opacity: .6; cursor: not-allowed; }

.ts-btn-primary {
    border: 0;
    background: linear-gradient(135deg, var(--az-a-1), var(--az-a-2));
    color: #fff;
    font-weight: 700;
    box-shadow: 0 6px 18px rgba(91, 141, 239, .28);
}

.ts-btn-primary:hover { filter: brightness(1.06); color: #fff; }

/* Inside the action panel the button IS the panel. */
.ts-panel-action .ts-btn-primary {
    width: 100%;
    min-height: 64px;
    font-size: 1.05rem;
    box-shadow: none;
    background: transparent;
}

.ts-btn-ghost { background: transparent; }

.ts-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.ts-actions-center { justify-content: center; }

/* ---- Result ---- */

.ts-result {
    border-radius: var(--az-r);
    border: 1px dashed #c9d4f5;
    background: var(--az-c-convert);
    padding: 16px;
    min-height: 120px;
}

.ts-result-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 120px;
    color: var(--az-ink-3);
    font-size: .92rem;
    text-align: center;
}

.ts-result-ok {
    border-style: solid;
    border-color: rgba(34, 176, 107, .4);
    background: rgba(34, 176, 107, .08);
}

.ts-result-bad {
    border-style: solid;
    border-color: rgba(198, 47, 47, .4);
    background: rgba(198, 47, 47, .06);
}

/* Numbers a tool produces - counts, sizes, totals. */
.ts-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 12px;
}

.ts-stat {
    padding: 14px 12px;
    text-align: center;
    border-radius: var(--az-r);
    background: var(--az-surface);
    border: 1px solid var(--az-line);
}

.ts-stat b {
    display: block;
    font-size: 1.5rem;
    line-height: 1.1;
    color: var(--az-ink);
    font-variant-numeric: tabular-nums;
}

.ts-stat span {
    font-size: .74rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--az-ink-3);
}

/* ---- Option chips (the reference's format picker) ---- */

.ts-options { display: flex; flex-wrap: wrap; gap: 7px; }

.ts-option {
    min-height: 38px;
    padding: 0 14px;
    border: 1px solid var(--az-line);
    border-radius: 9px;
    background: var(--az-surface);
    color: var(--az-ink-2);
    font: inherit;
    font-size: .84rem;
    font-weight: 600;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
}

.ts-option:hover { border-color: var(--az-a-2); }

/* Selected is colour AND weight AND a border, never colour alone. */
.ts-option.is-active {
    background: var(--az-z-2);
    border-color: var(--az-z-2);
    color: #fff;
}

.ts-option:focus-visible { outline: 3px solid var(--az-a-2); outline-offset: 2px; }

/* ---- Status line ---- */

.ts-status {
    margin: 12px 0 0;
    min-height: 1.3em;
    font-size: .93rem;
    font-weight: 600;
}

.ts-status.is-error   { color: var(--az-error); }
.ts-status.is-success { color: #0d5c37; }
.ts-status.is-info    { color: var(--az-ink-2); font-weight: 500; }

/* ---- Notes and disclosures ---- */

.ts-note {
    /* Block, not flex. As a flex container every inline <code>
       in the prose became a flex item of its own, which broke the
       sentence into a row of fragments with gaps between them. */
    display: block;
    padding: 11px 13px;
    border-radius: 0 var(--az-r) var(--az-r) 0;
    border-left: 3px solid var(--az-a-1);
    background: rgba(91, 141, 239, .07);
    font-size: .88rem;
    color: var(--az-ink-2);
}

.ts-note-warn {
    border-left-color: var(--az-z-2);
    background: rgba(248, 154, 77, .1);
}

.ts-visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ============================================================
   Responsive
   ============================================================ */

@media (max-width: 700px) {
    .ts { padding: 18px 0 26px; }
    .ts-card { padding: 16px; border-radius: var(--az-r); }
    .ts-flow { grid-template-columns: 1fr; }
    .ts-panel-action .ts-btn-primary { min-height: 54px; }
    .ts-actions .ts-btn { flex: 1 1 auto; }
}

@media (max-width: 360px) {
    .ts-shell, .ts-shell-narrow { padding: 0 10px; }
    .ts-card { padding: 14px 12px; }
}

@media (prefers-reduced-motion: reduce) {
    .ts-btn, .ts-option { transition-duration: .001ms !important; }
}

/* ---- Two-panel flow --------------------------------------------

   The reference converts images, so its four panels hold a file
   chip, a format picker, a button and a thumbnail - all happy at
   210px. A text tool's panels hold textareas, and four of those
   across 1120px gives each about 250px, which is narrower than
   the box it replaces. Two panels, input and result, side by
   side, with the controls in a strip beneath. */

.ts-flow-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }

.ts-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: flex-end;
    justify-content: space-between;
    margin-top: 16px;
}

.ts-strip > * { min-width: 0; }

.ts-checks { display: flex; flex-wrap: wrap; gap: 8px 18px; }

.ts-check {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: .87rem;
    color: var(--az-ink-2);
    cursor: pointer;
}

.ts-check input { width: 16px; height: 16px; accent-color: var(--az-a-2); cursor: pointer; }
.ts-check input:focus-visible { outline: 3px solid var(--az-a-2); outline-offset: 2px; }

/* The result textarea reads as an output, not another thing to
   fill in - it stays selectable and copyable but is not typed in. */
.ts-textarea-out { background: var(--az-surface); }

.ts-stats-inline { margin-top: 16px; }

@media (max-width: 700px) {
    .ts-flow-2 { grid-template-columns: 1fr; }
    .ts-strip { flex-direction: column; align-items: stretch; }
}

/* ---- Per-item result list (the push tester's per-token rows) ---- */

.ts-list { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 8px; }

.ts-list:empty { display: none; }

.pn-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
    padding: 11px 13px;
    border-radius: var(--az-r);
    border: 1px solid var(--az-line);
    background: var(--az-surface);
    font-size: .89rem;
}

/* The outcome is a word, not only a colour. */
.pn-badge {
    flex: none;
    min-width: 58px;
    text-align: center;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
}

.pn-row.is-ok  { border-color: rgba(34, 176, 107, .45); background: rgba(34, 176, 107, .07); }
.pn-row.is-bad { border-color: rgba(198, 47, 47, .4);  background: rgba(198, 47, 47, .05); }

.pn-row.is-ok  .pn-badge { background: rgba(34, 176, 107, .18); color: #0d5c37; }
.pn-row.is-bad .pn-badge { background: rgba(198, 47, 47, .12);  color: var(--az-error); }

.pn-token {
    flex: none;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .82rem;
    color: var(--az-ink-3);
}

/* The message is the point, so it takes the room and wraps. */
.pn-detail { flex: 1 1 240px; min-width: 0; color: var(--az-ink-2); }

/* ---- Inline code --------------------------------------------

   Scoped under .ts, so it reaches only pages that opted into this
   kit. The site stylesheet gives `code` a display and colour that
   breaks it out of a sentence, which turned the notes on these
   pages into a stack of fragments. */

.ts code {
    display: inline;
    padding: 1px 6px;
    border-radius: 6px;
    background: rgba(16, 22, 43, .06);
    color: var(--az-ink);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .88em;
    /* Long identifiers may wrap rather than shove the line open. */
    overflow-wrap: anywhere;
}

/* An ad placement inside the tool shell - spaced off the card so it
   reads as a separate block rather than part of the tool. */
.ts-adslot { margin-top: 18px; }

/* ============================================================
   FILE MODE - the optional second tab
   ============================================================

   Only two pages use it (css-minify, javascript-obfuscator), but
   both needed the same thing and both had built it by hand out of
   Bootstrap tabs and a table with no result column. Everything
   here is inside the .ts kit, so no page that has not opted in is
   touched.
   ============================================================ */

.ts-tabs {
    display: flex;
    gap: 4px;
    margin: 0 auto 14px;
    padding: 4px;
    border-radius: 999px;
    background: rgba(16, 22, 43, .05);
    width: fit-content;
}

.ts-tab {
    border: 0;
    background: transparent;
    padding: 9px 20px;
    border-radius: 999px;
    font: inherit;
    font-weight: 600;
    font-size: .92rem;
    color: var(--az-ink-2);
    cursor: pointer;
    /* A minimum height rather than a fixed one, so the label still
       fits when the browser's text size is turned up. */
    min-height: 40px;
    transition: background .15s ease, color .15s ease;
}

.ts-tab:hover { color: var(--az-ink); }

/* THE CHOSEN TAB IS NOT MARKED BY COLOUR ALONE - it carries the
   raised surface and the shadow as well, so it is still the
   obvious one in a high-contrast or monochrome rendering. */
.ts-tab.is-chosen {
    background: var(--az-surface);
    color: var(--az-ink);
    box-shadow: var(--az-shadow);
}

.ts-tab:focus-visible {
    outline: 3px solid var(--az-a-2);
    outline-offset: 2px;
}

.ts-card.is-hidden { display: none; }

.ts-file {
    display: block;
    width: 100%;
    padding: 14px;
    border: 2px dashed var(--az-line-2);
    border-radius: var(--az-r);
    background: var(--az-bg);
    font: inherit;
    color: var(--az-ink-2);
    cursor: pointer;
}

.ts-file:focus-visible {
    outline: 3px solid var(--az-a-2);
    outline-offset: 2px;
}

/* The table scrolls inside its own box rather than pushing the
   page sideways - a long file name on a phone would otherwise
   give the whole document a horizontal scrollbar. */
.ts-table-wrap { overflow-x: auto; margin-top: 16px; }

.ts-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .92rem;
}

.ts-table th,
.ts-table td {
    text-align: left;
    padding: 10px 12px;
    border-bottom: 1px solid var(--az-line);
    vertical-align: middle;
}

.ts-table th {
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--az-ink-3);
}

.ts-table td:first-child {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    overflow-wrap: anywhere;
}

/* Outcome is words in the cell, never a colour on its own. */
.ts-cell-ok { color: var(--az-ink-2); }
.ts-cell-error { color: var(--az-error); font-weight: 600; }

.ts-btn-small { padding: 6px 14px; font-size: .85rem; min-height: 36px; }

/* ============================================================
   ARCHIVE PREVIEW - the zip extractor
   ============================================================

   Text entries out of an archive are shown here rather than
   downloaded. The content is written with textContent, never
   innerHTML: an HTML file inside a zip somebody was sent is the
   least trustworthy input on this site.
   ============================================================ */

.ts-preview {
    margin-top: 18px;
    border: 1px solid var(--az-line);
    border-radius: var(--az-r);
    background: var(--az-bg);
    overflow: hidden;
}

.ts-preview-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding: 10px 14px;
    border-bottom: 1px solid var(--az-line);
    background: var(--az-surface);
}

.ts-preview-head .ts-panel-title { margin: 0; }

/* Scrolls in both directions inside its own box - a minified
   line out of an archive is thousands of characters wide and
   would otherwise take the whole page sideways with it. */
.ts-preview-body {
    margin: 0;
    padding: 14px;
    max-height: 420px;
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .85rem;
    line-height: 1.55;
    color: var(--az-ink);
    white-space: pre;
    tab-size: 4;
}

/* The buttons in a table row wrap rather than forcing the
   column wider on a narrow screen. */
.ze-actions {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

/* ============================================================
   H BATCH ADDITIONS
   ============================================================ */

/* is-hidden was scoped to .ts-card only, but the half-life tool
   switches plain panels with it too. Kept inside .ts so it can
   never collide with a utility class on the marketing site. */
.ts .is-hidden { display: none; }

/* The list of problems the redirect generator refuses on. Not a
   bare <ul> rule - the site stylesheet already styles those. */
.ts-problems {
    margin: 4px 0 0;
    padding-left: 20px;
    color: var(--az-error);
    font-size: .9rem;
    line-height: 1.6;
}

.ts-problems li { margin-bottom: 4px; }

/* The formula a calculator actually used, marked in the table.
   NOT by colour alone: it also carries a left border and bolder
   text, so it survives a monochrome or high-contrast rendering. */
.ts-table tr.is-chosen-row td {
    background: rgba(123, 91, 240, .06);
    font-weight: 600;
    box-shadow: inset 3px 0 0 var(--az-a-2);
}

/* ============================================================
   O BATCH ADDITIONS
   ============================================================

   All scoped inside .ts, so nothing here can reach a page that
   has not opted into the kit.
   ============================================================ */

/* A card that carries a warning the visitor must read BEFORE
   using the tool - the TOTP secret notice and the ovulation
   disclaimer. Amber edge plus a heavier left border, so it is
   distinguished by more than colour. */
.ts-card-warn {
    border-color: var(--az-z-2);
    border-left-width: 4px;
    background: rgba(248, 154, 77, .05);
}

.ts-card-warn p { margin: 0 0 10px; line-height: 1.65; }

.ts-flow-3 {
    display: grid;
    gap: 16px;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 760px) {
    .ts-flow-3 { grid-template-columns: 1fr; }
}

/* The stopwatch and timer reading. Tabular figures so the digits
   do not jitter as they change - without it the whole number
   shifts sideways every tenth of a second and is unreadable. */
.ts-clock {
    margin: 0 0 18px;
    text-align: center;
    font-size: clamp(2.6rem, 12vw, 4.5rem);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: .01em;
    color: var(--az-ink);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

/* A number and its unit, side by side, where the unit select
   should not stretch. */
.ts-pair { display: flex; gap: 8px; }
.ts-pair .ts-input { flex: 1 1 auto; min-width: 0; }
.ts-unit { flex: 0 0 auto; width: auto; min-width: 130px; }

.ts-required {
    font-weight: 500;
    font-size: .78rem;
    color: var(--az-ink-3);
    text-transform: uppercase;
    letter-spacing: .03em;
    margin-left: 6px;
}

/* Advisory rather than blocking, so amber and not red - the
   distinction matters when a tool reports both at once. */
.ts-warnings {
    margin: 4px 0 0;
    padding-left: 20px;
    color: var(--az-ink-2);
    font-size: .9rem;
    line-height: 1.6;
}

.ts-warnings li { margin-bottom: 4px; }

.ts-notepad { min-height: 380px; line-height: 1.7; }

/* A destructive or stop action. Still a real button with a
   visible focus ring; only the colour differs. */
.ts-btn-danger {
    background: var(--az-error);
    border-color: var(--az-error);
    color: #fff;
}

.ts-btn-danger:hover { filter: brightness(.94); }

/* ---------- one-time password ---------- */

.otp-code {
    margin: 0 0 12px;
    text-align: center;
    font-size: clamp(2.2rem, 10vw, 3.4rem);
    font-weight: 700;
    letter-spacing: .08em;
    color: var(--az-ink);
    font-variant-numeric: tabular-nums;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

.otp-countdown { margin-bottom: 8px; }

.otp-bar {
    height: 6px;
    border-radius: 999px;
    background: var(--az-line);
    overflow: hidden;
}

.otp-bar span {
    display: block;
    height: 100%;
    width: 100%;
    background: var(--az-a-2);
    /* Linear, and short enough that it never lags the number it
       is describing. */
    transition: width .95s linear;
}

/* Running low is signalled by colour AND by the seconds count
   beneath it, which is the accessible half of the pair. */
.otp-bar span.is-low { background: var(--az-error); }

@media (prefers-reduced-motion: reduce) {
    .otp-bar span { transition: none; }
}

/* ---------- open graph preview ---------- */

.og-preview {
    border: 1px solid var(--az-line);
    border-radius: var(--az-r);
    overflow: hidden;
    background: var(--az-surface);
    max-width: 520px;
}

.og-preview-image {
    aspect-ratio: 1200 / 630;
    background: var(--az-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--az-ink-3);
    font-size: .85rem;
    text-align: center;
    padding: 8px;
}

.og-preview-image img { width: 100%; height: 100%; object-fit: cover; display: block; }

.og-preview-body { padding: 12px 14px; }

.og-preview-host {
    margin: 0 0 4px;
    font-size: .72rem;
    letter-spacing: .04em;
    color: var(--az-ink-3);
}

.og-preview-title {
    margin: 0 0 4px;
    font-weight: 600;
    color: var(--az-ink);
    /* Two lines then an ellipsis, which is roughly what the
       platforms do - and the page says it is only roughly. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.og-preview-description {
    margin: 0;
    font-size: .88rem;
    color: var(--az-ink-2);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* ---------- timer finished ---------- */

.ts-card.is-finished { border-color: var(--az-a-2); }

.ts-card.is-finished .ts-clock {
    color: var(--az-a-2);
    animation: ts-pulse 1s ease-in-out 3;
}

@keyframes ts-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .45; }
}

/* Honoured by the page too, which skips adding is-finished
   entirely where reduced motion is asked for - belt and braces,
   because the animation is the point of the class. */
@media (prefers-reduced-motion: reduce) {
    .ts-card.is-finished .ts-clock { animation: none; }
}

.ts kbd {
    display: inline-block;
    padding: 1px 6px;
    border: 1px solid var(--az-line-2);
    border-bottom-width: 2px;
    border-radius: 5px;
    background: var(--az-bg);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .82em;
    color: var(--az-ink);
}
