/* Dead Letter Department — the entry page.
   Deliberately nothing like the Society's site: manila and franking ink, a back
   office after dark. Colours sampled from the set's own props. */

@font-face {
    font-family: 'Special Elite';
    src: url('img/special-elite.woff2') format('woff2');
    font-weight: 400;
    font-display: swap;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

:root {
    --bone: #e6d9c6;
    --manila: #cfb48b;
    --manila-deep: #bb996a;
    --shadow: #866c49;
    --ink: #27221f;
    --ink-soft: #574a3c;
    --oxblood: #562327;
    --brick: #7d2a20;
    --desk: #241d17;
    --desk-deep: #14100c;

    --type: 'Special Elite', 'Courier New', Courier, monospace;
}

body {
    font-family: var(--type);
    color: var(--ink);
    background: var(--desk-deep);
    -webkit-tap-highlight-color: transparent;
}

/* The desk is the page itself — one scene, with everything else layered onto
   it. It covers the whole document rather than the viewport, so scrolling moves
   down the desk instead of sliding the papers over a fixed photograph. */
.desk {
    min-height: 100vh;
    background: var(--desk-deep) url('img/desk.webp') center top / cover no-repeat;
    padding: 22px 14px 56px;
}

.column {
    max-width: 460px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* ----------------------------------------------------------- envelope ---- */

.letter {
    display: block;
    width: 100%;
    height: auto;
    /* the art carries its own shadow and clear space, so the gap closes up */
    margin: 0 0 -14px;
    filter: drop-shadow(0 12px 22px rgba(0, 0, 0, 0.55));
}

/* the envelope carries the Department's name in ink; this is for screen readers */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ---------------------------------------------------------- clipboard ---- */

/* One board, drawn once at its own proportions. The copy sits up at the top of
   the paper and any spare paper falls below it — the board never grows to chase
   the content, which would tile the crumples and print the same stain twice. */
.clipboard {
    position: relative;
    aspect-ratio: 916 / 1717;
    min-height: fit-content;
    background: url('img/clipboard.webp') top center / 100% 100% no-repeat;
    filter: drop-shadow(0 14px 26px rgba(0, 0, 0, 0.55));
    margin-bottom: 6px;
}

/* the paper's writable area, inside the clip and clear of the deckled edges */
.docket {
    position: absolute;
    /* clip reaches 9.8% down; paper is inset ~7% at the sides and 7% at the
       foot, and its deckle curls inward, so the copy sits a little inside that */
    top: 14.5%;
    left: 11%;
    right: 11%;
    bottom: 7%;
    display: flex;
    flex-direction: column;
}

.clipboard h2 {
    font-size: 1.26rem;
    font-weight: 400;
    letter-spacing: 2px;
    text-transform: uppercase;
    text-align: center;
    margin-bottom: 18px;
}

.clipboard p { font-size: 0.9rem; line-height: 1.7; margin-bottom: 13px; }
.instruction {
    color: var(--ink);
    border-left: 2px solid var(--brick);
    padding-left: 10px;
}

/* -------------------------------------------------------- forwarding ----- */

/* Struck over the docket, in the order a clerk would do it: refused first,
   then redirected. Both land hard and slightly off-square, the way a hand
   stamp actually meets paper. */
.forwarding {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.strike {
    position: absolute;
    opacity: 0;
}

.strike-return {
    width: 62%;
    top: 26%;
    left: 8%;
    transform: rotate(-9deg) scale(1.7);
}

/* the art is drawn 4.3 degrees off-square already, so it needs no tilt here */
.strike-forward {
    width: 88%;
    left: 6%;
    top: 50%;
    transform: scale(1.7);
    /* backed with its own stock, so it sits on the docket rather than in it */
    filter: drop-shadow(0 3px 7px rgba(30, 22, 16, 0.42));
}

/* Paced like a clerk working, not like a page loading: a beat to read the
   refusal before the redirection lands on top of it. */
.forwarding.striking .strike-return {
    animation: thump 0.5s cubic-bezier(0.2, 1.4, 0.4, 1) 0.6s forwards;
}
.forwarding.striking .strike-forward {
    animation: thump 0.5s cubic-bezier(0.2, 1.4, 0.4, 1) 2.1s forwards;
}

@keyframes thump {
    from { opacity: 0; }
    60%  { opacity: 1; }
    to   { opacity: 1; transform: rotate(var(--tilt, 0deg)) scale(1); }
}

.strike-return { --tilt: -9deg; }
.strike-forward { --tilt: 0deg; }

@media (prefers-reduced-motion: reduce) {
    .forwarding.striking .strike { animation: none; opacity: 1; }
    .strike-return { transform: rotate(-9deg) scale(1); }
    .strike-forward { transform: scale(1); }
}

/* ------------------------------------------------------------- tags ------ */

.slot-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    /* three across already reads smaller than the two-across tray, so this only
       needs a touch of inset to keep the hooks distinct from the tags */
    max-width: 79%;
    margin: 16px auto 14px;
}

.tag-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
    margin-top: 4px;
    margin-bottom: 24px;
    padding: 0 2px;
}

.tag {
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    display: block;
    line-height: 0;
    transition: transform 0.12s ease, opacity 0.12s ease;
}

.tag img {
    width: 100%;
    height: auto;
    aspect-ratio: 343 / 488;
    display: block;
    filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.35));
}

.tag:active { transform: translateY(1px); }

/* A hung tag has left the tray. Rather than fade it — which made the desk show
   through the paper — the space keeps its size and shows the mark left behind. */
/* A hung tag keeps its place in the tray. The spirit has gone to the hook, so
   its tag shows the mark where it stood — a second image, not a fade, which
   would have let the desk show through the paper. */
.tag:focus-visible { outline: 2px solid var(--brick); outline-offset: 3px; }

/* a hung tag sits a little lower and straighter than one still in the tray */
.slot-row .tag img { filter: drop-shadow(0 3px 5px rgba(0, 0, 0, 0.4)); }

/* ----------------------------------------------------------- button ------ */

.stamp-btn {
    display: block;
    width: 100%;
    max-width: 88%;
    margin: 0 auto;
    font-family: var(--type);
    font-size: 1rem;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: #f1e2cd;
    background: var(--oxblood);
    border: 1px solid #3a171a;
    border-radius: 2px;
    padding: 15px 12px;
    cursor: pointer;
    box-shadow: inset 0 0 0 1px rgba(241, 226, 205, 0.28), 0 6px 14px rgba(0, 0, 0, 0.4);
}
.stamp-btn:active { transform: translateY(1px); }

/* ---------------------------------------------------------- messages ----- */

/* Everything the clerk says lands on stained paper, so every state is struck
   hard — Special Elite has one weight, so this is a synthesised bold, which on
   a typewriter face reads as a firmer strike rather than a different cut. */
.message {
    /* three lines held open: the clerk's longest reply must not move anything */
    min-height: 4.4em;
    margin-top: 10px;
    margin-bottom: 0;
    font-size: 0.9rem;
    font-weight: 700;
    line-height: 1.5;
    text-align: center;
}
.message.error { color: var(--brick); }
.message.hint { color: var(--oxblood); font-style: italic; }
.message.ok { color: #2f5137; }

@media (max-width: 380px) {
    .docket { left: 10%; right: 10%; }
    .tag-grid { gap: 10px; }
}

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; }
}
