/* franc.works · the shared layer (polish phase, 2026-10-07)
   What every page has in common: the microtype floor, the arrival grammar,
   the contact sheet, phone chrome, and the canvases of the interaction layer
   (review/INTERACTION-DECISION.md). Page CSS keeps its own composition and
   loads after this file, so a page can always override. */

:root{
  /* the microtype floor: tracked caps never below 11px, 12px on a laptop */
  --micro:clamp(.6875rem,.62rem + .16vw,.8rem);
  --micro-track:.13em;
}

/* ═══ arrivals: settle, wipe, register ═══════════════════════════════
   Triggered once as an element enters, then latched, so everything on
   screen is fully legible at rest (the scrubbed version left the lower
   half of every screen faded: measured, review/OPEN-ITEMS.md M1).
   --v runs 0 → 1 on a CSS transition; it is registered so it can animate
   and inherited so a figure's photograph reads its figure's value.
   Without the .fw class (no script) nothing is hidden. */
@property --v{syntax:'<number>';inherits:true;initial-value:1}
/* arrival sets 1 explicitly: inheriting it from a parent that is itself
   mid-arrival made nested plates chase their parent and stall (measured at
   0.66 at rest before this rule; tools/rest-check.js) */
.fw :is([data-r],figure,.plate,.artefact,.mfig,.beat,.mplate){--v:0}
.fw :is([data-r],figure,.plate,.artefact,.mfig,.beat,.mplate).v{--v:1}
/* settle: text rises into place; the curve front-loads so it reads at once */
.fw :is([data-r],.beat){transition:--v .95s var(--e,cubic-bezier(.16,1,.3,1))}
/* wipe: the house feathered edge crosses the frame at an even pace */
.fw :is(figure,[data-r]:is(figure),.plate,.artefact,.mfig){transition:--v 1.35s cubic-bezier(.5,.05,.18,1)}
.fw .now{transition:none!important}

/* ═══ register: titles carry their three plates ═════════════════════
   Plates rest invisible under the ink (stacked at zero offset they only
   fringe the glyphs); the script shows them while input knocks them out
   of register and hides them as they land. */
.reg i{-webkit-user-select:none;user-select:none;pointer-events:none}
.fw .wrap .reg i,.fw .sheet .reg i{opacity:0}
/* the key (the black ink) waits for its plates: it develops as they land */
.fw .wrap .reg:not(.landed) b,.fw .sheet .reg:not(.landed) b{opacity:0}

/* ═══ the contact sheet ═════════════════════════════════════════════ */
.cform{max-width:26rem;margin:2rem auto 0;text-align:left}
.cform label{display:block;margin-bottom:1.3rem}
.cform label span{display:block;font-variation-settings:'opsz' 12,'wght' 700;
  font-size:var(--micro);letter-spacing:var(--micro-track);text-transform:uppercase;
  color:var(--soft);margin-bottom:.35rem}
.cform input,.cform textarea{width:100%;border:0;border-bottom:1px solid var(--ink);
  background:transparent;color:var(--ink);font-family:inherit;
  font-variation-settings:'opsz' 16,'wght' 500;font-size:1rem;padding:.35rem 0;
  border-radius:0;resize:vertical}
.cform input:focus,.cform textarea:focus{outline:none;border-bottom:2px solid var(--i1);
  padding-bottom:calc(.35rem - 1px)}
.cform .hp{position:absolute;left:-9999px;opacity:0;pointer-events:none}
.csend{display:inline-flex;flex-direction:column;align-items:flex-start;gap:.3rem;
  border:none;background:none;cursor:pointer;color:var(--ink);font-family:inherit;
  font-variation-settings:'opsz' 48,'wght' 800;letter-spacing:-.02em;
  font-size:clamp(1.2rem,2.4vw,1.9rem);line-height:1;
  border-bottom:3px solid var(--i2);padding:0 0 .2em;min-height:44px;
  transition:border-color .4s var(--e)}
.csend:hover{border-color:var(--i1)}
.csend small{font-variation-settings:'opsz' 12,'wght' 600;font-size:var(--micro);
  letter-spacing:var(--micro-track);text-transform:uppercase;color:var(--soft)}
#cmodal{position:fixed;inset:0;z-index:200;display:grid;place-items:center;padding:1.2rem}
#cmodal[hidden]{display:none}
.cback{position:absolute;inset:0;background:color-mix(in srgb,var(--ink) 34%,transparent)}
.csheet{position:relative;background:var(--ground-now,var(--ground));border:1px solid var(--rule);
  padding:clamp(1.6rem,4vw,2.6rem);width:min(26rem,94vw);max-height:90svh;overflow:auto}
.csheet h3{font-variation-settings:'opsz' 48,'wght' 800;letter-spacing:-.025em;
  font-size:clamp(1.4rem,3vw,1.9rem);margin-bottom:1.4rem}
.cx{position:absolute;top:.4rem;right:.55rem;border:0;background:none;cursor:pointer;
  color:var(--soft);font-size:1.5rem;line-height:1;padding:.55rem;min-width:44px;min-height:44px}
.cx:hover{color:var(--ink)}
.csheet .cform{margin:0;max-width:none;text-align:left}
/* phones, portrait tablets and squat glass (the editorial-flow query): the
   sheet rises from the bottom and the invitation stays visible above it */
@media (max-width:700px), (max-width:1024px) and (orientation:portrait), (max-height:620px){
  #cmodal{align-items:end;justify-items:stretch;padding:0}
  .csheet{width:100%;max-width:100%;min-height:50svh;max-height:78svh;
    border:0;border-top:1px solid var(--rule);
    padding:1.5rem var(--gut) calc(1.5rem + env(safe-area-inset-bottom))}
}
/* the sheet arrives like everything else: it settles */
@keyframes fw-sheet{from{opacity:0;translate:0 18px}}
@keyframes fw-back{from{opacity:0}}
#cmodal:not([hidden]) .csheet{animation:fw-sheet .55s var(--e) both}
#cmodal:not([hidden]) .cback{animation:fw-back .4s ease both}

/* ═══ the closing invitation on the case pages ══════════════════════ */
.closecta{text-align:center;padding-block:clamp(4rem,10vw,7rem) clamp(1rem,3vw,2rem)}
/* the close speaks at display size, as it does on the home page */
.closecta .h2{max-width:none;margin-inline:auto;font-variation-settings:'opsz' 96,'wght' 800;
  letter-spacing:-.04em;line-height:.85;font-size:clamp(2.6rem,min(7vw,11vh),7rem)}
.closecta .csend{align-items:center;text-align:center;gap:.5rem;margin:2rem auto 0;
  font-size:clamp(1.5rem,min(2.9vw,4.8vh),2.7rem);padding:.25em .4em .3em;min-height:52px;
  color:var(--i2);border-bottom-color:var(--i2)}
.closecta .csend:hover{color:var(--i1);border-bottom-color:var(--i1)}

/* ═══ look closer: press and hold ═══════════════════════════════════
   The crosshair is the tester's reticle: it marks a case photograph as
   something to look closer at, and rides at the glass's centre while held.
   While the glass is held nothing selects underneath it. */
@media (hover:hover) and (pointer:fine){
  .fw figure:not(.plate):not(.artefact) img{cursor:crosshair}
  .fw-looking,.fw-looking *{cursor:crosshair!important;-webkit-user-select:none;user-select:none}
}

/* ═══ the interaction layer's canvases ══════════════════════════════
   Both are hidden whenever nothing is moving; a resting page paints none. */
.fw-glass{position:fixed;left:0;top:0;pointer-events:none;z-index:4;
  visibility:hidden;contain:strict}
.fw-thread{position:fixed;inset:0;width:100vw;height:100vh;pointer-events:none;
  z-index:4;visibility:hidden}

@media (prefers-reduced-motion:reduce){
  .fw :is([data-r],figure,.plate,.artefact,.mfig,.beat,.mplate){transition:none!important}
  #cmodal .csheet,#cmodal .cback{animation:none!important}
}
@media print{.fw-glass,.fw-thread,#cmodal{display:none!important}}
