/* =============================================================================
   JOKE — the property's own components
   -----------------------------------------------------------------------------
   Everything here is drawn from the house tokens in assets/css/site.css, so the
   dark edition needs nothing of its own: assets/css/dark.css re-points --ink,
   --paper, --line and the rest under html[data-dark] and every rule below
   follows. The one thing this file must never carry is a literal white or a
   literal near-black on a SURFACE — that is the single way a component survives
   the paper edition and blanks out in the dark one.

   The category hues are the exception, and they are set from script.js rather
   than from here: each category carries two values, a screen colour for the
   dark ground and a print colour for the paper, and the engine writes the right
   one into --jk-hue. See the note on hue() in script.js.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   THE TYPEWRITER CARET
   The block cursor belongs to whatever line is mid-sentence and to nothing
   else, so it is drawn by the class the typewriter adds and removes rather
   than by the element. Reduced motion gets no caret at all — the text is
   already whole there, so a blinking block would be pointing at nothing.
   -------------------------------------------------------------------------- */
.joke-text { color: var(--ink-77); }
.joke-text.is-typing::after {
    content: '\258C';
    color: var(--accent);
    animation: jk-caret 1s steps(1) infinite;
    margin-left: .05em;
}
@keyframes jk-caret { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
    .joke-text.is-typing::after { display: none; }
}

/* -----------------------------------------------------------------------------
   THE LIVE JOKE, in the hero
   -------------------------------------------------------------------------- */
.jkhero {
    border: 1px solid var(--line);
    border-left: 2px solid var(--accent);
    border-radius: 14px;
    background: var(--paper);
    padding: 1.4rem 1.5rem 1.15rem;
    margin-top: 2rem;
    max-width: 46rem;
}
.jkhero__tag {
    display: flex; align-items: center; gap: .5rem;
    font-size: .625rem; font-weight: 700; letter-spacing: .2em;
    text-transform: uppercase; color: var(--ink-55); margin: 0 0 .8rem;
}
.jkhero__dot {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--accent); flex: 0 0 auto;
}
/* min-height holds two lines before a word of the joke exists. Without it the
   hero grows by the height of the joke the moment the typewriter starts, and
   everything under it steps down the page while the reader is reading. */
.jkhero__joke {
    font-size: 1.18rem; line-height: 1.55; color: var(--ink);
    margin: 0; min-height: 3.4em;
}
@media (max-width: 640px) { .jkhero__joke { font-size: 1.05rem; min-height: 4.6em; } }
.jkhero__acts { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1rem; }

/* -----------------------------------------------------------------------------
   THE VAULT — one card per category

   minmax(0, 1fr) rather than 1fr: a 1fr track grows to its content's
   min-content width, so a single unwrappable joke title would set the width of
   every other column in the grid and push the page sideways.
   -------------------------------------------------------------------------- */
.vault {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
    gap: 12px; margin-top: 1.4rem;
}
.cat {
    border: 1px solid var(--line);
    border-left: 2px solid var(--jk-hue, var(--accent));
    border-radius: 12px;
    background: var(--paper);
    padding: 1rem 1.1rem 1rem;
    display: flex; flex-direction: column; gap: .55rem;
    text-align: left; font: inherit; cursor: pointer;
    transition: border-color .2s var(--ease), transform .2s var(--ease);
}
.cat:hover { border-color: var(--ink); border-left-color: var(--jk-hue, var(--accent)); }
.cat:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cat__head { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.cat__icon { font-size: 1.55rem; line-height: 1; }
.cat__badge {
    font-size: .58rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
    color: var(--jk-hue, var(--accent));
    border: 1px solid var(--line); border-radius: 999px; padding: .2rem .55rem;
    white-space: nowrap;
}
.cat__n { font-size: 1rem; font-weight: 600; color: var(--ink); margin: 0; line-height: 1.3; }
.cat__d { font-size: .78rem; color: var(--ink-55); line-height: 1.45; margin: 0; }
.cat__foot {
    margin-top: auto; padding-top: .5rem;
    display: flex; justify-content: space-between; align-items: baseline; gap: .6rem;
    font-size: .72rem; color: var(--muted); font-variant-numeric: tabular-nums;
}
.cat__go { color: var(--jk-hue, var(--accent)); font-weight: 600; }

/* -----------------------------------------------------------------------------
   A JOKE, as a row — in the sheet and in the search results
   -------------------------------------------------------------------------- */
.jk {
    display: flex; gap: .85rem; align-items: flex-start;
    border: 1px solid var(--line-soft); border-radius: 10px;
    padding: .8rem .9rem; background: var(--paper);
}
.jk + .jk { margin-top: .5rem; }
.jk.is-hit { border-color: var(--jk-hue, var(--accent)); }
.jk__n {
    flex: 0 0 auto; width: 1.6rem;
    font-size: .68rem; font-weight: 700; letter-spacing: .06em;
    color: var(--muted); font-variant-numeric: tabular-nums; padding-top: .22rem;
}
.jk__b { min-width: 0; flex: 1 1 auto; }
.jk__t { font-size: .93rem; line-height: 1.55; margin: 0; }
.jk__from {
    display: block; margin-top: .35rem;
    font-size: .62rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
    color: var(--jk-hue, var(--accent));
}
.jk__copy {
    flex: 0 0 auto; font: inherit; font-size: .68rem; font-weight: 700;
    letter-spacing: .12em; text-transform: uppercase;
    color: var(--ink-55); background: transparent;
    border: 1px solid var(--line); border-radius: 999px;
    padding: .35rem .7rem; cursor: pointer; min-height: 32px;
    transition: border-color .2s var(--ease), color .2s var(--ease);
}
.jk__copy:hover { border-color: var(--ink); color: var(--ink); }
.jk__copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 560px) {
    .jk { flex-wrap: wrap; }
    .jk__copy { margin-left: auto; }
}

/* -----------------------------------------------------------------------------
   THE READING SHEET

   A category is twelve jokes, which is more than a band wants and exactly what
   a sheet is for. It is a dialog: scrim, panel, focus trap, Escape — the same
   shape the menu uses, so the two behave alike.
   -------------------------------------------------------------------------- */
.sheet[hidden] { display: none; }
.sheet { position: fixed; inset: 0; z-index: 120; }
.sheet__scrim {
    position: absolute; inset: 0;
    background: rgba(12, 17, 22, .55);
    opacity: 0; transition: opacity .28s var(--ease);
}
.sheet.is-open .sheet__scrim { opacity: 1; }
.sheet__panel {
    position: absolute; inset: auto 0 0; margin: 0 auto;
    width: min(100%, 46rem); max-height: 88vh;
    display: flex; flex-direction: column;
    background: var(--paper);
    border: 1px solid var(--line); border-bottom: 0;
    border-radius: 16px 16px 0 0;
    transform: translateY(14px); opacity: 0;
    transition: transform .3s var(--ease), opacity .3s var(--ease);
}
.sheet.is-open .sheet__panel { transform: none; opacity: 1; }
@media (min-width: 760px) {
    .sheet__panel {
        inset: 50% 0 auto; transform: translateY(calc(-50% + 14px));
        border-bottom: 1px solid var(--line); border-radius: 16px;
        max-height: 82vh;
    }
    .sheet.is-open .sheet__panel { transform: translateY(-50%); }
}
.sheet__head {
    display: flex; align-items: flex-start; gap: .9rem;
    padding: 1rem 1.15rem; border-bottom: 1px solid var(--line);
}
.sheet__icon { font-size: 1.7rem; line-height: 1; flex: 0 0 auto; }
.sheet__ttl { margin: 0 auto 0 0; min-width: 0; }
.sheet__ttl b { display: block; font-size: 1.05rem; font-weight: 600; color: var(--jk-hue, var(--ink)); }
.sheet__ttl span { display: block; font-size: .74rem; color: var(--ink-55); margin-top: .15rem; }
.sheet__x {
    flex: 0 0 auto; width: 34px; height: 34px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; color: var(--ink-55);
    border: 1px solid var(--line); border-radius: 9px; cursor: pointer;
}
.sheet__x:hover { border-color: var(--ink); color: var(--ink); }
.sheet__x svg { width: 15px; height: 15px; }
.sheet__body { padding: 1rem 1.15rem; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.sheet__foot {
    display: flex; flex-wrap: wrap; gap: .55rem; align-items: center;
    padding: .8rem 1.15rem; border-top: 1px solid var(--line);
}
.sheet__note {
    margin: 0 auto 0 0; font-size: .68rem; font-weight: 700;
    letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
}

/* -----------------------------------------------------------------------------
   FIND A JOKE
   -------------------------------------------------------------------------- */
.find { display: grid; gap: .8rem; margin-top: 1.2rem; }
.find__row { display: flex; gap: .55rem; flex-wrap: wrap; }
.find__row .field { flex: 1 1 18rem; min-width: 0; }
.find__count {
    margin: 0; font-size: .68rem; font-weight: 700;
    letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
}
.find__out { margin: 0; }

/* -----------------------------------------------------------------------------
   THE SUBMISSION FORM
   -------------------------------------------------------------------------- */
.give { display: grid; gap: .9rem; margin-top: 1.2rem; max-width: 40rem; }
.give__two { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: .8rem; }
@media (max-width: 560px) { .give__two { grid-template-columns: minmax(0, 1fr); } }

/* 16px and nothing smaller on a touch pointer: Safari zooms the page for a
   focused field under that, and a zoomed page carries the fixed header off the
   top of the screen. Matched on pointer, not on width — a narrow window on a
   desktop is not a phone. */
@media (pointer: coarse) {
    .field, .menu__q { font-size: 16px; }
}

/* -----------------------------------------------------------------------------
   THE HERO'S TWO COLUMNS

   .hero__in is 46rem in the house sheet and stays that on a phone; the poster
   only earns a column of its own once there is one to spare. minmax(0, 1fr) on
   the text track, or a long unbroken line in a joke sets the width of the whole
   grid and pushes the document sideways.
   -------------------------------------------------------------------------- */
@media (min-width: 900px) {
    .hero__in--plate { max-width: 62rem; }
    .hero__grid { display: grid; grid-template-columns: minmax(0, 1fr) 260px; gap: 2.6rem; align-items: start; }
}

/* The property's own poster, from the neon build. It is not inverted for the
   paper edition and should not be: it is an artwork with a black ground rather
   than a diagram, and inverting it turns the joker's face inside out. A
   hairline and a radius are enough to make a dark plate read as deliberate on
   white paper. */
.plate { margin: 2rem 0 0; }
.plate img {
    display: block; width: 100%; height: auto;
    border: 1px solid var(--line); border-radius: 12px;
}
.plate figcaption {
    margin-top: .55rem; font-size: .625rem; font-weight: 700;
    letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
}
@media (min-width: 900px) { .plate { margin-top: .35rem; } }

/* =============================================================================
   THE LAB — the regulator, the engine and the meter

   All of it on the house tokens, and the five band colours are the ONE place
   this property is allowed a semantic hue. They are the house's own semantic
   tokens rather than five new colours: --taken for flat, --unsure for a smile,
   --info for a laugh, --free for a real one, and the accent for the good stuff.
   Those four already carry a measured contrast in both editions, which is four
   fewer colours to get wrong.
   ========================================================================== */
.jkhero__src {
    margin: .55rem 0 0; font-size: .625rem; font-weight: 700;
    letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
}
.labstat {
    margin: .8rem 0 0; font-size: .68rem; font-weight: 600;
    letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}

.lab {
    display: grid; gap: 12px; margin-top: 1.6rem;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}
.lab__box {
    border: 1px solid var(--line); border-left: 2px solid var(--accent);
    border-radius: 12px; background: var(--paper); padding: 1.1rem 1.15rem 1.2rem;
    display: flex; flex-direction: column; gap: .6rem; min-width: 0;
}
.lab__h {
    margin: 0; font-size: .625rem; font-weight: 700; letter-spacing: .2em;
    text-transform: uppercase; color: var(--ink-55);
}
.lab__blurb { margin: 0; font-size: .92rem; color: var(--ink); font-weight: 500; }
.lab__row { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
.lab__row .field { flex: 1 1 10rem; min-width: 0; }
.lab__out {
    margin: .3rem 0 0; font-size: 1.02rem; line-height: 1.55; color: var(--ink);
    min-height: 4.2em; border-left: 2px solid var(--jk-hue, var(--accent));
    padding-left: .8rem;
}
.lab__src {
    margin: 0; font-size: .625rem; font-weight: 700;
    letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
}

/* ------------------------------------------------------------- the regulator
   A segmented control, and exactly one segment may be lit. The invariant is
   worth keeping in mind here for the same reason it was worth keeping on the
   homepage's orb selector: two lit segments is the bug this shape produces, and
   it produces it by matching on a substring instead of on an identity. */
.reg { display: flex; flex-wrap: wrap; gap: .3rem; }
.reg__b {
    flex: 1 1 auto; font: inherit; font-size: .68rem; font-weight: 700;
    letter-spacing: .1em; text-transform: uppercase;
    padding: .5rem .5rem; border: 1px solid var(--line); border-radius: 8px;
    background: transparent; color: var(--ink-55); cursor: pointer; min-height: 34px;
    transition: border-color .2s var(--ease), background .2s var(--ease), color .2s var(--ease);
}
.reg__b:hover { border-color: var(--ink); color: var(--ink); }
.reg__b:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.reg__b[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* ------------------------------------------------------------- the readings */
.jk__acts { display: flex; align-items: center; gap: .4rem; flex: 0 0 auto; }
.jk__meta {
    margin: .3rem 0 0; display: flex; flex-wrap: wrap; gap: .3rem .7rem;
    font-size: .58rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
}
.jk__origin { color: var(--muted); }
.jk__origin.is-built { color: var(--jk-hue, var(--accent)); }
.jk__from { color: var(--jk-hue, var(--accent)); }

.jk__score {
    font: inherit; font-size: .72rem; font-weight: 700; font-variant-numeric: tabular-nums;
    min-width: 34px; min-height: 32px; padding: .25rem .5rem;
    border: 1px solid var(--line); border-radius: 999px;
    background: transparent; color: var(--ink-55); cursor: pointer;
}
.jk__score:hover { border-color: var(--ink); color: var(--ink); }
.jk__score:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The five bands, on the house's own semantic tokens. */
.is-flat  { color: var(--taken)  !important; border-color: var(--taken); }
.is-smile { color: var(--unsure) !important; border-color: var(--unsure); }
.is-laugh { color: var(--info)   !important; border-color: var(--info); }
.is-real  { color: var(--free)   !important; border-color: var(--free); }
.is-gold  { color: var(--accent) !important; border-color: var(--accent); }

/* ----------------------------------------------------------------- the meter */
.mtr {
    margin-top: .6rem; padding: .7rem .8rem; border-radius: 9px;
    border: 1px solid var(--line-soft); background: var(--tint);
    display: grid; gap: .3rem;
}
.mtr__r { display: grid; grid-template-columns: 6.4rem minmax(0, 1fr) 3.1rem; gap: .6rem; align-items: center; }
.mtr__l { font-size: .62rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-55); }
.mtr__bar { height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; }
.mtr__bar i { display: block; height: 100%; background: var(--ink); border-radius: 999px; }
.mtr__r.is-penalty .mtr__bar i { background: var(--taken); }
.mtr__v {
    font-size: .66rem; font-weight: 700; color: var(--ink-55);
    font-variant-numeric: tabular-nums; text-align: right;
}
.mtr__foot { margin: .35rem 0 0; font-size: .7rem; color: var(--muted); line-height: 1.5; }
@media (max-width: 520px) {
    .mtr__r { grid-template-columns: 5.2rem minmax(0, 1fr) 2.8rem; gap: .4rem; }
    .mtr__l { font-size: .56rem; letter-spacing: .06em; }
}

.give__reading {
    margin: .4rem 0 0; font-size: .74rem; font-weight: 700;
    letter-spacing: .04em;
}

/* The sheet can hold several hundred rows now, so it grows a page at a time. */
.jkmore { margin: 1rem auto 0; display: block; }

/* =============================================================================
   THE LANGUAGE TOGGLE

   Two segments, one lit, in the sheet head. Same shape as the regulator and the
   edition pill, because a third control shape on one page is one too many.
   ========================================================================== */
.lang { display: flex; gap: .25rem; flex: 0 0 auto; align-self: center; }
.lang[hidden] { display: none; }
.lseg {
    font: inherit; font-size: .66rem; font-weight: 700; letter-spacing: .04em;
    padding: .34rem .6rem; min-height: 30px;
    border: 1px solid var(--line); border-radius: 999px;
    background: transparent; color: var(--ink-55); cursor: pointer;
    transition: border-color .2s var(--ease), background .2s var(--ease), color .2s var(--ease);
}
.lseg:hover { border-color: var(--ink); color: var(--ink); }
.lseg:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lseg[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* THE NATIVE LINE.

   DM Sans covers Latin and Latin-Extended and nothing else, so eight of these
   twenty languages — Russian, Greek, Hebrew, Arabic, Persian, Yiddish, Hindi,
   Korean, Japanese, Mandarin — would fall through to whatever the browser
   picked, which on a bad day is a row of boxes. The stack below names the
   system faces that actually ship with the platforms this site is read on, and
   the generic families at the end are the real safety net.

   line-height is raised because Devanagari, Arabic and CJK all carry taller
   glyph boxes than Latin and the house 1.55 crops descenders on several of
   them. */
.jk__t--nat {
    font-family: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
                 "Noto Sans", "Noto Sans Hebrew", "Noto Sans Arabic", "Noto Sans Devanagari",
                 "Noto Sans CJK SC", "Noto Sans CJK JP", "Noto Sans CJK KR",
                 "Hiragino Sans", "Yu Gothic", "Malgun Gothic", "Microsoft YaHei",
                 "Arial Unicode MS", sans-serif;
    line-height: 1.75;
    font-size: .95rem;
}
/* Right-to-left is a layout fact, not a style: without it the full stop lands
   at the wrong end of the sentence and every reader of those four languages can
   see at a glance that nobody was asked. */
.jk__t--nat[dir="rtl"] { text-align: right; }
.jk__lang {
    color: var(--jk-hue, var(--accent));
    font-variant-numeric: tabular-nums;
}
@media (max-width: 620px) {
    .sheet__head { flex-wrap: wrap; }
    .lang { order: 3; width: 100%; }
}

/* The long ones get their own rule and their own heading: they are a different
   object from a one-liner and burying ten of them inside two hundred would mean
   nobody ever found one. */
.jkdiv {
    margin: 1.6rem 0 .7rem; padding-top: 1.1rem;
    border-top: 1px solid var(--line);
    font-size: .625rem; font-weight: 700; letter-spacing: .2em;
    text-transform: uppercase; color: var(--ink-55);
}
/* Not measured. A dash, drawn quietly, because the absence of a score is the
   correct reading rather than a failure. */
.is-na { color: var(--muted) !important; border-color: var(--line); }
